过滤器Filter

一、概述

过滤器:
地漏,滤网,滤纸,口罩,净水机 :过滤掉杂质

servlet 过滤器:
拦截不符合要求的请求进行拦截,使之不能够到达servlet
对请求的数据进行加工处理

过滤器Filter

作用:
1.拦截 (不符合要求请求拦截,使之不达到servlet)
2.抽取公共代码,对共同的的业务进行抽离,加工数据

二、过滤器使用场景

设置编码格式

 //解决当前servlet 接收中文乱码
req.setCharacterEncoding("utf-8");
// 解决响应乱码
resp.setContentType("text/html;charset=utf-8");

记录日志信息

记录所用请求的路径,参数,客户端ip,异常 等信息
为什么记录日志?
在软件的生产/线上环境 只能使用日志排查bug

将鉴权的代码抽离带过滤其中

减少代码冗余

黑白名单,敏感词过滤

举例:一个用户每秒钟访问服务器100次/机器攻击 将用户加入黑名单,拒绝提供服务

三、实现过滤器

实现Filter

编写Java类实现Filter接口
在doFilter方法中编写拦截逻辑
设置拦截路径

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

/**
 * 第一个过滤器
 * 1.实现 javax.servlet.Filter
 *
 *  2.完成  public void doFilter 方法
 *
 *  3.声明 Filter
 *        1.在web.xml
 *                  <!--
 *         声明 过滤器
 *     -->
 *     <filter>
 *         <filter-name>MyFilter1</filter-name>
 *         <filter-class>com.qfedu.servlet.filter.MyFilter1</filter-class>
 *     </filter>
 *
 *     <!--
 *         为MyFilter1 配置感兴趣的路径
 *         /*   对 / 下所有的路径都惊醒拦截过滤
 *         /goods/*  只对/goods/ 下的路径 过滤
 *
 *         *.do  只对所有 以.do  结尾的路径匹配
 *
 *     -->
 *     <filter-mapping>
 *         <filter-name>MyFilter1</filter-name>
 *         <url-pattern>/*</url-pattern>
 *     </filter-mapping>
 *
 *   2.使用注解声明
 *
 */
public class MyFilter1 implements Filter {
    // 初始化方法  容器启动时加载调用
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        System.out.println("MyFilter1 -----init");

    }

    @Override // 当请求 符合 过滤器拦截的路径 当前方法执行 过滤/拦截 业务逻辑
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("MyFilter1 -----doFilter");
        // servletRequest 请求
        // servletResponse 响应
        // filterChain 过滤器调用连 ,决定者是否放行当前请求到 后面的过滤器 或者 servlet

        // 放行当前请求  交给后面 的  过滤器 或者 servlet 进行处理
        //如果不写,则默认拦截全部
        filterChain.doFilter(servletRequest, servletResponse);

    }

    @Override
    public void destroy() {
        System.out.println("MyFilter1 -----destroy");
    }
}

web.xml声明


    <!--
        声明 过滤器
    -->
    <filter>
        <filter-name>MyFilter1</filter-name>
        <filter-class>com.qfedu.servlet.filter.MyFilter1</filter-class>
    </filter>

    <!--
        为MyFilter1 配置感兴趣的路径
        /*   对 / 下所有的路径都惊醒拦截过滤
        /goods/*  只对/goods/ 下的路径 过滤

        *.do  只对所有 以.do  结尾的路径匹配

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

web.xml声明的优先级

<!--
        声明 过滤器
    -->
    <filter>
        <filter-name>MyFilter1</filter-name>
        <filter-class>com.qfedu.servlet.filter.MyFilter1</filter-class>
    </filter>

    <filter>
        <filter-name>MyFilter2</filter-name>
        <filter-class>com.qfedu.servlet.filter.MyFilter2</filter-class>
    </filter>

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

    <!--
        在web.xml 中声明 的  <filter-mapping>  的顺寻决定 Filter 拦截的顺序
        <filter-mapping> 越靠上,优先级越高
    -->


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

基于注解的声明

基于注解的Filter 过滤的顺序,是按照Filter名称的字典顺序进行加载(也就是按照英文字母)

@WebFilter("/*")// 声明 当前Filter 加入到容器
public class MyFilter1 implements Filter {
。。。。
}

@WebFilter("/*")// 声明 当前Filter 加入到容器
public class MyFilter2 implements Filter {
。。。。
}

设置编码格式过滤器

/**
  配置编码格式
   使用过滤器结局中文乱码问题
 */
@WebFilter("*.do")// 声明 当前Filter 加入到容器
public class EncodingFilter implements Filter {
    // 初始化方法  容器启动时加载调用
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        System.out.println("EncodingFilter -----init");

    }

    @Override // 当请求 符合 过滤器拦截的路径 当前方法执行 过滤/拦截 业务逻辑
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("EncodingFilter -----doFilter");


        servletRequest.setCharacterEncoding("utf-8");

        // 设置响应编码格式
        // "text/html;charset=utf-8"  告诉浏览器得到响应 使用html 解析该请求
        // css js .png .image 不能解析为html
        servletResponse.setContentType("text/html;charset=utf-8");


        // 放行当前请求交给后面的过滤器或者servlet 进行处理
        filterChain.doFilter(servletRequest, servletResponse);

    }

    @Override
    public void destroy() {
        System.out.println("EncodingFilter -----destroy");
    }
}

登录鉴权过滤器

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

/**
 * 鉴权用户是否登录 过滤器
 */
@WebFilter("*.do")
public class LoginFilter implements Filter {

    // 初始化方法  容器启动时加载调用
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        System.out.println("LoginFilter -----init");

    }

    @Override // 当请求 符合 过滤器拦截的路径 当前方法执行 过滤/拦截 业务逻辑
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("LoginFilter -----doFilter");

        // 将 ServletRequest 转化为 HttpServletRequest
        HttpServletRequest req  = (HttpServletRequest) servletRequest;

        // 获取当前浏览器请求的session
        HttpSession session = req.getSession();

        // 获取标记位
        Object result =  session.getAttribute("loginFlag");

        if (result!=null){ // 鉴权(鉴定用户是否登录)
            boolean loginFlag = (boolean) result;

            if (loginFlag){ // 鉴权成功  放行

                // 放行当前请求  交给后面 的  过滤器 或者 servlet 进行处理
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }

        }

        // 鉴权失败 需要登录才可以访问
        req.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);

    }

    @Override
    public void destroy() {
        System.out.println("LoginFilter -----destroy");
    }

}

顺序问题总结

1.基于xml声明的Filter,是按照FilterMapping 进行排序
2.注解:基于注解的Filter 过滤的顺序,是按照Filter名称的字典顺序进行加载
3.xml 和注解 的Filter 顺序,所有的xml顺序都优于 注解的顺序

上一篇:由浅入深讲解责任链模式,理解Tomcat的Filter过滤器


下一篇:Filter过滤器的使用