06月07, 2019

Java Web--Servlet--Filter过滤器

Filter过滤器

一、Filter简介

Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,如下所示: -w701

二、Filter是如何实现拦截的?

  Filter接口中有一个doFilter方法,当我们编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:

  1. 调用目标资源之前,让一段代码执行。
  2. 是否调用目标资源(即是否让用户访问web资源)。
  3. 调用目标资源之后,让一段代码执行。

  web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对 象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方 法,即web资源就会被访问,否则web资源不会被访问。

三、Filter开发入门

3.1、Filter开发步骤

Filter开发分为二个步骤:

  1. 编写java类实现Filter接口,并实现其doFilter方法。
  2. 如果是配置XML, 在 web.xml 文件中使用<filter><filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源。如果是配置注解,在自定义的Filter类上,使用@WebFilter直接,最关键的属性是:filterNameurlPatternsinitParams

3.2、IDEA开发Filter流程

选择创建Filter

-w591

创建Filter类名以及配置方式

-w552

Filter类代码

package com.yingside.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;

@WebFilter(filterName = "TestFilterDemo",
        urlPatterns = "/*", //通配符,表示对根目录下所有资源过滤
        initParams = {
            @WebInitParam(name = "charset", value = "utf-8") //这里可以放一些初始化的参数
        }
)
public class TestFilterDemo implements Filter {
    public void destroy() {
        System.out.println("TestFilterDemo.destroy ---- 容器销毁时调用");
    }
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("TestFilterDemo.doFilter ---- 过滤前");
        chain.doFilter(req, resp);
        System.out.println("TestFilterDemo.doFilter ---- 过滤后");
    }
    public void init(FilterConfig config) throws ServletException {
        System.out.println("TestFilterDemo.init ---- 初始化Filter时调用,单例模式,只会调用一次");
    }
}

使用web.xml配置

注意:注解和web.xml选择一种方式配置就可以了,不要两个都配置

在配置文件中的配置如下:

<!--配置过滤器-->
<filter>
    <filter-name>TestFilterDemo</filter-name>
    <filter-class>com.yingside.filter.TestFilterDemo</filter-class>
    <!--配置TestFilterDemo过滤器的初始化参数-->
    <init-param>
        <description>配置TestFilterDemo过滤器的初始化参数</description>
        <param-name>charset</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>

<!--映射过滤器-->
<filter-mapping>
    <filter-name>TestFilterDemo</filter-name>
    <!--“/*”表示拦截所有的请求 -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

这样,访问界面上的所有请求,都会触发filter拦截,可以自定义一个Servlet页面做一下测试,甚至是静态页面的请求也会触发过滤器

这是一个简单的配置流程,那么现在我们来看一个Filter过滤器的实际应用

四、Filter统一过滤字符编码

每次建一个Servlet都需要去过滤request Post,Get请求的一些字符编码,以及Response响应的编码,能不能一次性解决这个问题,Filter过滤器就能帮我们解决这个问题

过滤器Filter:

package com.yingside.filter;

import com.yingside.wrapper.CharacterEncodingRequest;

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

@WebFilter(filterName = "CharacterEncodingFilter",
        urlPatterns = "/*",
        initParams = {
                @WebInitParam(name = "charset", value = "utf-8")
        }
)
public class CharacterEncodingFilter implements Filter {
    private FilterConfig config;
    private String defaultCharset = "UTF-8";
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //将请求和相应转换为HttpServletRequest,HttpServletResponse
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //读取初始化的参数
        String charset = config.getInitParameter("charset");
        if(charset==null){
            charset = defaultCharset;
        }
        //设置Post请求编码
        request.setCharacterEncoding(charset);
        //设置响应编码
        response.setContentType("text/html;charset="+charset);

        //但是get请求的乱码问题,需要具体参数的转换
        //这里不能直接获取参数,我们也不知道到底是哪些参数需要转换
        //但是,java提供Request对象的装饰模式,让我们可以自定义加强Request对象
        //我们可以自己继承这个类增强Request对象,
        //在这个装饰模式的类中,我们可以加强getParameter(name)这个方法
        CharacterEncodingRequest characterEncodingRequest = new CharacterEncodingRequest(request);
        //注意这里传入过滤链中的request是我们加强过的request了
        chain.doFilter(characterEncodingRequest, resp);
    }

    public void init(FilterConfig config) throws ServletException {
        this.config = config;
    }

}

CharacterEncodingRequest类:

package com.yingside.wrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.UnsupportedEncodingException;

public class CharacterEncodingRequest extends HttpServletRequestWrapper {
    private HttpServletRequest request;
    public CharacterEncodingRequest(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    @Override
    public String getParameter(String name) {
        //获取参数的值
        String value = this.request.getParameter(name);
        if (value == null) {
            return null;
        }
        //如果不是get请求,直接返回参数的值
        if(!this.request.getMethod().equalsIgnoreCase("get")){
            return value;
        }
        else{
            try {
                value = new String(value.getBytes("ISO8859-1"),"UTF-8");
                return value;
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

本文链接:http://www.yanhongzhi.com/post/filter.html

-- EOF --

Comments