Filter执行流程

来源:互联网 发布:chrome 定时执行js 编辑:程序博客网 时间:2024/05/29 19:20

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/j2eehttp://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/j2eehttp://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也是实例化一次,多次调用。


=============================================================

java filter里<filter-mapping>中的<dispatcher>作用

2.4版本的servlet规范在部属描述符中新增加了一个<dispatcher>元素,这个元素有四个可能的值:即 REQUEST、FORWARD、INCLUDE和ERROR。可以在一个<filter-mapping>元素中加入任意数目的<dispatcher>,使得filter将会作用于直接从客户端过来的request、通过forward过来的request、通过 include过来的request和通过<error-page>过来的request。如果没有指定任何< dispatcher >元素,默认值是REQUEST。可以通过下面几个例子来辅助理解。

 

例1:

<filter-mapping>
    <filter-name>Logging Filter</filter-name>
    <url-pattern>/products/*</url-pattern>
</filter-mapping>

这种情况下,过滤器将会作用于直接从客户端发过来的以/products/…开始的请求。因为这里没有制定任何的< dispatcher >元素,默认值是REQUEST。

 

例2:

<filter-mapping>
    <filter-name>Logging Filter</filter-name>
    <servlet-name>ProductServlet</servlet-name>
    <dispatcher>INCLUDE</dispatcher>
</filter-mapping>

这种情况下,如果请求是通过request dispatcher的include方法传递过来的对ProductServlet的请求,则要经过这个过滤器的过滤。其它的诸如从客户端直接过来的对ProductServlet的请求等都不需要经过这个过滤器。
指定filter的匹配方式有两种方法:直接指定url-pattern和指定servlet,后者相当于把指定的servlet对应的url-pattern作为filter的匹配模式。
filter的路径匹配和servlet是一样的,都遵循servlet规范中《SRV.11.2 Specification of Mappings》一节的说明

 

例3:

<filter-mapping>
    <filter-name>Logging Filter</filter-name>
    <url-pattern>/products/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

在这种情况下,如果请求是以/products/…开头的,并且是通过request dispatcher的forward方法传递过来或者直接从客户端传递过来的,则必须经过这个过滤器。

0 0
原创粉丝点击