Filter執行流程 – JAVA編程語言程序開發技術文章

Filter是從Servlet2.3規范開始新增的功能,並在Servlet2.4規范中得到增強,接下來讓我們一起來看看Filter的真實面目吧。

一. 概念

    過濾器就是在源數據和目的數據之間起過濾作用的中間組件。對Web應用來說,過濾器是一個駐留在服務器端的Web組件,它可以截取客戶端和資源之間的請求與響應信息,並對這些信息進行過濾。

 

二. 執行流程

    當Web容器接受到一個對資源的請求時,它就會判斷是否有過濾器與這個資源相關聯(這是一個自動的過程)。如果有,那麼容器將把請求交給過濾器進行處理。在過濾器中,你可以改變請求的內容,或者重新設置請求的報頭信息,然後再將請求發送給目標資源。當目標資源對請求作出響應時候,容器同樣會將響應先轉發給過濾器,再過濾器中,你可以對響應的內容進行轉換,然後再將響應發送到客戶端.。

    如果有多個過濾器,則它會像一個鏈(根據web.xml中的位置)一樣執行。

    我們先看一個圖:

 

 

三. 實例及解析

    我們來看一個登錄的例子,它需要用到兩個過濾器,一個是轉換編碼格式,一個是判斷是否登錄。

    先看一下這個例子的時序圖:

 

 

接下來我們看一下源碼:

   login.jsp

[java] <pre class="java" name="code"><%@ page language="java" contentType="text/html; charset=GB18030" 
    pageEncoding="GB18030"%> 
<% 
    String command = request.getParameter("command"); 
    if ("login".equals(command)) { 
        if ("dan".equals(request.getParameter("userId")) 
                && "123".equals(request.getParameter("password"))) { 
 
            //登陸成功將用戶信息放到session中  
            session.setAttribute("user_name", 
                    request.getParameter("userId")); 
 
            //設置超時,單位:秒  
            session.setMaxInactiveInterval(6000); 
 
            //重定向到主控頁面  
            response.sendRedirect(request.getContextPath() + "/main.jsp"); 
        } 
    } 
%> 
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=GB18030"> 
<title>登錄</title> 
<SCRIPT language=JavaScript> 
    function init() { 
        loginForm.userId.focus(); 
    } 
 
</SCRIPT> 
</head> 
<body onload=init()> 
    <FORM name="loginForm"> 
        <input type="hidden" name="command" value="login">     
        用戶名:   
        <INPUT name="userId" value="dan" type="text" size="20"   maxlength="20">  
        密   碼:  
        <INPUT name="password"   value="123" type="password" size="21" maxlength="20">  
        <input type="submit" onclick="submitForm()" value="提交" name="login" id="login"> 
    </FORM> 
</body> 
</html> 
<pre class="java" name="code"><%@ page language="java" contentType="text/html; charset=GB18030"
 pageEncoding="GB18030"%>
<%
 String command = request.getParameter("command");
 if ("login".equals(command)) {
  if ("dan".equals(request.getParameter("userId"))
    && "123".equals(request.getParameter("password"))) {

   //登陸成功將用戶信息放到session中
   session.setAttribute("user_name",
     request.getParameter("userId"));

   //設置超時,單位:秒
   session.setMaxInactiveInterval(6000);

   //重定向到主控頁面
   response.sendRedirect(request.getContextPath() + "/main.jsp");
  }
 }
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GB18030">
<title>登錄</title>
<SCRIPT language=JavaScript>
 function init() {
  loginForm.userId.focus();
 }

</SCRIPT>
</head>
<body onload=init()>
 <FORM name="loginForm">
  <input type="hidden" name="command" value="login"> 
  用戶名: 
  <INPUT name="userId" value="dan" type="text" size="20" maxlength="20">
  密   碼:
  <INPUT name="password" value="123" type="password" size="21" maxlength="20">
  <input type="submit" onclick="submitForm()" value="提交" name="login" id="login">
 </FORM>
</body>
</html>

   CharsetEncodingFilter.java

[java] package filter; 
 
import java.io.IOException; 
 
import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
 
public class CharsetEncodingFilter implements Filter { 
 
    private String encoding; 
     
    @Override 
    public void destroy() { 
         
    } 
 
    @Override 
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, 
            FilterChain filterChain) throws IOException, ServletException { 
        //設置字符集  
        servletRequest.setCharacterEncoding(encoding); 
        filterChain.doFilter(servletRequest, servletResponse); 
         
    } 
 
    @Override 
    public void init(FilterConfig filterConfig) throws ServletException { 
        //取得初始化參數  
        this.encoding = filterConfig.getInitParameter("encoding"); 
    } 
 

package filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class CharsetEncodingFilter implements Filter {

 private String encoding;
 
 @Override
 public void destroy() {
  
 }

 @Override
 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
   FilterChain filterChain) throws IOException, ServletException {
  //設置字符集
  servletRequest.setCharacterEncoding(encoding);
  filterChain.doFilter(servletRequest, servletResponse);
  
 }

 @Override
 public void init(FilterConfig filterConfig) throws ServletException {
  //取得初始化參數
  this.encoding = filterConfig.getInitParameter("encoding");
 }

}
 
   AuthFilter.java

[java] package filter; 
 
import java.io.IOException; 
 
import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.servlet.http.HttpSession; 
 
public class AuthFilter implements Filter { 
 
    public void destroy() { } 
 
    public void doFilter(ServletRequest request, ServletResponse response, 
            FilterChain chain) throws IOException, ServletException { 
        HttpServletRequest req = (HttpServletRequest) request; 
        HttpServletResponse res = (HttpServletResponse) response; 
        String requestURI = req.getRequestURI().substring( 
                req.getRequestURI().indexOf("/", 1), 
                req.getRequestURI().length()); 
        if (!"/login.jsp".equals(requestURI)) { 
            HttpSession session = req.getSession(false); 
            if (session == null || session.getAttribute("user_name") == null) { 
                res.sendRedirect(req.getContextPath() + "/login.jsp"); 
                return; 
            } 
        } 
        // 繼續訪問其他資源  
        chain.doFilter(req, res); 
    } 
 
    public void init(FilterConfig filterConfig) throws ServletException {} 
 

package filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class AuthFilter implements Filter {

 public void destroy() { }

 public void doFilter(ServletRequest request, ServletResponse response,
   FilterChain chain) throws IOException, ServletException {
  HttpServletRequest req = (HttpServletRequest) request;
  HttpServletResponse res = (HttpServletResponse) response;
  String requestURI = req.getRequestURI().substring(
    req.getRequestURI().indexOf("/", 1),
    req.getRequestURI().length());
  if (!"/login.jsp".equals(requestURI)) {
   HttpSession session = req.getSession(false);
   if (session == null || session.getAttribute("user_name") == null) {
    res.sendRedirect(req.getContextPath() + "/login.jsp");
    return;
   }
  }
  // 繼續訪問其他資源
  chain.doFilter(req, res);
 }

 public void init(FilterConfig filterConfig) throws ServletException {}

}
 

Web.xml

  

[html] <?xml version="1.0" encoding="UTF-8"?> 
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> 
     
  <filter> 
    <filter-name>CharsetEncodingFilter</filter-name> 
    <filter-class>filter.CharsetEncodingFilter</filter-class> 
    <init-param> 
      <param-name>encoding</param-name> 
      <param-value>GB18030</param-value> 
    </init-param> 
  </filter> 
  <filter-mapping> 
    <filter-name>CharsetEncodingFilter</filter-name> 
    <url-pattern>*.jsp</url-pattern> 
  </filter-mapping> 
  <filter-mapping> 
    <filter-name>CharsetEncodingFilter</filter-name> 
    <url-pattern>/servlet/*</url-pattern> 
  </filter-mapping> 
   
  <filter> 
    <filter-name>AuthFilter</filter-name> 
    <filter-class>filter.AuthFilter</filter-class> 
  </filter> 
  <filter-mapping> 
    <filter-name>AuthFilter</filter-name> 
    <url-pattern>*.jsp</url-pattern> 
  </filter-mapping> 
   
  <filter-mapping> 
    <filter-name>AuthFilter</filter-name> 
    <url-pattern>/servlet/*</url-pattern> 
  </filter-mapping> 
     
</web-app> 
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
   
  <filter>
    <filter-name>CharsetEncodingFilter</filter-name>
    <filter-class>filter.CharsetEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>GB18030</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CharsetEncodingFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
  <filter-mapping>
   <filter-name>CharsetEncodingFilter</filter-name>
   <url-pattern>/servlet/*</url-pattern>
  </filter-mapping>
 
  <filter>
   <filter-name>AuthFilter</filter-name>
   <filter-class>filter.AuthFilter</filter-class>
  </filter>
  <filter-mapping>
   <filter-name>AuthFilter</filter-name>
   <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
 
  <filter-mapping>
   <filter-name>AuthFilter</filter-name>
   <url-pattern>/servlet/*</url-pattern>
  </filter-mapping>
   
</web-app>

Filter中主要有三個方法init(),doFilter(),destroy()

  1.init(FilterConfigfilterConfig)    

    Web容器調用該方法該方法來初始化過濾器。容器在調用該方法時,向過濾器傳遞

FilterConfig對象,利用FilterConfig對象可以得到ServletContext對象,以及部署描述符中配置的過濾器的初始化參數。

 

從圖中可以看出來Listener,Filter,Servlet及Tomcat的一個啟動順序。

    2.doFilter(ServletRequestrequest, ServletResponse response,FilterChain chain)

    這是Filter的主要方法,其中的request和response和servlet裡的參數一樣,至於chain是用於後面對請求的轉發的,該參數的chain.doFilter方法是一種回調過程。

    該方法以chain.doFilter()為界限,先執行前面的代碼,然後執行chain.doFilter()方法來將請求傳遞給下一個Filter(如果沒有Filter瞭就傳遞給Servlet),等到這條鏈執行完後,再往回執行後面的代碼,它是使用回調來實現的。   

     大傢可以通過下面的圖來進行理解:

 

 

3.destroy()

     這個方法servlet的destroy()方法一樣,都是當服務器斷開的時候才執行該銷毀方法,Filter也是實例化一次,多次調用。

 

摘自 趙丹丹的專欄

發佈留言