Filter(过滤器)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MyBabyChao/article/details/82353663

1.什么是Filter

Filter也称之为过滤器,可以对web服务器管理的所有web资源:例如Jsp、Servlet、html文件等进行拦截,从而实现一些特殊的功能。

Filter的用途
1. 解决中文乱码问题
2. 权限访问控制
3. 过滤敏感词汇
4. 压缩响应信息


2.编写过滤器

实现过滤器需要两个步骤:

  1. 编写Java类实现Filter接口
  2. 在web.xml文件中注册Filter,并设置它需要拦截的资源。
package com.mbc.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 MyFilter implements Filter {
    /**
     * init()属于Filter的生命周期方法。当web应用程序启动时,web服务器将创建Filter的实例对象,
     * 调用init方法,完成对象的初始化功能,从而能对用户的请求进行拦截。Filter对象只会创建一次,因此
     * init方法也只会执行一次。init方法的参数:FilterConfig对象,封装了当前filter的配置信息,由服务器
     * 根据web.xml中的相应的配置信息来生成。
     */
    public void init(FilterConfig fConfig) throws ServletException {
        System.out.println("过滤器初始化了。。。");
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //对request和response进行一些预处理
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        System.out.println("我是目标资源执行之前运行的代码...");
        chain.doFilter(request, response);//让目标资源执行,放行
        System.out.println("我是目标资源执行之后,响应回给客户端时经过过滤器运行的代码...");
    }

    /**
     * destroy()属于Filter的生命周期方法。在服务器关闭之前执行,仅执行一次,
     * 用于释放过滤器使用的资源
     */
    public void destroy() {
        System.out.println("过滤器销毁了。。。");
    }
}

在web. xml中配置Filter

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.mbc.filter.MyFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Filter是如何实现拦截的

当我们编写好Filter并配置好Filter要对哪些web资源拦截后,当用户需要访问配置有Filter的web资源时,web服务器每次在调用web资源的service方法之前会调用Filter的doFilter方法。该方法中可以决定是否过滤掉用户的请求。web服务器调用Filter的doFilter方法时,会传递一个FilterChain的对象进来,它也提供了一个doFilter方法,开发人员根据需求决定是否调用此方法(chain.doFilter(request, response);)。若调用,web服务器通过调用web资源的service方法,用户就可以访问到请求的资源,否则就访问不了。

image

Filter中doFilter()的代码执行如下

  1. 调用目标资源前,让一段代码执行
  2. 是否调用目标资源(即是否有FilterChain对象的doFilter方法)
  3. 调用目标资源后,响应回给客户端时经过Filter时执行的代码

即若用户对web资源的访问通过Filter的过滤后,服务器对用户的访问进行响应时还需要执行chain.doFilter(request, response)下的代码。

如图所示:图片来自javaweb学习总结(四十二)——Filter(过滤器)学习


3.Filter的部署

Filter分为两个步骤

  1. 注册Filter
  2. 映射Filter

1. 注册Filter

<filter>
          <description>过滤器的描述</description>
          <filter-name>MyFilter</filter-name>
          <filter-class>com.mbc.filter.MyFilter</filter-class>
          <!--配置FilterDemo02过滤器的初始化参数-->
          <init-param>
              <description>配置过滤器的初始化参数</description>
              <param-name>name</param-name>
              <param-value>mbc</param-value>
          </init-param>
          <init-param>
              <description>配置初始化参数</description>
              <param-name>age</param-name>
              <param-value>18</param-value>
          </init-param>
</filter>

说明:
- <description>:用于添加描述信息,可以不配置
- <filter-name>:用于指定Filterd的名称
- <filter-class>:用于指定过滤器的完整类名
- <init-param>:用于为过滤器指定初始化参数,可以有多个。它的子元素<param-name>指定参数的名字,<parm-value>指定参数的值。此元素可以不配置。通过FilterConfig对象访问初始化参数,类似Servlet的ServletConfig。

2. 映射Filter

<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

说明:
- <filter-mapping>:元素用于设置一个Filter所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet名称和资源访问的请求路径

  • <filter-name>:子元素用于设置filter的注册名称。该值必须是在元素中声明过的过滤器的名字

  • <url-pattern>:设置filter所拦截的请求路径

  • <servlet-name>:指定过滤器所拦截的Servlet名称。

  • <dispatcher>:指定过滤器所拦截的资源被Servlet容器调用的方式,可以是

    • REQUEST:只要是请求过来,都拦截,默认就是REQUEST

    • FORWARD: 只要是转发都拦截

    • ERROR: 页面出错发生跳转时拦截

    • INCLUDE:包含页面的时候就拦截

可以设置多个子元素用来指定Filter对资源的多种调用方式进行拦截


4.多个Filter的执行顺序

如果有多个过滤器,那么他们会按照注册的映射顺序执行,即根据web.xml中元素的配置顺序。只要有一个过滤器不放行,那么后面排队的过滤器不会收到请求。


5.Filter应用实例

解决中文乱码问题

这里使用装饰者模式,对GET请求进行装饰。包括以下文件:

  1. index.html:发送get、post请求的界面
  2. EncodingFilter:过滤器,对所有的请求进行编码处理
  3. IndexServlet:Servlet,测试是否能得到正确的数据
  4. EncodingRequestImpro:装饰类,对get请求的getParameterMap()、getParameterValues()、getParameter()进行装饰(编码处理)

1.index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <a href="IndexServlet?name=张三&hobby=游泳">通过get提交中文数据</a>
    <form method="post" action="IndexServlet">
        <input name="name" value="张三">
        <input name="hobby" value="游泳">
        <input type="submit" value="提交">
    </form>
</body>
</html>

2.EncodingFilter

package com.mbc.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 com.mbc.servlet.EncodingRequest;
import com.mbc.servlet.EncodingRequestImpro;

public class EncodingFilter implements Filter {


    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        if(req.getMethod().equals("GET")) {
            HttpServletRequest req = (HttpServletRequest) request;    
            //对请求进行装饰
            EncodingRequestImpro encodingRequest = new EncodingRequestImpro(req);
            //装饰完后放行
            chain.doFilter(encodingRequest, response);
        }else if(req.getMethod().equals("POST")) {
            request.setCharacterEncoding("UTF-8");
            chain.doFilter(request, response);
        }

    }

    public void init(FilterConfig fConfig) throws ServletException {
    }

    public void destroy() {
    }
}

EncodingFilter部署

<filter>
    <display-name>EncodingFilter</display-name>
    <filter-name>EncodingFilter</filter-name>
    <filter-class>com.mbc.filter.EncodingFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>EncodingFilter</filter-name>
    <url-pattern>/*</url-pattern><!--对所有请求都拦截-->
    <dispatcher>REQUEST</dispatcher>
 </filter-mapping>

3.EncodingRequestImpro

package com.mbc.servlet;

import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class EncodingRequestImpro extends HttpServletRequestWrapper {
    private HttpServletRequest request = null;
    private boolean flag = false;   //用于标记map是否被编码过了

    public EncodingRequestImpro(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        Map<String, String[]> map = request.getParameterMap();
        if(map != null && flag == false) {
            flag = true;
            Set<String> keySet = map.keySet();
            for (String key : keySet) {
                String[] values = map.get(key);
                for(int i = 0; i < values.length; i++) {//对作用域中map中的值重新编码
                    try {
                        values[i] = new String(values[i].getBytes("ISO-8859-1"), "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return map;
    }

    @Override
    public String[] getParameterValues(String name) {
        Map<String, String[]> map = this.getParameterMap();//调用正确编码的map
        if(map != null) {
            return map.get(name);
        }
        return null;
    }

    @Override
    public String getParameter(String name) {
        String[] values = this.getParameterValues(name);
        if(values != null) {
            return values[0];
        }
        return null;
    }
}
  1. IndexServlet
package com.mbc.servlet;

import java.io.IOException;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class IndexServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name = request.getParameter("name");
        String hobby = request.getParameter("hobby");
        String[] values = request.getParameterValues("name");
        Map<String, String[]> map = request.getParameterMap();

        System.out.println("--------------");//检查getParameterValues()得到的是否是乱码
        for (String string : values) {
            System.out.println("values = " + string);
        }

        System.out.println("--------------");//检查getParameterMap()得到的是否是乱码
        for(Map.Entry<String, String[]> entry : map.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue()[0]);
        }

        System.out.println("-----------------");//检查getParameter得到的是否是乱码
        System.out.println("name = "+name + "hobby = " + hobby);

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

参考:

javaweb学习总结(四十二)——Filter(过滤器)学习

JavaWeb三大组件之过滤器(Filter)

使用过滤器(Filter)解决请求参数中文乱码问题(复杂方式)

猜你喜欢

转载自blog.csdn.net/MyBabyChao/article/details/82353663