SpringBoot 中Filter的作用以及使用

1、Filter的作用

Filter使用户可以改变一个 request和修改一个response.
Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在离开 servlet时处理response.
换种说法,filter其实是一个”servlet chaining”(servlet 链).
通俗点说法filter相当于加油站,request是条路,response是条路,
目的地是servlet,这个加油站设在什么地方对什么数据操作可以由你来控制。

Filter过滤器实现的是javax.servlet.Filter接口的类,而在javax.servlet.Filter中定义了以下三个方法:

  • init(FilterConfig fConfig)
    init()方法用来初始化过滤器,可以在init()方法中获取Filter中的初始化参数。
@Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //用来获取Filter中初始化的参数
    }
  • doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    doFilter()方法完成过滤操作。当请求发过来的时候,过滤器将执行doFilter方法。
    在HttpServletRequest 执行doFilter()之前,根据需要检查 HttpServletRequest ,同时也可以修改HttpServletRequest 请求头和数据。
    在HttpServletResponse 执行doFilter()之后,根据需要检查 HttpServletResponse ,同时也可以修改HttpServletResponse响应头和数据。
@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("进行过滤以及逻辑判断操作");
        filterChain.doFilter(servletRequest,servletResponse);
    }
  • destroy()
    Filter对象创建后会驻留在内存,当web应用移除或服务器停止时调用destroy()方法进行销毁。在Web容器卸载 Filter 对象之前被调用。destroy()方法在Filter的生命周期中仅执行一次。通过destroy()方法,可以释放过滤器占用的资源。
@Override
    public void destroy() {
        //销毁Filter对象,Filter生命周期结束
    }

上来我们先创建一个小demo 然后我们再讲解其中的原理
我们在IDEA中创建一个SpringBoot的基础项目(这里不介绍这么创建了)

一、这里采用的@WebFilter注解过滤

目录结构

springboot 增加 filter不生效 springboot的filter_过滤器


@Order(x)x越小优先级 越高

@WebFilter 用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置将相应的类部署为过滤器。**该注解具有下表给出的一些常用属性 ( 以下所有属性均为可选属性,但是 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值 )

springboot 增加 filter不生效 springboot的filter_spring_02

package cn.tll.config;

import org.springframework.core.annotation.Order;

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

/**
 * @author tll
 * @create 2020/8/1 12:41
 * @Order(x) 里面的数越小 越优先执行
 * @WebFilter() 代表着这是个Filter类 并把它注入到容器中
 */
@Order(1)
@WebFilter(initParams = {@WebInitParam(name = "nofilter",value = "/one,/two")})
public class FirstFilter implements Filter {

    /**
     * 不过滤的资源
     */
    private String[] nofilter;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //将不过滤的资源存入数组中
        String nofilterString = filterConfig.getInitParameter("nofilter");
        if (nofilterString!=null&&nofilterString.length()>0){
            nofilter = nofilterString.split(",");
        }

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        boolean flag = isNofilter(request);
        if (flag){
            filterChain.doFilter(servletRequest,servletResponse);
        }else {
            request.getRequestDispatcher("/forword").forward(servletRequest,servletResponse);
        }

    }

    @Override
    public void destroy() {

    }
	/**
	*isNofilter  判断路径是否不需要过滤
	*/
    public boolean isNofilter(HttpServletRequest request){
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        for (String s : nofilter) {
            if (requestURI.contains(s)){
                return true;
            }
        }
        return false;
    }
}

Controller中的代码
这里的@RestController注解作用就不用多说了

package cn.tll.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author tll
 * @create 2020/8/1 12:48
 */
@RestController
public class IndexController {


    @RequestMapping({"/","/index"})
    public String index(){
        return "访问成功";
    }

    @RequestMapping("/forword")
    public String forword(){
        return "请先登录";
    }

    @RequestMapping("/one")
    public String one(){
        return "one";
    }

    @RequestMapping("/two")
    public String two(){
        return "two";
    }
}

最后千万不要忘了在启动类上加上@ServletComponentScan
注:@ServletComponentScan注解的含义在SpringBootApplication(启动类)上使用@ServletComponentScan注解后,Servlet、Filter(过滤器)、Listener(监听器)可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码!

package cn.tll;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

/**
 * 因为使用的是注解Filter 所以需要在程序入口加入@ServletComponentScan
 *
 */
@SpringBootApplication
@ServletComponentScan
public class SpringbootFilterApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootFilterApplication.class, args);
    }

}

二,@Bean注解方式

我们还是先创建一个干净的SpringBoot项目吧

springboot 增加 filter不生效 springboot的filter_java_03


首先把Controller写好 先测试一下有无问题

package cn.tll.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author tll
 * @create 2020/8/2 8:51
 */
@RestController
public class IndexController {

    @RequestMapping({"/","/index"})
    public String index(){
        return "欢迎进入首页";
    }

    @RequestMapping("noRoot")
    public String noRoot(){
        return "对不起,请先登录";
    }

    @RequestMapping("/one")
    public String one(){
        return "one";
    }

    @RequestMapping("/two")
    public String two(){
        return "two";
    }

}

springboot 增加 filter不生效 springboot的filter_过滤器_04


好的没问题

再创建一个WebConfig

package cn.tll.config;

import cn.tll.filter.FirstFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author tll
 * @create 2020/8/2 8:57
 */
@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean filterRegistrationBean(){
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(new FirstFilter());
        //过滤所有路径
        registrationBean.addUrlPatterns("/*");
        //添加不过滤路径
        registrationBean.addInitParameter("noFilter","/one,/two");
        registrationBean.setName("firstFilter");
        registrationBean.setOrder(1);
        return registrationBean;
    }

	 @Bean
	    public FilterRegistrationBean twoFilterRegistrationBean(){
	        FilterRegistrationBean registrationBean = new FilterRegistrationBean(new TwoFilter());
	        registrationBean.setOrder(2);
	        registrationBean.addUrlPatterns("/*");
	        registrationBean.setName("TwoFilter");
	        return registrationBean;
	    }
}

接着就是创建Filter了
这里创建两个Filter主要是用于查看setOrder优先级是否有用
Order(x) 里面的x数值越小优先级越高

package cn.tll.filter;

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

/**
 * @author tll
 * @create 2020/8/2 9:00
 */
public class FirstFilter implements Filter {

    private String[] noFilters;

    /**
     * 过滤器初始化
     * @param filterConfig
     * @throws ServletException
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String noFilter = filterConfig.getInitParameter("noFilter");
        if (noFilter!=null&&noFilter.length()>0){
            noFilters = noFilter.split(",");
        }
    }

    /**
     * 过滤器方法
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("这里是FirstFilter");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        boolean flag = isFilter(request);
        if (flag){
            System.out.println("可以访问");
            filterChain.doFilter(servletRequest,servletResponse);
        }else {
            System.out.println("不可以访问");
            //没有权限不可以访问,需要转发到友好界面
            request.getRequestDispatcher("/noRoot").forward(servletRequest,servletResponse);
        }
    }

    /**
     * 过滤器销毁
     */
    @Override
    public void destroy() {

    }

    /**
     * 判断URL是否包含不过滤的路径
     * @param request
     * @return
     */
    public boolean isFilter(HttpServletRequest request){
        String requestURI = request.getRequestURI();
        for (String noFilter : noFilters) {
            System.out.println(noFilter);
            if (requestURI.contains(noFilter)){
                return true;

            }
        }
        return false;
    }
}
package cn.tll.filter;

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

/**
 * @author tll
 * @create 2020/8/2 9:23
 */
public class TwoFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("这里是TwoFiter");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

大功告成,你觉得那种方法简单呢?