Filter的執行順序與實例
Filter介紹
Filter可認為是Servlet的一種“變種”,它主要用於對用戶請求進行預處理,也可以對HttpServletResponse進行後處理,是個典型的處理鏈。它與Servlet的區別在於:它不能直接向用戶生成響應。完整的流程是:Filter對用戶請求進行預處理,接著將請求交給Servlet進行處理並生成響應,最後Filter再對服務器響應進行後處理。
Filter有如下幾個用處。
- 在HttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest。
- 根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和數據。
- 在HttpServletResponse到達客戶端之前,攔截HttpServletResponse。
- 根據需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和數據。
Filter有如下幾個種類。
- 用戶授權的Filter:Filter負責檢查用戶請求,根據請求過濾用戶非法請求。
- 日誌Filter:詳細記錄某些特殊的用戶請求。
- 負責解碼的Filter:包括對非標準編碼的請求解碼。
- 能改變XML內容的XSLT Filter等。
- Filter可負責攔截多個請求或響應;一個請求或響應也可被多個請求攔截。
創建一個Filter只需兩個步驟:
- 建Filter處理類;
- web.xml文件中配置Filter。
下面先介紹一個簡單的記錄日誌的Filter,這個Filter負責攔截所有的用戶請求,並將請求的信息記錄在日誌中。
public class LogFilter implements Filter { /** * FilterConfig可用於訪問Filter的配置信息 */ private FilterConfig config; @Override public void init(FilterConfig filterConfig) throws ServletException {this.config = config; } /** * 執行過濾的核心方法 * * @param request * @param response * @param chain * @throws IOException * @throws ServletException */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //---------下面代碼用於對用戶請求執行預處理--------- //獲取ServletContext對象,用於記錄日誌 ServletContext context = this.config.getServletContext(); long before = System.currentTimeMillis(); System.out.println("開始過濾..."); //將請求轉換成HttpServletRequest請求 HttpServletRequest hrequest = (HttpServletRequest) request; //記錄日誌 context.log("Filter已經截獲到用戶的請求地址: " + hrequest.getServletPath()); //Filter只是鏈式處理,請求依然放行到目的地址 chain.doFilter(request, response); //---------下面代碼用於對服務器響應執行後處理--------- long after = System.currentTimeMillis(); //記錄日誌 context.log("過濾結束"); //再次記錄日誌 context.log("請求被定位到" + hrequest.getRequestURI() + "所花的時間為: " + (after - before)); } @Override public void destroy() { this.config = null; } }
上面程序實現了doFilter()方法,實現該方法就可實現對用戶請求進行預處理,也可實現對服務器響應進行後處理——它們的分界線為是否調用了chain.doFilter(),執行該方法之前,即對用戶請求進行預處理;執行該方法之後,即對服務器響應進行後處理。
在上面的請求Filter中,僅在日誌中記錄請求的URL,對所有的請求都執行chain.doFilter (request,reponse)方法,當Filter對請求過濾後,依然將請求發送到目的地址。如果需要檢查權限,可以在Filter中根據用戶請求的HttpSession,判斷用戶權限是否足夠。如果權限不夠,直接調用重定向即可,無須調用chain.doFilter(request,reponse)方法。
FirstFilter.java
public class FirstFilter implements Filter { @Override public void destroy() { System.out.println("1st destroy()..."); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("before invoke 1stFilter‘s chain.doFilter() .."); chain.doFilter(request, response); System.out.println("after invoke 1stFilter‘s chain.doFilter() .."); } @Override public void init(FilterConfig arg0) throws ServletException { System.out.println("1stFilter init()..."); } }
SecondFilter.java
public class SecondFilter implements Filter { @Override public void destroy() { System.out.println("2ndFilter destroy()..."); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("before invoke 2ndFilter‘s chain.doFilter() .."); chain.doFilter(request, response); System.out.println("after invoke 2ndFilter‘s chain.doFilter() .."); } @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("2ndFilter init()..."); } }
MyServlet.java
public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet doGet be invoked..."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub this.doGet(req, resp); } }
web.xml
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <filter> <filter-name>firstFilter</filter-name> <filter-class>com.winner.FirstFilter</filter-class> </filter> <filter> <filter-name>secondFilter</filter-name> <filter-class>com.winner.SecondFilter</filter-class> </filter> <filter-mapping> <filter-name>secondFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>firstFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.winner.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/MyServlet</url-pattern> </servlet-mapping> </web-app>
然後發布,發現打印的日誌如下:
1stFilter init()...
2ndFilter init()...
這裏過濾器初始化好了。
當我們訪問我們的 應用:http://localhost:8080/MyServlet
before invoke 2ndFilter‘s chain.doFilter() ..
before invoke 1stFilter‘s chain.doFilter() ..
servlet doGet be invoked...
after invoke 1stFilter‘s chain.doFilter() ..
after invoke 2ndFilter‘s chain.doFilter() ..
當我們將web.xml中filter的位置進行調整後(註意filter-mapping的順序):
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <filter> <filter-name>firstFilter</filter-name> <filter-class>com.winner.FirstFilter</filter-class> </filter> <filter> <filter-name>secondFilter</filter-name> <filter-class>com.winner.SecondFilter</filter-class> </filter> <filter-mapping> <filter-name>firstFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>secondFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.winner.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/MyServlet</url-pattern> </servlet-mapping> </web-app>
當我們訪問我們的 應用:http://localhost:8080/MyServlet
before invoke 1stFilter‘s chain.doFilter() ..
before invoke 2ndFilter‘s chain.doFilter() ..
servlet doGet be invoked...
after invoke 2ndFilter‘s chain.doFilter() ..
after invoke 1stFilter‘s chain.doFilter() ..
Filter的執行順序與實例