對(duì)于所有 Web 應(yīng)用程序來(lái)說(shuō),安全是非常重要的。一個(gè)安全問(wèn)題是當(dāng)變量超出會(huì)話范圍時(shí)您可能需要考慮限制用戶(hù)訪問(wèn) Web 應(yīng)用程序的特殊頁(yè)面。出現(xiàn)這個(gè)問(wèn)題時(shí),您可能想要求用戶(hù)再次登錄,然后才能繼續(xù)。

 

目錄

概述

創(chuàng)建一個(gè)具有兩頁(yè)的項(xiàng)目

 

使用 Servlet Filter

修改按鈕動(dòng)作處理器方法

小結(jié)

 




本技巧適用于以下技術(shù)和資源

NetBeans IDE 6.05.5.1 5.5

 

JavaServer Faces Components/
Java EE Platform

1.2 with Java EE 5*
1.1 with J2EE 1.4

Travel Database

不需要

BluePrints AJAX Component Library

不需要

* 到發(fā)布本文時(shí)止,Sun Java System Application Server 只支持 Java EE 5

現(xiàn)在,本文中的技巧已適用于 Sun Java Application Server PE 9.0 Update Release 1 Tomcat 5.5.17。如果您使用其他服務(wù)器,請(qǐng)查看發(fā)行說(shuō)明 FAQ 了解已知問(wèn)題和解決辦法。有關(guān)所支持服務(wù)器和 Java EE 平臺(tái)的詳細(xì)信息,請(qǐng)參閱發(fā)行說(shuō)明

概述

本技巧介紹當(dāng)會(huì)話超時(shí)或達(dá)到空值時(shí)您如何將該用戶(hù)重定向到另一個(gè)頁(yè)面。在這種情況下,您希望在加載頁(yè)面時(shí)執(zhí)行重定向。但是使用超級(jí)鏈接不起作用,按鈕動(dòng)作處理器方法的標(biāo)準(zhǔn)代碼也不起作用。

處理該情況的最可靠方法是使用 Servlet Filter。而且使用 Servlet Filter 還非常高效,因?yàn)橐坏┰O(shè)置了此過(guò)濾器,您便可以在項(xiàng)目中的任何頁(yè)面或組件中使用。同時(shí)您還可以為按鈕動(dòng)作處理器方法編寫(xiě)自定義代碼,后一種方法不如前面的方法可靠,原因是該方法取決于 web.xml 文件中的設(shè)置。修改后的動(dòng)作處理器代碼還必須包含于您要測(cè)試會(huì)話是否超時(shí)的所有頁(yè)面上。盡管本技巧介紹如何修改按鈕動(dòng)作處理器,但建議您盡可能使用 Servlet Filter 方法。

無(wú)論您選擇哪種方法,要使代碼正常工作,您還需要在 web.xml 文件中設(shè)置一個(gè)會(huì)話超時(shí)值;例如,將會(huì)話超時(shí)值設(shè)置為 1 分鐘:

 <session-config>
       <session-timeout>1</session-timeout>
 </session-config> 

創(chuàng)建一個(gè)具有兩頁(yè)的項(xiàng)目

您可以自己輕松創(chuàng)建此示例。在您的可視 Web 應(yīng)用程序中設(shè)置兩個(gè)頁(yè)面:頁(yè)面1 具有一個(gè)按鈕和一個(gè)顯示會(huì)話超時(shí)消息的 ErrorPage。如果用戶(hù)在達(dá)到 web.xml 文件中設(shè)置的超時(shí)值之前,單擊頁(yè)面 1 上的按鈕,則不會(huì)發(fā)生任何事情(因?yàn)闀?huì)話尚未超時(shí))。但是,如果已經(jīng)達(dá)到了超時(shí)值,即表示該會(huì)話已經(jīng)超時(shí),則該按鈕會(huì)將用戶(hù)帶到 ErrorPage

請(qǐng)記住,當(dāng)會(huì)話超時(shí)時(shí)查看重定向是否正常工作,您必須等待超過(guò)您在 web.xml 文件中設(shè)置的超時(shí)值之后才能單擊該按鈕。

使用 Servlet Filter

當(dāng)會(huì)話超時(shí)時(shí)重定向用戶(hù)的最佳方法是使用 Servlet Filter。使用該方法,您不需要對(duì)按鈕動(dòng)作處理器的代碼進(jìn)行任何修改。

常規(guī)步驟如下:

l          使用 GUI 創(chuàng)建一個(gè) Filter 類(lèi)并將它的過(guò)濾器映射設(shè)置為 Servlet Faces Servlet

l          Servlet Filter 類(lèi)中的代碼替換為自定義代碼。

l          部署項(xiàng)目。

下面是完成此操作的方法。

1.       首先,創(chuàng)建 Filter 類(lèi)。在 NetBeans 6.0 中,右鍵單擊該項(xiàng)目,然后單擊 New -> Other 打開(kāi) File Type 對(duì)話框。(在 NetBeans 5.5 5.5.1 中,右鍵單擊該項(xiàng)目,然后單擊 New->File/Folder 可打開(kāi)該對(duì)話框。)然后在該對(duì)話框屏幕的 Categories 列(如果它尚未高亮顯示)中選擇 Web,在 Files Type 列中選擇 Filter。單擊 Next

2.       將顯示 New Filter 對(duì)話框。在 Class Name 中輸入 SessionCheckFilter,然后單擊 Next。(您可以為此過(guò)濾器使用任何名稱(chēng)。)

3.       Configure Filter Deployment 對(duì)話框中,在 Filter Mappings 框(如果尚未高亮顯示)中選擇 SessionCheckFilter,然后單擊 Edit

1. Configure Filter Deployment 對(duì)話框 (單擊可放大圖像)

4.       Filter Mapping 對(duì)話框中,選中 Servlet 并確保它設(shè)置為 Faces Servlet。然后單擊 Finish

2Filter Mapping 對(duì)話框

5.       現(xiàn)在,在源編輯器中打開(kāi) SessionCheckFilter 類(lèi),然后用以下代碼替換整個(gè)類(lèi)。

代碼示例 1:用于重定向的 SessionCheckFilter 代碼

public class SessionCheckFilter implements Filter {
 private static int firstRequest = 0;
 public void doFilter(ServletRequest request, ServletResponse response,
                    FilterChain chain) throws IOException, ServletException {
      HttpServletRequest hreq = (HttpServletRequest)request;
      HttpServletResponse hres = (HttpServletResponse)response;
      HttpSession session = hreq.getSession();
      if (session.isNew()) {
          if(firstRequest == 0){
               firstRequest++;
          } else {
               hres.sendRedirect("faces/ErrorPage.jsp");
               return;
          }
      }
      chain.doFilter(request, response);
 }
 public void init(FilterConfig filterConfig) throws ServletException {}
 public void destroy() {}
}

Servlet Filter 采用 doFilter 方法進(jìn)行它的所有處理。它獲得對(duì)會(huì)話的參考并測(cè)試會(huì)話是否是新的會(huì)話或者用戶(hù)是否仍然在上一個(gè)會(huì)話中。如果是新的會(huì)話,則代碼會(huì)增加變量 firstRequest,它表示這不再是新的會(huì)話。但是,如果用戶(hù)仍然位于相同的會(huì)話中并且該會(huì)話已經(jīng)超時(shí),則 Servlet Filter 會(huì)將該用戶(hù)重定向到一個(gè)設(shè)置為處理超時(shí)問(wèn)題的頁(yè)面。在本例中,為 faces/ErrorPage.jsp

現(xiàn)在,您可以部署和運(yùn)行該項(xiàng)目了。當(dāng)您等待超過(guò)超時(shí)值(在本例中,為 1 分鐘)之后單擊主頁(yè)面上的按鈕時(shí),過(guò)濾器會(huì)將您重定向到錯(cuò)誤頁(yè)面。無(wú)論您以前單擊該按鈕多少次,都會(huì)發(fā)生該重定向。還請(qǐng)注意,Servlet Filter 適用于任何頁(yè)面和任何組件。您不需要為頁(yè)面上的組件編寫(xiě)任何特殊的代碼。

修改按鈕動(dòng)作處理器方法

您也可以為按鈕動(dòng)作處理器方法編寫(xiě)一些自定義的代碼以在會(huì)話到期時(shí)將用戶(hù)重定向到另一個(gè)頁(yè)面。

除了設(shè)置超時(shí)值之外,要使該方法正常工作,還要確保將 web.xml 文件中的 javax.faces.STATE_SAVING_METHOD 參數(shù)設(shè)置為 client。如果設(shè)置為 server,則按鈕動(dòng)作方法將永遠(yuǎn)也不會(huì)被調(diào)用,無(wú)論超時(shí)值的設(shè)置如何都是如此。要驗(yàn)證和更改此參數(shù)的設(shè)置,請(qǐng)展開(kāi) web.xml 文件的 Context Parameters 部分。如果 javax.faces.STATE_SAVING_METHOD 的值設(shè)置為 server,請(qǐng)使用 Edit 按鈕將屬性值更改為 client

3設(shè)置 javax.faces.STATE_SAVING_METHOD 參數(shù)

所有關(guān)鍵代碼都位于按鈕動(dòng)作處理器方法中。在 Java 源編輯器中打開(kāi) Page1 按鈕動(dòng)作處理器方法,并向該方法中添加以下代碼。輸入該代碼之后,請(qǐng)使用 Fix Imports 函數(shù)導(dǎo)入該代碼使用的類(lèi)。

代碼示例 2:用于會(huì)話超時(shí)重定向的按鈕動(dòng)作處理器

 public String button1_action() {
        ExternalContext externalContext = getFacesContext().getExternalContext();
        HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
        HttpSession session = request.getSession();
        if (session.isNew()) {
          try {
            String errorPageURL = externalContext.getRequestContextPath() +
                "/faces/ErrorPage.jsp";
            externalContext.redirect(errorPageURL);
          } catch(IOException ioe) {
            System.out.println("==============");
            ioe.printStackTrace(System.out);
            System.out.println(ioe.toString());
            System.out.println("==============");
          }
        } else {
          System.out.println("==============");
          System.out.println("*** Session is not New ***");
          System.out.println("==============");
        }
     return null;
}

該動(dòng)作處理器方法的關(guān)鍵部分位于開(kāi)始部分。前三個(gè)方法為:

 ExternalContext externalContext = getFacesContext().getExternalContext();
 HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
 HttpSession session = request.getSession();

為您提供一個(gè)該會(huì)話本身的處理器。

接下來(lái),您檢查該會(huì)話是否是新會(huì)話,或者是否用戶(hù)仍然處于相同(上一個(gè))會(huì)話中。如果是新會(huì)話,則執(zhí)行 try 塊中的代碼;否則,用戶(hù)仍然處于相同會(huì)話中,并且動(dòng)作處理器方法返回。try 塊中的重定向代碼如下:

 if (session.isNew()) {
   try {
     String errorPageURL = externalContext.getRequestContextPath() +
        "/faces/ErrorPage.jsp";
   externalContext.redirect(errorPageURL);

上面的代碼建立了到您要重定向到的頁(yè)面的路徑,在本例中為錯(cuò)誤頁(yè)面 ErrorPage.jsp。路徑為 Web 應(yīng)用程序上下文和重定向到的頁(yè)面名稱(chēng)的組合。代碼使用 ExternalContext.getRequestContextPath 方法返回請(qǐng)求 URI 的一部分,該部分標(biāo)識(shí)請(qǐng)求的 Web 應(yīng)用程序上下文,并且還向此上下文中附加重定向頁(yè)面的名稱(chēng) (/faces/ErrorPage.jsp)

然后,調(diào)用 ExternalContext.redirect 方法,將它的絕對(duì) URL 路徑傳遞給重定向頁(yè)面。redirect 方法將客戶(hù)端請(qǐng)求重定向到指定的 URL。它還在當(dāng)前請(qǐng)求的 FacesContext 實(shí)例上調(diào)用 responseComplete 方法。

小結(jié)

盡管兩種方法都可以正常工作,但很容易看出使用 Servlet Filter 是處理會(huì)話超時(shí)時(shí)重定向問(wèn)題的最簡(jiǎn)單方法。您不僅可以使用 IDE 對(duì)話框創(chuàng)建 Servlet Filter,使所需要添加的代碼非常簡(jiǎn)單。而且使用 Servlet Filter 還不需要在要檢查會(huì)話是否超時(shí)的每個(gè)頁(yè)面上(或者包括在多個(gè)組件動(dòng)作處理器中)重定向邏輯。