在Faces API中有兩個類是要經常使用的. 一個是FacesContext 一個是ExternalContext.首先講解如何使用FacesContext .
對每個JSF請求,FacesServlet對象都會為其擷取一個javax.faces. context.
FacesContext類的執行個體。FacesServlet對象將下列3個取自Web容器的對象傳給javax.faces.context.FacesContextFactory對象的getFacesContext方法,以此來做到這一點:
● javax.servlet.ServletContext● javax.servlet.ServletRequest● javax.servlet.ServletResponse這意味著FacesContext的執行個體裡包含了所有處理JSF請求所需的每個請求的狀態資訊。圖3-1展示了FacesContext執行個體裡封裝的其他一些對象。
3.2.1 擷取當前執行個體一個經常用到的方法是靜態getCurrentInstance方法,它返回當前的FacesContext執行個體。此方法的簽名如下:public static FacesContext getCurrentInstance()下面的代碼是一個用此方法擷取FacesContext當前執行個體的例子:FacesContext facesContext = FacesContext.getCurrentInstance();
3.2.2 擷取和修改組件樹FacesContext執行個體裡最重要的內容是請求頁面的組件樹。組件樹是由javax.faces.tree.Tree類來表示的(本章後面的“使用Tree類”一節會討論)。FacesContext執行個體的tree屬性就是Tree對象。要擷取或修改Tree對象,可使用tree屬性的讀取方法和賦值方法:public abstract Tree getTree()public abstract void setTree(Tree tree)
3.2.3 添加和擷取訊息在 請求處理生命週期裡,可能會遇到錯誤。比如,當驗證器執行輸入驗證時,因為使用者輸入了不正確的值,驗證可能失敗;當組件試圖把輸入值轉換為綁定到組件的模 型對象所需的類型時,也可能會失敗。所有訊息都必須存放到FacesContext執行個體裡以備後面進行處理。比如,您可能希望在頁面裡顯示錯誤訊息,從而 為使用者更正錯誤提供協助。錯誤訊息是由javax.faces.application.Message介面(第11章再詳細討論)來表示的,您可以通過使用FacesContext類的addMessage方法向FacesContext執行個體裡添加Message對象。這個方法的簽名如下:public abstract void addMessage(UIComponent component, Message message)如果component不為空白,新加入的message就關聯到component上。否則,它就不與任何特定組件的執行個體相關。舉例來說,驗證器在驗證組件值失敗時可調用FacesContext的addMessage方法,傳入值無效的組件及一個包含特定錯誤訊息的Message對象。所有添加到FacesContext執行個體的Message對象都被加入到一個集合裡。可通過調用getMessages方法的兩個重載方法之一來擷取加入的Message對象:public abstract Iterator getMessages()public abstract Iterator getMessages(UIComponent component)第一種形式的調用在一個Iterator裡返回所有Message對象,而第二種形式的調用則僅返回與給定UIComponent相關聯的Message對象。
3.2.4 添加和擷取請求處理事件UIComponent 可以產生FacesEvent對象。比如,當單擊一個UICommand組件時,它會產生一個ActionEvent對象(ActionEvent類是 FacesEvent類的子類)。這個FacesEvent對象需要在FacesContext執行個體裡儲存起來,以備請求處理生命週期裡的下一步處理事件 時所用。可通過使用FacesContext類的addFacesEvent方法向FacesContext執行個體添加FacesEvent對象。此方法的簽名如下:public abstract void addFacesEvent(FacesEvent event)要提取先前添加的FacesEvent對象,可調用getFacesEvents方法,其簽名如下:public abstract Iterator getFacesEvents()此方法返回FacesEvent時的順序與其在隊列中的順序一致。
3.2.5 向Response對象裡寫入資訊為 了向Response對象裡寫入資訊,FacesContext類提供了兩個屬性,一個是 javax.faces.Context.ResponseStream類型,另一個是 javax.faces.context.ResponseWriter類型。ResponseStream類型的對象用於輸出位元據,而 ResponseWriter類型的對象則用於輸出字元。這些屬性的讀取方法和賦值方法如下:public abstract ResponseStream getResponseStream()public abstract void setResponseStream(ResponseStream responseStream)public abstract ResponseWriter getResponseWriter()public abstract void setResponseWriter(ResponseWriter responseWriter)
3.2.6 擷取和設定地區第11章將會討論到,JSF支援國際化和本地化。這意味著您可以根據使用者的地區決定發送什麼樣的回應資訊。locale屬性裡存放了當前處理中所用的Locale對象。初始狀況下,locale屬性的值和網路瀏覽器裡指定的地區是一樣的,但可以修改這個值,從而發送輸出所使用的地區將獨立於瀏覽器所使用的地區。此屬性的讀取方法和賦值方法如下:public abstract Locale getLocale()public abstract void setLocale(Locale locale)
3.2.7 操作請求處理生命週期FacesContext類還提供了兩個方法與請求處理生命週期進行互動:● 在當前階段的處理完成後,調用renderResponse方法通知JSF實現把控制權轉到呈現響應階段。也就是說,處於當前階段和呈現響應階段之間的所有其他階段都不再執行。● 調用responseComplete方法,告訴JSF實現此次請求的HTTP響應已經完成(比如在使用了HTTP重新導向的情況下)。因此,當前階段完成後,必須中止請求處理生命週期的處理。這些方法的簽名如下:public abstract void renderResponse()public abstract void responseComplete()
3.2.8 擷取其他請求狀態資訊其他每個請求的狀態資訊封裝在ExternalContext對象裡,可以使用getExternalContext方法擷取該對象:public abstract ExternalContext getExternalContext()現在講解ExternalContext。使 用ExternalContext類提供的方法可以擷取ServletContext、ServletRequest和ServletResponse對 象,構造FacesContext執行個體時需要這些對象。除此之外,ExternalContext執行個體提供了封裝器方法,可以使用這些方法獲得原來需要從 ServletContext、ServletRequest及ServletResponse對象上調用一些方法獲得的資訊。
3.3.1 擷取ServletContext、ServletRequest和ServletResponse對象可使用下列方法擷取servlet資訊:● getContext 此方法可擷取Web應用中與當前請求相關聯的ServletContext對象。其簽名如下:public abstract Object getContext()● getRequest 此方法可擷取代表當前正在處理的請求的ServletRequest對象。其簽名如下:public abstract Object getRequest()● getResponse 此方法可擷取代表當前正在呈現的響應的ServletResponse對象。其簽名如下:public abstract Object getResponse()這些方法都是返回一個java.lang.Object對象,不是servlet特有的類型,這樣就可以使JSF實現獨立於其啟動並執行環境。比如,JSF既可用於Web容器,也可以用於其他容器,如portlet等。
3.3.2 擷取ServletContext特性getApplicationMap方法返回一個包含ServletContext對象裡全部特性名/值對的Map對象。下面是此方法的簽名:public abstract java.util.Map getApplication()作為一個例子,下面的代碼可擷取一個名叫databaseUtility的特性:Object contextAttribute = null;FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map contextMap = externalContext.getApplicationMap();if (contextMap!=null)contextAttribute = contextMap.get("databaseUtility");
3.3.3 擷取Session對象及其特性通 過ExternalContext對象可訪問與當前請求相關聯的Session對象。getSession方法可取回目前使用者的 javax.servlet.http.HttpSession對象,如果目前使用者沒有相應的Session對象,此方法的行為由傳入的參數決定:如果為 該方法傳入了一個true值,它會建立一個Session對象;否則,它會返回null。下面是getSession方法的簽名:public abstract Object getSession(boolean create)此方法其實是javax.servlet.http.HttpServletRequest介面中getSession方法的封裝器。getSessionMap方法返回一個包含與當前請求相關聯的Session對象裡所有特性名/值對的Map對象。下面是它的方法簽名:public abstract java.util.getSessionMap()要 擷取Session對象裡的特性,可調用Map類的get方法,傳入要擷取的特性名即可。文檔中沒有指明在當前請求沒有相應Session對象的情況下, 此方法是返回null還是一個空的Map對象。所以在調用Map的get方法之前,需要先檢查Map是否為null。下面的代碼是擷取Session特性 的例子:Object sessionAttribute = null;FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map sessionMap = externalContext.getSessionMap();if (sessionMap!=null)sessionAttribute = sessionMap.get(key);最後一行的key是一個包含特性名的字串。
3.3.4 擷取ServletContext對象的初始參數getInitParameter方法是ServletContext對象的getInitParameter方法的封裝器,用這個方法可以提取在部署描述符(web.xml檔案)裡用context-init元素指定的初始參數值。此方法的簽名如下:public abstract String getInitParameter(String parameterName)舉例來說,如果在部署描述符聲明了如下context-init元素:<context-param><param-name>contactPerson</param-name><param-value>Scott Jobim</param-value></context-param>下面代碼中的字串變數initParam的值會是Scott Jobim。FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();String initParam = externalContext.getInitParameter("contactPerson");getInitParameterMap方法返回一個包含ServletContext對象中全部初始參數的Map對象。其簽名如下:public abstract java.util.Map getInitParameterMap()為了擷取一個初始參數的值,使用Map對象的get方法,同時傳遞初始參數的名稱。比如,下面的代碼把初始參數databaseName的值輸出到控制台。FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map paramMap = externalContext.getInitParameterMap();if (paramMap!=null) {System.out.println(paramMap.get("databaseName"));}
3.3.5 擷取Request對象的特性getRequestMap方法返回一個包含當前Request對象中全部特性名/值對的Map對象。其方法簽名如下:public abstract java.util.Map getRequestMap()作為一個例子,下面的代碼可用來提取Request對象裡的特性:Object requestAttribute = null;FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map requestMap = externalContext.getRequestMap();if (requestMap!=null)requestAttribute = requestMap.get(key);最後一行裡的Key是一個包含要提取的屬性名稱的字串。
3.3.6 訪問Request對象裡的參數名和值getRequestParameterMap、getRequestParameterNames和getRequestParameterValuesMap方法可用來訪問Request對象裡的參數名和值。getRequestParameterMap返回一個包含Request對象裡全部參數名/值對的Map對象。其簽名如下:public abstract java.util.Map getRequestParameterMap()作為一個例子,下面的代碼可用來提取名為id的請求參數的值:String id = null;FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map requestParameterMap = externalContext.getRequestParameterMap();if (requestParameterMap!=null)id = (String) requestParameterMap.get("id");getRequestParameterNames 方法返回一個包含全部請求參數名的Iterator。此方法其實是ServletRequest.getParameterNames方法的封裝器。不同 的是,ExternalContext類的getRequestParameterNames返回一個Iterator,而不是 java.util.Enumeration。此方法的簽名如下:public abstract java.util.Iterator getRequestParameterNames()作為一個例子,下面的代碼把所有的請求參數名/值對輸出到控制台。FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map requestParameterMap = externalContext.getRequestParameterMap();Iterator parameterNames = externalContext.getRequestParameterNames();while (parameterNames.hasNext()) {String parameterName = (String) parameterNames.next();String parameterValue =(String) requestParameterMap.get(parameterName);System.out.println(parameterName + " : " + parameterValue);}getRequestParameterValuesMap 方法返回一個包含Request對象裡全部參數名/值對的Map對象。此方法與getRequestParameterMap方法很相似,但 getRequestParameterValuesMap可返回全部相同參數名的值。在此方法返回的Map對象上調用get(key)方法,這一點等同 於擷取當前請求的ServletRequest並在其上調用getParameterValues(key)。也就是說,Map對象返回的是一個字串數 組。GetRequestParameterValuesMap方法的簽名如下:public abstract java.util.Map getRequestParameterValuesMap()下面例子中的代碼把請求參數id的全部值輸出到控制台。String[] id = null;FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map requestParameterValuesMap = externalContext.getRequestParameterValuesMap();if (requestParameterValuesMap!=null) {id = (String[]) requestParameterValuesMap.get("id");// print all values of idfor (int i=0; i<id.length; i++) {System.out.println(id[i]);}}
3.3.7 擷取要求標頭的名和值getRequestHeaderMap方法返回一個包含當前請求中全部頭名/值對的Map對象。其方法簽名如下:public abstract java.util.Map getRequestHeaderMap()舉個例子來說,下面的代碼提取host頭的值:String host = null;FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map headerMap = externalContext.getRequestHeaderMap();if (headerMap!=null) {host = (String) headerMap.get("host");System.out.println(host);}注意:前序的名稱是不區分大小寫。比如,對getRequestHeaderMap返回的Map對象分別用host、Host和Host作為參數來調用get方法,其結果是一樣的。getRequestHeaderValuesMap方法與getRequestHeaderMap方法相似。但在getRequestHeader
ValuesMap方法返回的Map對象上調用get方法會得到一個字串的數組。getRequestHeaderValuesMap方法的簽名如下:public abstract java.util.Map getRequestHeaderValuesMap()在getRequestHeaderValuesMap方法返回的Map對象上調用get方法會返回一個java.util.Enumeration值。下面的代碼使用getRequestHeaderValuesMap方法來擷取一個包含全部頭名/值對的Map對象,然後在此Map對象上調用get方法以擷取全部Accept-Encoding頭的值,並將結果輸出到控制台。FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map headerValuesMap = externalContext.getRequestHeaderValuesMap();if (headerValuesMap!=null) {Enumeration headers =(Enumeration) headerValuesMap.get("Accept-Encoding");while (headers.hasMoreElements()) {String value = (String) headers.nextElement();System.out.println(value);}}
3.3.8 擷取CookiegetRequestCookies方法是HttpServletRequest.getCookies方法的封裝器,它返回一個javax.servlet.http.Cookie對象的數組,數組中是當前Request對象裡的全部Cookie。此方法的簽名如下:public abstract Cookie[] getRequestCookies()例如,下面的代碼取得當前請求中的全部Cookie對象,然後在結果數組上迴圈,輸出全部Cookie的名和值。FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Cookie[] cookies = externalContext.getRequestCookies();for (int i=0; i<cookies.length; i++) {Cookie cookie = cookies[i];String cookieName = cookie.getName();String cookieValue = cookie.getValue();System.out.println(cookieName + " : " + cookieValue);}getRequestCookieMap 方法返回一個包含當前請求中全部Cookie的、以Cookie的名稱作為鍵的Map對象。在此Map對象上調用get方法會返回一個 javax.servlet.http.Cookie對象。GetRequestCookieMap方法的簽名如下:public abstract java.util.Map getRequestCookieMap()例如,下面的代碼取得名為password的Cookie對象並將其值輸出到控制台。FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Map cookieMap = externalContext.getRequestCookieMap();if (cookieMap!=null) {Cookie cookie = (Cookie) cookieMap.get("password");if (cookie!=null)System.out.println("Value:" + cookie.getValue());}注意:Cookie名稱區分大小寫。
3.3.9 擷取場所getRequestLocale方法是ServletRequest.getLocale方法的封裝器,它返回Request對象中的Locale對象。此方法的簽名如下:public abstract java.util.Locale getRequestLocale()例如,下面的代碼取回使用者的場所並輸出該場所的顯示語言和顯示國家。FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Locale locale = externalContext.getRequestLocale();System.out.println("Language:" + locale.getDisplayLanguage());System.out.println("Country:" + locale.getDisplayCountry());
3.3.10 擷取上下文路徑getRequestContextPath是HttpServletRequest.getContextPath方法的封裝器,它返回請求URI中指明請求內容相關的上下文路徑部分。其方法簽名如下:public abstract String getRequestContextPath()下面的程式碼片段把請求URI的上下文路徑輸出到控制台:FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();System.out.println("Context path:" +externalContext.getRequestContextPath());對於URL http://localhost:8080/JSFCh03/faces/test.jsp來說,getRequestContextPath方法的傳回值為/JSFCh03。getRequestPathInfo 方法是HttpServletRequest.getPathInfo方法的封裝器,它返回當用戶端進行請求時與用戶端發送的URL相關聯的額外路徑信 息。這部分資訊跟在servlet路徑資訊的後面,但在查詢字串之前。getRequestPathInfo方法的簽名如下:public abstract String getRequestPathInfo()例如,下面代碼輸出請求URL的路徑資訊。FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();System.out.println("Path info:" +externalContext.getRequestPathInfo());對於URL http://localhost:8080/JSFCh03/faces/test.jsp而言,getRequestPathInfo方法的傳回值為test.jsp。
3.3.11 擷取資源路徑getResourcePaths 方法是ServletContext類的getResourcePaths方法的封裝器,它返回一個Set對象,其中包含Web應用中最長子路徑與傳入的 路徑參數相匹配的資源路徑。表示子目錄的路徑以“/”結束。返回的路徑是相對於Web應用根路徑的相對路徑,並以“/”開始。此方法的簽名如下:public abstract java.util.Set getResourcePaths(String path)比如,考慮如下代碼:FacesContext facesContext = FacesContext.getCurrentInstance();ExternalContext externalContext = facesContext.getExternalContext();Set resourcePaths = externalContext.getResourcePaths("/");Iterator iterator = resourcePaths.iterator();while (iterator.hasNext()) {String path = (String) iterator.next();System.out.println(path);}System.out.println("----------------------------");resourcePaths = externalContext.getResourcePaths("/WEB-INF");iterator = resourcePaths.iterator();while (iterator.hasNext()) {String path = (String) iterator.next();System.out.println(path);}這段代碼兩次調用了getResourcePaths方法,第一次傳入“/”,第二次傳入“/WEB-INF”。如果在一個目錄結構3-2所示的Web應用裡運行以上代碼,則返回的第一個Set裡包含如下路徑:/order.jsp/index.jsp/Styles.css/images//details.jsp/WEB-INF//checkOut.jsp/browse.jsp/shoppingCart.jsp/search.jsp/menu.jsp第二個Set裡包含如下路徑:/WEB-INF/faces-config.xml/WEB-INF/web.xml/WEB-INF/classes//WEB-INF/lib/圖3-2 測試getResourcesPath的目錄結構getResourceAsStream方法是ServletContext.getResourceAsStream的封裝器,它返回指定路徑中作為java.io.InputStream對象的資源。其方法簽名如下:public abstract java.io.InputStream getResourceAsStream(String path)
3.3.12 編碼URLencodeURL方法是HttpServletResponse.encodeURL方法的封裝器,它編碼給定的URL,其方法是加入會話的ID資訊;或者,如果不需要這個步驟,則直接將給定的URL原封不動地返回。其方法簽名如下:public abstract String encodeURL(String url)在portlet中使用JSF時,encodeActionURL和encodeResourceURL方法很有用。encodeActionURL迫使URL作為參數傳遞,造成動作在入口/portlet中起作用。這個方法的簽名如下:public abstract String encodeResourceURL(String sb)encodeResourceURL方法迫使URL作為參數傳遞,引用資源以在入口/portlet中起作用。該方法造成URL需要根據包括的特定入口進行重新導向。實際上,它簡單地返回一個絕對URL。下面是encodeResourceURL方法的簽名:public abstract String encodeResourceURL(String sb)
3.3.13 指派請求dispatchMessage方法可根據當前上下文指派請求。對servlet而言,它通過調用forward實現這一點;而對portlet而言,則是通過調用include方法實現這一點。此方法的簽名如下:public abstract void dispatchMessage(String requestURL) throws java.io.IOException, FacesException