JAVA_WEB 过滤器

6 篇文章 0 订阅
1 篇文章 0 订阅

部分转自:http://blog.csdn.net/reggergdsg/article/details/52821502

一、Filter简介

       Filter是在Servlet 2.3之后增加的新功能,当需要限制用户访问某些资源或者在处理请求时提前处理某些资源时,即可使用过滤器完成。过滤器是以一种组件的形式绑定到Web应用程序当中的,与其他的Web应用程序组件不同的是,过滤器是采用“链”的方式进行处理的,如下图所示:


        在没有使用过滤器以前,客户端都是直接请求Web资源的,但是一旦加入了过滤器,从上图中可以发现,所有的请求都是先交给了过滤器处理,然后再访问相应的Web资源,可以达到对某些资源的访问限制。
      过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换等等操作,便于代码重用,不必每个servlet中还要进行相应的操作。



二、Filter的工作原理
      Filter接口中有一个doFilter方法,当我们编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,
都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
      调用目标资源之前,让一段代码执行。
      是否调用目标资源(即是否让用户访问web资源)。
      调用目标资源之后,让一段代码执行。
      web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。

三、Filter链

      在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,配置在前的则位于链的前端。当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,如果没有,则调用目标资源。
      在doFilter()方法中,chain.doFilter()前的一般是对request执行的过滤操作,chain.doFilter后面的代码一般是对response执行的操作。过滤链代码的执行顺序如下:

    


四、Filter开发步骤

 Filter开发分为2步:
 * 编写java类实现Filter接口,并实现其doFilter方法。
 * 在web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源。

Filter接口定义的3个方法:
public void init(FilterConfig filterConfig) 
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)
public void destroy() 

      3个方法中,最需要注意的是doFilter()方法,在此方法中定义了ServletRequest、ServletResponse和FilterChain 3个参数,从前两个参数中可以发现,过滤器可以完成对任意协议的过滤操作。FilterChain接口的主要作用是将用户的请求向下传递给其他的过滤器或者Servlet。

//简单的过滤器
package com.om.FilterDemo;

import java.io.IOException;

@javax.servlet.annotation.WebFilter(filterName = "Filter")
public class SimpleFilter implements javax.servlet.Filter {
    public void destroy() {
        System.out.println("过滤器销毁。");
    }

    public void doFilter(javax.servlet.ServletRequest req, javax.servlet.ServletResponse resp, javax.servlet.FilterChain chain) throws javax.servlet.ServletException, IOException {
        // 执行过滤
        System.out.println("**执行doFilter()方法之前。");
        chain.doFilter(req, resp);//将请求继续传递
        System.out.println("**执行doFilter()方法之后。");
    }

    public void init(javax.servlet.FilterConfig config) throws javax.servlet.ServletException {
        String initParam=config.getInitParameter("ref");//取得初始化参数
        System.out.println("***过滤器初始化,初始化参数="+initParam);
    }

}
本程序中,SimpleFilter类实现了Filter接口,所以要覆写Filter接口中定义的3个方法。在doFilter()方法中增加了两条输出语句,分别是在FilterChain调用doFilter()方法之前和之后,因为过滤器采用的是“链”的处理方式,所以两条语句都会执行。

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
           version="2.5">
    <filter>
        <filter-name>simple</filter-name>
        <filter-class>com.om.FilterDemo.SimpleFilter</filter-class>
        <init-param>
            <param-name>ref</param-name>
            <param-value>HELLOWORLD</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>simple</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

      过滤器的配置与Servlet的配置样式非常类似。<description>用于添加描述信息,该元素的内容可为空,<description>可以不配置。<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。<filter-class>元素用于指定过滤器的完整的限定类名。<init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。在过滤器中,
      可以使用FilterConfig接口对象来访问初始化参数。如果过滤器不需要指定初始化参数,那么<init-param>元素可以不配置。但需要注意的是,这里的<url-pattern>表示一个过滤器的过滤位置,如果是“/*”表示对于根目录下的一切操作都需要过滤,输入“http://localhost/mldn/”打开虚拟目录首页,程序的运行结果会在Tomcat后台输出,输出内容如下所示:


从上图的输出中可以清楚地发现,过滤器中的初始化方法是在容器启动时自动加载的,并且通过FilterConfig的getInitParameter()方法取出了配置的初始化参数,只初始化一次。但是对于过滤器中的doFilter()方法实际上会调用两次,一次是在FilterChain操作之前,一次是在FilterChain操作之后。

五、过滤器路径

       上面的例子是对一个目录中的所有内容进行过滤,但是在开发中,有可能只对某一个或某几个目录过滤,此时就可以明确地写出是对哪个目录过滤或者是多增加过滤的映射路径。

        对JSP文件夹进行过滤——修改<usl-pattern>

<filter-mapping> 
        <filter-name>simple</filter-name> 
        <url-pattern>/jsp/*</url-pattern> 
</filter-mapping>

        增加多个过滤路径,增加多个<filter-mapping>

<filter-mapping>
        <filter-name>simple</filter-name>
        <url-pattern>/jsp/admin/*</url-pattern>
    </filter-mapping>
    <filter-mapping> 
        <filter-name>simple</filter-name>
        <url-pattern>/js/*</url-pattern> 
    </filter-mapping>

六、Filter的生命周期

6.1、Filter的创建
  Filter的创建和销毁由web服务器负责。 web应用程序启动时,web服务器将创建Filter的实例对象,并调用其init方法,完成对象的初始化
功能,从而为后续的用户请求作好拦截的准备工作,filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数,可获得代表当前
filter配置信息的FilterConfig对象。

6.2、Filter的销毁
  web容器调用destroy方法销毁Filter。destroy方法在Filter的生命周期中仅执行一次。在destroy方法中,可以释放过滤器使用的资源。

6.3、FilterConfig接口
  用户在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其init方法时,会把封装了
filter初始化参数的filterConfig对象传递进来。因此开发人员在编写filter时,通过filterConfig对象的方法,就可获得:
  String getFilterName():得到filter的名称。
  String getInitParameter(String name): 返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
  Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
  public ServletContext getServletContext():返回Servlet上下文对象的引用。


七、过滤器的应用

       过滤器本身是属于一个组件的形式加入到应用程序之中的,例如,可以使用过滤器完成编码的过滤操作或者是用户的登录验证,下面讲解这两种操作的实现。

       应用一、编码过滤

    在Web开发中,编码过滤是必不可少的操作,如果按照之前的做法,在每一个JSP或者Servlet中都重复编写“request.setCharacterEncoding("GBK")”的语句肯定是不可取的,会造成大量的代码重复,那么此时即可通过过滤器完成这种编码过滤。

package com.om.FilterDemo;

import javax.servlet.*;
import java.io.IOException;

public class EncodingFilter implements Filter {
    private String charSet;
    public void destroy() {
    }
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        req.setCharacterEncoding(this.charSet); //设置统一编码
    }
    public void init(FilterConfig config) throws ServletException {
        this.charSet=config.getInitParameter("charset");//取得初始化参数
    }
}

配置web.xml

<filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>com.om.FilterDemo.EncodingFilter</filter-class>
        <init-param>
            <param-name>charset</param-name>
            <param-value>GBK</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

       在初始化操作时,通过FilterConfig中的getInitParameter()取得了一个配置的初始化参数,此参数的内容是一个指定的过滤编码,然后在doFilter()方法中执行request.setCharacterEncoding()操作,即可为所有页面设置统一的请求编码。


    应用二、登录验证

        登录验证是所有Web开发中不可缺少的部分,最早的做法是通过验证session的方式完成,但是如果每个页面都这样做的话,则肯定会造成大量的代码重复,而通过过滤器的方式即可避免这种重复的操作。在这里需要注意的是,session本身是属于HTTP协议的范畴,但是doFilter()方法中定义的是ServletRequest类型的对象,那么要想取得session,则必须进行向下转型,将ServletRequest变为HttpServletRequest接口对象,才能通过getSession()方法取得session对象。

package com.om.FilterDemo;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter(filterName = "LoginFilter")
public class LoginFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request=(HttpServletRequest)req; //向下转型
        HttpSession ses=request.getSession();//获取session
        if(ses.getAttribute("userid")!=null){//判断是否登录
            chain.doFilter(req,resp);
        }else{//没有登录
            request.getRequestDispatcher("login.jsp") .forward(req, resp); //跳转到登录页 
        }

    }

    public void init(FilterConfig config) throws ServletException {

    }

}
        首先通过HttpServlet取得了当前的session,然后判断在session范围内是否存在userid的属性,如果存在,则表示用户已经登录过;如果不存在,则跳转到login.jsp上进行登录。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值