• servlet之过滤器(转载)


     

    林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

     

    一、Filter

       1、过滤器的概念

    Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。

    优点:过滤链的好处是,执行过程中任何时候都可以打断,只要不执行chain.doFilter()就不会再执行后面的过滤器和请求的内容。而在实际使用时,就要特别注意过滤链的执行顺序问题

         2、过滤器的作用描述

     

    • 在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest 。 
    • 根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。
    •  在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。 
    • 根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。

    3、特点

    Servlet 过滤器是在Java Servlet规范2.3中定义的,它能够对Servlet容器的请求和响应对象进行检查和修改,它在Servlet被调用之前检查Request对象, 修改Request Header和Request内容;在Servlet被调用之后检查Response对象,修改Response Header和Response内容。Servlet过滤器负责过滤的Web组件可以是Servlet、JSP或HTML文件,具有以下特点:

    • Servlet过滤器可能检查和修改ServletRequest和ServletResponse对象
    • 可以指定Servlet过滤器和特定的URL关联,只有当客户请求访问此URL时,才会触发该过滤器工作
    • 多个Servlet过滤器可以被串联起来,形成管道效应,协同修改请求和响应对象
    •  所有支持Java Servlet规范2.3的Servlet容器,都支持Servlet过滤器

     4、接口

    所有的Servlet过滤器类都必须实现javax.servlet.Filter接口。该接口定义了以下3个方法:

    •   init(FilterConfig)     这是Servlet过滤器的初始化方法,Servlet容器创建Servlet过滤器实例后就会调用这个方法。在这个方法中可以通过 FilterConfig来读取web.xml文件中Servlet过滤器的初始化参数。
    • doFilter(ServletRequest, ServletResponse, FilterChain)  这是完成实际的过滤操作的方法,当客户请求访问与过滤器关联的URL时,Servlet容器先调用该方法。FilterChain参数用来访问后续的过滤 器的doFilter()方法。
    •  destroy() Servlet容器在销毁过滤器实例前调用该方法,在这个方法中,可以释放过滤器占用的资源。

    5、Filter过程

    它 使用户可以改变一个request和修改一个response. Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在离开 servlet时处理response.换种说法,filter其实是一个”servletchaining”(servlet 链).一个filter 包括:

    • 在servlet被调用之前截获;
    • 在servlet被调用之前检查servletrequest;
    •  根据需要修改request头和request数据;
    • 根据需要修改response头和response数据;
    • 在servlet被调用之后截获.

    你 能够配置一个filter 到一个或多个servlet;单个servlet或servlet组能够被多个filter 使用.几个实用的filter 包括:用户辨认filter,日志filter,审核filter,加密filter,符号filter,能改变xml内容的XSLTfilter等.

    6、Filter建立步骤

           建立一个过滤器涉及下列五个步骤:
            1)建立一个实现Filter接口的类。这个类需要三个方法,分别是:doFilter、init和destroy。doFilter方法包含主要的过滤代码(见第2步),init方法建立设置操作,而destroy方法进行清楚。
            2)在doFilter方法中放入过滤行为。doFilter方法的第一个参数为ServletRequest对象。此对象给过滤器提供了对进入的信息 (包括表单数据、cookie和HTTP请求头)的完全访问。第二个参数为ServletResponse,通常在简单的过滤器中忽略此参数。最后一个参 数为FilterChain,如下一步所述,此参数用来调用servlet或JSP页。
           3)调用FilterChain对象的doFilter方法。Filter接口的doFilter方法取一个FilterChain对象作为它的一个参 数。在调用此对象的doFilter方法时,激活下一个相关的过滤器。如果没有另一个过滤器与servlet或JSP页面关联,则servlet或JSP 页面被激活。
           4)对相应的servlet和JSP页面注册过滤器。在部署描述符文件(web.xml)中使用filter和filter-mapping元素。
           5)禁用激活器servlet。防止用户利用缺省servlet URL绕过过滤器设置。

    过滤器需要在web.xml文件中进行配置

    1. <!-- 配置Filter -->  
    2.     <filter>    
    3.         <filter-name>LogFilter</filter-name>    
    4.         <filter-class>com.mucfc.LogFilter</filter-class>    
    5.     </filter>    
    6.     <filter-mapping>    
    7.         <filter-name>LogFilter</filter-name>    
    8.         <url-pattern>/*</url-pattern><!-- 表示处理根目录下的所有请求 -->  
    9.     </filter-mapping>    

    或者直接用注解:

    1. @WebFilter(filterName="log",urlPatterns={"/*"})  
    2. public class LogFilter implements Filter {  
    3. .................................  
    4. }  

        7、映射的配置
    (1) 映射到一个或多个jsp

    1. <filter-mapping>  
    2. <filter-name>FilterName</filter-name>  
    3. <url-pattern>/path/FileName.jsp</url-pattern>  
    4. </filter-mapping>  

    (2) 映射到一个或多个servlet

    1. <filter-mapping>  
    2. <filter-name>FilterName</filter-name>  
    3. <servlet-name>ServletName1</servlet-name>  
    4. </filter-mapping>  
    5. <filter-mapping>  
    6. <filter-name>FilterName</filter-name>  
    7. <servlet-name>ServletName2</servlet-name>  
    8. </filter-mapping>  

    (3) 映射到任意的url

    1. <filter-mapping>  
    2. <filter-name>FilterName</filter-name>  
    3. <url-pattern>/*</url-pattern>  
    4. </filter-mapping>  



    二、Filter简单示例

    本例子工程免费下载

    下面我们要通过Filter来输出一个Hello World,先建立一个web工程。

    然后添加一个Filter如下:

    1. package com.mucfc;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. import javax.servlet.Filter;  
    6. import javax.servlet.FilterChain;  
    7. import javax.servlet.FilterConfig;  
    8. import javax.servlet.ServletContext;  
    9. import javax.servlet.ServletException;  
    10. import javax.servlet.ServletRequest;  
    11. import javax.servlet.ServletResponse;  
    12. import javax.servlet.annotation.WebFilter;  
    13. import javax.servlet.http.HttpServletRequest;  
    14. import javax.servlet.http.HttpServletResponse;  
    15. import javax.servlet.http.HttpSession;  
    16. @WebFilter(filterName="log",urlPatterns={"/*"})  
    17. public class LogFilter implements Filter {  
    18.   
    19.     private FilterConfig filterConfig;  
    20.     @Override  
    21.     public void destroy() {  
    22.         filterConfig=null;  
    23.           
    24.     }  
    25.   
    26.     @Override  
    27.     public void doFilter(ServletRequest arg0, ServletResponse arg1,  
    28.             FilterChain arg2) throws IOException, ServletException {  
    29.         //获取ServletContext对象,用于记录日志  
    30.         ServletContext servletContext=filterConfig.getServletContext();  
    31.         long before=System.currentTimeMillis();  
    32.         System.out.println("开始过滤");  
    33.           
    34.         HttpServletRequest httpServletRequest=(HttpServletRequest)arg0;  
    35.           
    36.           
    37.         //输出信息  
    38.         System.out.println("Filter已经截获到用户的请求地址"+httpServletRequest.getServletPath());  
    39.         //Filter 只是链式处理,请求依然放行到目的地址  
    40.         arg2.doFilter(arg0, arg1);    
    41.         //输出到服务器响应执行后处理  
    42.         long after=System.currentTimeMillis();  
    43.         System.out.println("过滤 结束");  
    44.         System.out.println("请求被定位到"+httpServletRequest.getRequestURI()+"  所花时间为"+(after-before));  
    45.           
    46.           
    47.     }  
    48.   
    49.     @Override  
    50.     public void init(FilterConfig arg0) throws ServletException {  
    51.         filterConfig=arg0;  
    52.           
    53.     }  
    54.   
    55. }  

    这里是直接使用注解的方式来配置Filter,也可以在web.xml中配置

    然后就是另一个Servlet

    1. package com.mucfc;  
    2.   
    3. import java.io.IOException;  
    4. import java.io.PrintWriter;  
    5.   
    6. import javax.servlet.ServletException;  
    7. import javax.servlet.annotation.WebServlet;  
    8. import javax.servlet.http.HttpServlet;  
    9. import javax.servlet.http.HttpServletRequest;  
    10. import javax.servlet.http.HttpServletResponse;  
    11.   
    12.   
    13. @WebServlet(name="HelloServlet" ,urlPatterns="/HelloServlet")  
    14. //采用WebServlet注解,不用再到web.xml中配置  
    15. public class HelloServlet extends HttpServlet {  
    16.     private static final long serialVersionUID = 1L;  
    17.          
    18.   
    19.     public HelloServlet() {  
    20.         super();  
    21.     }  
    22.   
    23.   
    24.     protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
    25.         request.setCharacterEncoding("gb2312");  
    26.         response.setCharacterEncoding("gb2312");  
    27.         PrintWriter out=response.getWriter();  
    28.         out.println("你好!hello World  ");  
    29.         out.close();  
    30.     }  
    31.   
    32.   
    33.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
    34.     }  
    35.   
    36.   
    37.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
    38.     }  
    39.   
    40. }  

    这里也是基于注解实现Servlet。这样子可以省去在web.xml中大量的代码,速度更加的快!

    1. @WebServlet(name="HelloServlet" ,urlPatterns="/HelloServlet")  

    相当于以下

    1. <!-- 配置servlet -->  
    2.     <servlet>  
    3.         <servlet-name>HelloServlet</servlet-name>  
    4.         <servlet-class>com.mucfc.HelloServlet</servlet-class>  
    5.     </servlet>  
    6.   
    7.     <servlet-mapping>  
    8.         <servlet-name>HelloServlet</servlet-name>  
    9.         <url-pattern>/HelloServlet</url-pattern>  
    10.     </servlet-mapping>  


    然后就是运行了:浏览器输入:http://localhost:8080/ServletLearningChapter2_1/HelloServlet

    控制台输出:

     

    页面输出:


    三、四种过滤器比较

    1、request过滤器

    这种过滤器的工作方式比较简单,大家也经常遇到,如下所示:以下是web.xml文件配置方式:

    1. <filter>  
    2.     <filter-name>myFilter</filter-name>  
    3.     <filter-class>packagename.MyFilterName</filter-class>  
    4. </filter>  
    5. <filter-mapping>  
    6.     <filter-name>myFilter</filter>  
    7.     <servlet-name> 目标资源</servlet-name>  
    8. </filter-mapping>  


    下面我们更改一下web.xml文件的配置,如下方式:

    1. <filter>  
    2.     <filter-name>myFilter</filter-name>  
    3.     <filter-class>packagename.MyFilterName</filter-class>  
    4. </filter>  
    5. <filter-mapping>  
    6.     <filter-name>myFilter</filter>  
    7.     <servlet-name> 目标资源1</servlet-name>  
    8. </filter-mapping>  
    9. <filter-mapping>  
    10.     <filter-name>myFilter</filter>  
    11.     <servlet-name> 目标资源2</servlet-name>  
    12. </filter-mapping>  


    也 就是说此过滤器对目标资源一和目标资源二都进行过滤,然后当目标资源一被访问的时候我们将请求转发给目标资源二,那么这个时候过滤器是怎么工作的呢?如下 图所示:我们可以看到,当我们访问目标资源一时过滤器截取了请求,然后再转发给目标资源一,然后再转发给目标资源二,从图中我们可以看到过滤器没有截取转 发到目标资源二的请求,但是我们已经在web.xml文件中配置了该过滤器对目标资源二的过滤,为什么又没有起到过滤作用呢?

    答案就在于,目标资源一是客户端直接访问,而目标资源二是被转发过来的,这时过滤器就不能过滤目标资源二。如果你直接访问目标资源二,你会发现该过滤器起到了作用? 

    我们上面的web.xml文件配置与以下方式等价:

    1. <filter>  
    2.      <filter-name>myFilter</filter-name>  
    3.     <filter-class>packagename.MyFilterName</filter-class>  
    4. </filter>  
    5.  <filter-mapping>  
    6.     <filter-name>myFilter</filter>  
    7.     <servlet-name> 目标资源1</servlet-name>  
    8.     <dispatcher>REQUEST</dispatcher>  
    9. </filter-mapping>  
    10. <filter-mapping>  
    11.     <filter-name>myFilter</filter>  
    12.     <servlet-name> 目标资源2</servlet-name>  
    13.     <dispatcher>REQUEST</dispatcher>  
    14. </filter-mapping>  

    这种方式的配置,说明只有直接访问该目标资源时该过滤器才会起作用,对转发到该目标资源的请求将忽略不处理。

    那如果我想对转发到目标资源二的请求进行过滤,那怎么办呢?答案见,下一种过滤器,forward过滤器。

    2、forward过滤器

    我们将web.xml文件的配置修改如下:

    1. <filter>  
    2.   <filter-name>myFilter</filter-name>  
    3.    <filter-class>packagename.MyFilterName</filter-class>  
    4. </filter>  
    5. <filter-mapping>  
    6.    <filter-name>myFilter</filter>  
    7.    <servlet-name> 目标资源1</servlet-name>  
    8.    <dispatcher>REQUEST</dispatcher>  
    9. </filter-mapping>  
    10. <filter-mapping>  
    11.    <filter-name>myFilter</filter>  
    12.    <servlet-name> 目标资源2</servlet-name>  
    13.    <dispatcher>FORWARD</dispatcher>  
    14. </filter-mapping>  


    我们看对目标资源二过滤的配置方式,这时过滤方式为forward,也就是说对转发到目标资源二的请求过滤,如果直接访问目标资源二,过滤器将不起作用。 

    3、include过滤器

    理解了forward过滤器之后,include过滤器就不难理解了。以下方式: 

    1. <filter>  
    2.     <filter-name>myFilter</filter-name>  
    3.    <filter-class>packagename.MyFilterName</filter-class>  
    4. </filter>  
    5. <filter-mapping>  
    6.    <filter-name>myFilter</filter>  
    7.    <servlet-name> 目标资源1</servlet-name>  
    8.    <dispatcher>REQUEST</dispatcher>  
    9. </filter-mapping>  
    10. <filter-mapping>  
    11.    <filter-name>myFilter</filter>  
    12.    <servlet-name> 目标资源2</servlet-name>  
    13.    <dispatcher>INCLUDE</dispatcher>  
    14. </filter-mapping>  

    此表示对包含了目标资源二的请求过滤,如果直接访问目标资源二,则此过滤器将不起作用。

    在JSP页面中的动作:指令包含,这时此过滤器不工作。

    4、error过滤器

    当我们访问一个web目标资源时,如果服务器没有找到该目标资源,那么服务器就会给出一个404错误代码。如果我们给404错误代码定义一个页面,那么当404错误发生时就会调用该页面,请看以下web.xml文件的配置:

    1. <filter>  
    2.    <filter-name>myFilter</filter-name>  
    3.    <filter-class>packagename.MyFilterName</filter-class>  
    4. </filter>  
    5. <filter-mapping>  
    6. <filter-name>myFilter</filter>  
    7.    <servlet-name> /error.jsp</servlet-name>  
    8.    <dispatcher>ERROR</dispatcher>  
    9. </filter-mapping>  
    10. <error-page>  
    11.    <error-code>404</error-code>  
    12.    <location>/error.jsp</location>  
    13. </error-page>  
    当我们访问一个不存在的文件时,就会访问error.jsp,但是配置了过滤器对错误页面进行过滤,所以过滤器先接受到请求,然后再转发给error.jsp。

    如果我们访问一个已经存在的页面,会不会调用error.jsp呢?如果这个页面中有response.sendError(404,"出错了!");那么该错误页面仍然会被调用,过滤器也会工作。

     
     
     

    四、Filter使用范例--登陆验证

    现在很多网页都要你用账号登录后才能浏览相关的内容。这里我实现通过登录账号,然后浏览相应的网页。

    1、新建一个web工程,最终目录 如下:

    2、登陆界面JSP:

    1. <%@ page language="java" contentType="text/html" pageEncoding="UTF-8"%>  
    2.   
    3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
    4. <html>  
    5. <head>  
    6. <title>登录</title>    
    7. </head>  
    8. <body>  
    9. <form action="http://localhost:8080/ServletLearningChapter2_2/Main.jsp" method="POST">    
    10.             用户:<input type="text" name="username" /><br/>    
    11.             密码:<input type="password" name="password" /><br/>    
    12.             <input type="submit" value="登录" />             
    13.         </form>    
    14.   
    15. </body>  
    16. </html>  


    3、登录成功后进行主界面:

    1. <%@ page language="java" contentType="text/html; charset=UTF-8"  
    2.     pageEncoding="UTF-8"%>  
    3. <%@page import="java.util.*"%>  
    4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
    5. <html>  
    6. <head>  
    7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
    8. <title>Insert title here</title>  
    9. </head>  
    10. <body>  
    11. <% String name=request.getParameter("username"); %>  
    12. 欢迎用户:  
    13. <%=name %>   
    14. 您已经登录成功,可以尽情浏览本网站  
    15.   
    16. </body>  
    17. </html>  


    4、一般如果不加过滤器的话,我们是可以直接通过http://localhost:8080/ServletLearningChapter2_2/Main.jsp

    来访问到Main.jsp的。如下:

    但是实际我们是想要得用户登录后才能访问,所以要增加如下的过滤 器

    5、过滤器

    1. package com.mucfc;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. import javax.servlet.Filter;  
    6. import javax.servlet.FilterChain;  
    7. import javax.servlet.FilterConfig;  
    8. import javax.servlet.ServletException;  
    9. import javax.servlet.ServletRequest;  
    10. import javax.servlet.ServletResponse;  
    11. import javax.servlet.http.HttpServletRequest;  
    12. import javax.servlet.http.HttpServletResponse;  
    13. import javax.servlet.http.HttpSession;  
    14.     /**  
    15.      *   
    16.      * 权限过滤器  
    17.      *   
    18.      * */      
    19.     public class AuthorityFilter implements Filter {  
    20.          private FilterConfig config;    
    21.         @Override  
    22.         public void destroy() {  
    23.              this.config=null;    
    24.         }  
    25.   
    26.         @Override  
    27.         public void doFilter(ServletRequest request, ServletResponse response,  
    28.                 FilterChain chain) throws IOException, ServletException {  
    29.             //获取Filter配置参数    
    30.             String encoding=config.getInitParameter("encoding");    
    31.             String loginPage=config.getInitParameter("loginPage");    
    32.             String afterLogin=config.getInitParameter("afterLogin");    
    33.             //设置request编码    
    34.             request.setCharacterEncoding(encoding);    
    35.             HttpServletRequest requ=(HttpServletRequest) request;    
    36.             HttpSession session=requ.getSession();    
    37.             //获取客户请求页面    
    38.             String requestPath=requ.getServletPath();     
    39.             String name=requ.getParameter("username");  
    40.                 if(name==""||name==null){    
    41.                 System.out.println("权限拦截器的消息:"+"终止");    
    42.              HttpServletResponse resq=(HttpServletResponse)response;  
    43.                 resq.sendRedirect(requ.getContextPath()+loginPage);  
    44.             }else{    
    45.                 System.out.println("权限拦截器的消息:"+"放行");    
    46.                 request.setCharacterEncoding("UTF-8");  
    47.                 chain.doFilter(request, response);    
    48.             }    
    49.         }  
    50.   
    51.         @Override  
    52.         public void init(FilterConfig config) throws ServletException {  
    53.             this.config=config;   
    54.         }     
    55.           
    56.     }  


    6、然后在web.xml中来配置过滤器(这里也可以直接 用注解的方式 来配置,具体看上面的例子)

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
    5.     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
    6.   
    7.   <welcome-file-list>  
    8.     <welcome-file>Login.html</welcome-file>  
    9.     <welcome-file>Login.htm</welcome-file>  
    10.     <welcome-file>Login.jsp</welcome-file>  
    11.   </welcome-file-list>  
    12.   
    13.     <!-- 权限拦截器 -->  
    14.      <filter>  
    15.         <filter-name>AuthorityFilter</filter-name>  
    16.         <filter-class>com.mucfc.AuthorityFilter</filter-class>  
    17.         <init-param>  
    18.             <param-name>encoding</param-name>  
    19.             <param-value>GBK</param-value>  
    20.         </init-param>  
    21.         <init-param>  
    22.             <param-name>loginPage</param-name>  
    23.             <param-value>/Login.jsp</param-value>  
    24.         </init-param>  
    25.         <init-param>  
    26.             <param-name>afterLogin</param-name>  
    27.             <param-value>/Main.jsp</param-value>  
    28.         </init-param>  
    29.     </filter>  
    30.     <filter-mapping>  
    31.         <filter-name>AuthorityFilter</filter-name>  
    32.         <url-pattern>/Main.jsp</url-pattern>  
    33.     </filter-mapping>   
    34.   
    35. </web-app>  


    7、下面就是直接启动了,输入http://localhost:8080/ServletLearningChapter2_2/

    然后什么都不输入,直接点击登录,发现又跳转到Login.jsp

    浏览器中直接输入http://localhost:8080/ServletLearningChapter2_2/Main.jsp,它又会自动跳转到Login.jsp

    然后输入一个用户名和密码,就可以正确跳转到Main.jsp(这里没做用户名和密码的判断,只做了一个用户判断)

    再来看看控制台的输出结果

    从控制台的输出结果我们可以知道是正确 的!

  • 相关阅读:
    linux升级node版本
    mysql视图
    mysql全文本搜索
    mysql数据处理函数
    mysql数据分组
    mysql组合查询
    Django添加生产环境配置
    费用保险单,如何失焦时自动补零
    div+css滚动条
    phpadmin导入数据提示文件最大限制的修改方法
  • 原文地址:https://www.cnblogs.com/snail-lb/p/5656641.html
Copyright © 2020-2023  润新知