SpringBoot——使用Filter过滤器
作者:mmseoamin日期:2023-12-11

过滤器Filter可以在controller处理逻辑之前和之后加入一些其他逻辑,可以在controller之前进行验证和信息处理,或者在controller之后进行统计记录。过滤器可以设置过滤路径,多个过滤器也可以指定过滤顺序;

过滤器可以实现一个接口类javax.servlet.Filter:

SpringBoot——使用Filter过滤器,第1张

实现接口中的三个方法:

  1. init:过滤器初始化操作,springboot启动的时候调用;
  2. doFilter:过滤处理逻辑;
  3. destroy:过滤器销毁操作,项目结束停止的时候调用;

注:doFilter方法里有个FilterChain参数,在过滤逻辑里需要手动调用chain.doFilter(request, response)才会往下处理其他过滤器和controller;

可以使用三种方法配置过滤器:

1.使用@Component过滤所有url地址

只需要实现Filter接口,实现接口里必要的doFilter方法(init和destroy方法是接口里的默认方法),实现类使用@Component修饰就可以了;

启动类,使用的默认配置,端口8080,本机ip是192.168.1.30:

/**
 * 2023年3月10日下午3:51:13
 */
package testspringboot.test8filter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 * @author XWF
 *
 */
@SpringBootApplication
public class Test8Main {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SpringApplication.run(Test8Main.class, args);
	}
}

controller类:

/**
 * 2023年3月10日下午4:05:24
 */
package testspringboot.test8filter;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author XWF
 *
 */
@RestController
@RequestMapping("/filter")
public class MyController {
	@RequestMapping("/test")
	public String test1(String a) {
		System.out.println("_Controller_test1:" + a);
		return "test1";
	}
	
	@RequestMapping("/test/a")
	public String test2(String a) {
		System.out.println("_Controller_test2:" + a);
		return "test2";
	}
	
	@RequestMapping("/test/b")
	public String test3(String a) {
		System.out.println("_Controller_test3:" + a);
		return "test3";
	}
	
}

测试的Filter类:

/**
 * 2023年3月10日下午4:00:40
 */
package testspringboot.test8filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
/**
 * @author XWF
 *
 */
@Component
public class MyFilter1 implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("MyFilter1 init:" + filterConfig.getFilterName());
	}
	
	@Override
	public void destroy() {
		System.out.println("MyFilter1 destroy");
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("过滤所有Controller之前");
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		System.out.println("RequestURL=" + httpRequest.getRequestURL());
		chain.doFilter(request, response);
		System.out.println("过滤所有Controller之后");
	}
}

从启动日志就可以看到,项目启动的时候过滤器就是初始化:

SpringBoot——使用Filter过滤器,第2张

http测试使用的是Apipost工具,执行几次测试:

SpringBoot——使用Filter过滤器,第3张

SpringBoot——使用Filter过滤器,第4张

SpringBoot——使用Filter过滤器,第5张

SpringBoot——使用Filter过滤器,第6张

程序输出日志:

SpringBoot——使用Filter过滤器,第7张

可以看到所有的路径都会被过滤器过滤,没有controller处理的路径也会被过滤;

结束项目,过滤器就会执行销毁方法:

SpringBoot——使用Filter过滤器,第8张

2.使用@Configuration配置过滤器

首先需要实现Filter接口(不使用@Component注解),然后需要一个@Configuration配置类,配置类里使用@Bean手动定义注入FilterRegistrationBean类,使用FilterRegistrationBean类设置自定义的Filter实现类和一些设置项;

两个Filter实现类:

/**
 * 2023年3月13日下午4:19:00
 */
package testspringboot.test8filter;
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 org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
 * @author XWF
 *
 */
public class MyFilter2ForConf implements Filter {
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("ConfFilter2 init " + filterConfig.getFilterName());
		System.out.println("ConfFilter2 init flag param = " + filterConfig.getInitParameter("flag")); //获得初始化参数
	}
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("配置的MyConfFilter2 start");
		chain.doFilter(request, response);
		System.out.println("配置的MyConfFilter2 end");
	}
}
/**
 * 2023年3月14日上午10:00:53
 */
package testspringboot.test8filter;
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;
/**
 * @author XWF
 *
 */
public class MyFilter3ForConf implements Filter {
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("ConfFilter3 init " + filterConfig.getFilterName());
	}
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("配置的MyConfFilter_3 start");
		chain.doFilter(request, response);
		System.out.println("配置的MyConfFilter_3 end");
	}
}

过滤器配置类:

/**
 * 2023年3月14日上午9:30:13
 */
package testspringboot.test8filter;
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author XWF
 *
 */
@Configuration
public class FilterConf {
	@Bean
	public FilterRegistrationBean a() {
		FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>();
		filterRegistrationBean.setEnabled(true);	//是否启用注入过滤器
		filterRegistrationBean.setFilter(new MyFilter2ForConf());	//设置过滤器
		filterRegistrationBean.setOrder(2);		//设置过滤器顺序,小的在前
		filterRegistrationBean.setName("My_Conf_Filter");	//设置过滤器名字
		List urlPatterns = new ArrayList<>();
		urlPatterns.add("/filter/test/a");
		filterRegistrationBean.setUrlPatterns(urlPatterns);		//设置过滤路径
		filterRegistrationBean.addUrlPatterns("/filter/x", "/filter/y");	//添加过滤路径
//		filterRegistrationBean.setInitParameters(initParameters);	//设置初始化参数
		filterRegistrationBean.addInitParameter("flag", "ok");		//添加设置初始化参数
		return filterRegistrationBean;
	}
	
	@Bean
	public FilterRegistrationBean b() {
		FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>();
		filterRegistrationBean.setFilter(new MyFilter3ForConf());
		filterRegistrationBean.setOrder(1);
		filterRegistrationBean.addUrlPatterns("/filter/test/*");
		return filterRegistrationBean;
	}
	
}

启动项目,三个过滤器都会init:

SpringBoot——使用Filter过滤器,第9张

访问controller测试:

SpringBoot——使用Filter过滤器,第10张

Order为1的filter3先过滤,Order为2的filter2在后,先使用@Configuration配置的过滤器过滤,再使用@Component的过滤器,另外controller之前过滤器是顺序执行,controller之后则是倒序执行,即由外向内进入再由内向外退出过滤器;

3.使用@WebFilter和@ServletComponentScan配置过滤器

在Filter实现类上使用@WebFilter注解,在启动类上使用@ServletComponentScan注解设置扫描路径;(该方法无法设置过滤顺序,默认按类名排序)

启动类添加@ServletComponentScan注解:

/**
 * 2023年3月10日下午3:51:13
 */
package testspringboot.test8filter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
/**
 * @author XWF
 *
 */
@SpringBootApplication
@ServletComponentScan(basePackages = {"testspringboot.test8filter"})
public class Test8Main {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SpringApplication.run(Test8Main.class, args);
	}
}

过滤器实现类:

/**
 * 2023年3月14日上午11:09:18
 */
package testspringboot.test8filter;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.DispatcherType;
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.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
/**
 * @author XWF
 *
 */
@WebFilter(value = "/filter/test/a", urlPatterns = {}, asyncSupported = false, description = "测试过滤器", 
		dispatcherTypes = {DispatcherType.REQUEST},displayName = "displayName", filterName = "注解filter4", 
		initParams = {@WebInitParam(name = "str", value = "HELLO")}, 
		largeIcon = "", smallIcon = "", servletNames = "")
public class MyFilter4ForAnnotation implements Filter {
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("Annotation Filter4 init: " + filterConfig.getFilterName());
		System.out.println("Annotation Filter4 paramNames: ");
		Enumeration ele = filterConfig.getInitParameterNames();		//所有初始化参数名字
		while(ele.hasMoreElements()) System.out.println("\t" + ele.nextElement());
		System.out.println("Annotation Filter4 param str: " + filterConfig.getInitParameter("str"));
	}
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("注解filter4 start");
		chain.doFilter(request, response);
		System.out.println("注解filter4 stop");
	}
}
/**
 * 2023年3月14日上午11:09:35
 */
package testspringboot.test8filter;
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.annotation.WebFilter;
/**
 * @author XWF
 *
 */
@WebFilter("/filter/test/*")
public class MyFilter5ForAnnotation implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("Annotation Filter5 init: " + filterConfig.getFilterName());	//注解Filter默认名是类全路径
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("注解filter5 start");
		chain.doFilter(request, response);
		System.out.println("注解filter5 stop");
	}
}

启动测试,过滤器初始化:

SpringBoot——使用Filter过滤器,第11张

测试:

SpringBoot——使用Filter过滤器,第12张

先执行@Configuration配置的过滤器,再执行@WebFilter注解配置的过滤器,最后执行@Component配置的过滤器(这也是默认order顺序);

@Component+@Order也能设置过滤器顺序;

在使用@WebFilter的过滤器上不要配置@Component@Configuration,否则会使@WebFilter里的过滤路径失效,将过滤所有路径;

过滤器执行顺序:

  • 先执行设置order的(只有@Configuration和@Component两类)
    • 按照设置的order从小到大执行
      • order相同的,先按照@Configuration => @Component排序,相同配置类型里按照类名排序执行;
  • 后执行默认order的
    • 按照@Configuration => @WebFilter => @Component三种类型顺序执行,相同配置类型里按照类名排序执行;