过滤器Filter可以在controller处理逻辑之前和之后加入一些其他逻辑,可以在controller之前进行验证和信息处理,或者在controller之后进行统计记录。过滤器可以设置过滤路径,多个过滤器也可以指定过滤顺序;
过滤器可以实现一个接口类javax.servlet.Filter:
实现接口中的三个方法:
注:doFilter方法里有个FilterChain参数,在过滤逻辑里需要手动调用chain.doFilter(request, response)才会往下处理其他过滤器和controller;
可以使用三种方法配置过滤器:
只需要实现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之后"); } }
从启动日志就可以看到,项目启动的时候过滤器就是初始化:
http测试使用的是Apipost工具,执行几次测试:
程序输出日志:
可以看到所有的路径都会被过滤器过滤,没有controller处理的路径也会被过滤;
结束项目,过滤器就会执行销毁方法:
首先需要实现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 FilterRegistrationBeana() { 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:
访问controller测试:
Order为1的filter3先过滤,Order为2的filter2在后,先使用@Configuration配置的过滤器过滤,再使用@Component的过滤器,另外controller之前过滤器是顺序执行,controller之后则是倒序执行,即由外向内进入再由内向外退出过滤器;
在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: "); Enumerationele = 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"); } }
启动测试,过滤器初始化:
测试:
先执行@Configuration配置的过滤器,再执行@WebFilter注解配置的过滤器,最后执行@Component配置的过滤器(这也是默认order顺序);
@Component+@Order也能设置过滤器顺序;
在使用@WebFilter的过滤器上不要配置@Component@Configuration,否则会使@WebFilter里的过滤路径失效,将过滤所有路径;
过滤器执行顺序: