在之前的範例當中,曾經在 Scriptlet 中寫下 out
與 request
等字眼,然後直接操作一些方法。像 out
、request
這樣的字眼,在轉譯為 Servlet 之後,會直接對應於 Servlet 中的某個物件,例如 request
就對應 HttpServletRequest
物件。像 out
、request
這樣的字眼,通常稱之為隱含物件(Implicit Object)或隱含變數(Implicit Variable)。
以下先列表對照 JSP 中的隱含物件與轉譯後的型態,有一些部份也許是你第一次看到的型態,將在稍後詳加說明:
out
轉譯後對應
JspWriter
物件,其內部關聯一個PrintWriter
物件。request
轉譯後對應
HttpServletRequest
物件。response
轉譯後對應
HttpServletResponse
物件。config
轉譯後對應
ServletConfig
物件。application
轉譯後對應
ServletContext
物件。session
轉譯後對應
HttpSession
物件。pageContext
轉譯後對應
PageContext
物件,它提供了 JSP 頁面資源的封裝,並可設定頁面範圍屬性。exception
轉譯後對應
Throwable
物件,代表由其他JSP 頁面丟出的例外物件,只會出現於 JSP 錯誤頁面(isErrorPage
設定為true
的 JSP 頁面)。page
轉譯後對應
this
。
大部份的隱含物件,在轉譯後所對應的 Servlet 相關物件,先前講解 Servlet 的文件都有作過說明。page
隱含物件則是對應於轉譯後 Java 類別中的 this
物件,主要是讓不熟悉 Java 的網頁設計師,在必要時可以用較直覺的 page
名稱來存取。
exception
隱含物件將在之後談到 JSP 錯誤處理時時再加以說明。
至於 out
、pageContext
、exception
這些隱含物件,轉譯後的型態你可能是第一次看到,以下先針對這些隱含物件進行說明。
out
隱含物件不直接對應於先前說明 Servlet 時,由 HttpServletResponse
所取得的 PrintWriter
物件。out
隱含物件在轉譯之後,會對應於 javax.servlet.jsp.JspWriter
類別的實例,JspWriter
則直接繼承 java.io.Writer
類別。JspWriter
主要模擬了 BufferedWriter
與 PrintWriter
的功能。
JspWriter
在內部也是使用 PrintWriter
來進行輸出,但 JspWriter
具有緩衝區功能。當使用 JspWriter
的 print()
或 println()
進行回應輸出時,如果 JSP 頁面沒有緩衝,則直接建立 PrintWriter
來輸出回應,如果 JSP 頁面有作緩衝,則只有在出清(flush)緩衝區時,才會真正建立 PrintWriter
物件進行輸出。
會對頁面進行緩衝處理,表示在緩衝區滿的時候,可能有兩種處理方式:
- 累積緩衝區的容量後再一次輸出回應,所以緩衝區滿了就直接出清。
- 你也許是想控制輸出的量在緩衝區容量之內,所以緩衝區滿了表示有錯誤,此時要丟出例外。
在撰寫 JSP 頁面時,可以透過 page
指示元素的 buffer
屬性來設定緩衝區的大小,預設是 8kb
。緩衝區滿了之後該採取哪種行為,則是由 autoFlush
屬性決定,預設是 true
,表示滿了就直接出清。如果設定為 false
,則要自行呼叫 JspWriter
的 flush()
方法來出清緩衝區,如果緩衝區滿了卻還沒呼叫 flush()
資料 送出至客戶端,呼叫 println()
時將會丟出 IOException
例外。
接著說明 pageContext
隱含物件。pageContext
隱含物件轉譯後對應於 javax.servlet.jsp.PageContext
型態之物件,這個物件將所有 JSP 頁面的資訊封裝起來,轉譯後的 Servlet 可透過 PageContext
來取得所有的 JSP 頁面資訊。
例如在轉譯後的 Servlet 程式碼當中,要取得對應 JSP 頁面的 ServletContext
、ServletConfig
、 HttpSession
與 JspWriter
物件時,是透過以下的程式碼來取得:
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
所有的隱含物件都可以藉由 pageContext
來取得。除了封裝所有的 JSP 頁面資訊之外,還可以使用 pageContext
來設定頁面範圍屬性。在先前的文件中,你知道 Servlet 中可以設定屬性的物件有 HttpServletRequest
、HttpSession
與 ServletContext
,可分別用來設定請求範圍、會話範圍與應用程式範圍屬性。
在學到 JSP 時,你則會多認識一個用 pageContext
來設定的頁面範圍屬性,同樣是使用 setAttrubute()
、getAttribute()
與 removeAttribute()
來進行設定。預設是可設定或取得頁面範圍屬性,頁面範圍屬性表示作用範圍僅限同一頁面之中。
來舉自行設定頁面範圍屬性的一個例子。你想要先檢查頁面範圍屬性中,是否曾被設定過某個屬性,如果有就直接取用,如果沒有就直接生成,且設定為頁面屬性。例如:
<%
Some some = pageContext.getAttribute("some");
if(some == null) {
some = new Some();
pageContext.setAttribute("some", some);
}
%>
事實上,你可以透過 pageContext
設定四種範圍屬性,而不用使用個別的 pageContext
、request
、 session
、application
來進行設定。以 pageContext
提供單一的 API 來管理屬性作用範圍,你可以使用以下的方法來進行設定:
getAttribute(String name, int scope)
setAttribute(String name, Object value, int scope)
removeAttribute(String name, int scope)
其中的 scope
可以使用以下的常數來進行指定:pageContext.PAGE_SCOPE
、pageContext.REQUEST_SCOPE
、pageContext.SESSION_SCOPE
、pageContext.APPLICATION_SCOPE
,分別表示頁面、請求、會話與應用程式範圍。例如要設定會話範圍的屬性:
pageContext.setAttribute("login", "caterpillar", pageContext.SESSION_SCOPE);
要取得會話範圍的屬性時,可以使用以下的方式:
String attr =
(String) pageContext.getAttribute("login", pageContext.SESSION_SCOPE);
當不知道屬性的範圍時,也可以使用 pageContext
的 findAttribute()
方法來找出屬性,只要指定屬性名稱即可。findAttribute()
會依序從頁面、請求、會話、應用程式範圍尋找看看有無對應的屬性,先找到就傳回。例如:
Object attr = pageContext.findAttribute("attr");
隱含物件的認識,應視為認識 JSP 的一個過程,在 JSP 頁面中使用了隱藏物件,就代表著 JSP 頁面中多少都夾雜著 Scriptlet,在現在來說並不鼓勵,可以的話,在 JSP 頁面中不要使用隱藏物件。