简介
说明
本文用示例介绍SpringBoot(SpringMVC)中的过滤器的用法。
Filter可以有多个。一个filter执行完之后会执行另外一个。
过滤器的使用场景
- 控制用户访问权限
- 记录日志
- 图像转换
- 数据压缩
- 加密
- Token校验
- 媒体类型过滤
实例1:单过滤器
两种方式注册filter(两种方式的本质都是一样的,都是去FilterRegistrationBean注册自定义Filter ):
1、使用Spring Boot提供的FilterRegistrationBean注册Filter
2、使用原生servlet注解(@WebFilter)定义Filter。缺点:无法指定过滤器顺序。
注册方式1:FilterRegistrationBean
定义Filter
package com.example.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class MyFilter implements Filter {
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter.init");
System.out.println(" 过滤器名:" + filterConfig.getFilterName());
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// do something 处理request 或response
System.out.println("MyFilter.doFilter");
if (servletRequest instanceof HttpServletRequest) {
System.out.println(" URL:" + ((HttpServletRequest)servletRequest).getRequestURL());
}
// 调用filter链中的下一个filter
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("MyFilter.destroy");
}
}
注册自定义Filter
package com.example.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean registrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
注册方式2:@WebFilter
此法的缺点:无法指定过滤器顺序。
package com.example.filter;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
// 定义filterName 和过滤的url
@WebFilter(filterName = "myFilter" ,urlPatterns = "/*")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter.init");
System.out.println(" 过滤器名:" + filterConfig.getFilterName());
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// do something 处理request 或response
System.out.println("MyFilter.doFilter");
if (servletRequest instanceof HttpServletRequest) {
System.out.println(" URL:" + ((HttpServletRequest)servletRequest).getRequestURL());
}
// 调用filter链中的下一个filter
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("MyFilter.destroy");
}
}
Controller
package com.example.controller;
import com.example.entity.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/test1")
public User test1(User user) {
System.out.println("HelloController.test1");
return user;
}
}
实体类
package com.example.entity;
import lombok.Data;
@Data
public class User {
private Integer id;
private String name;
private Integer age;
}
测试
启动SpringBoot
2020-09-04 23:25:27.216 INFO 16948 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2020-09-04 23:25:27.216 INFO 16948 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 781 ms MyFilter.init 过滤器名:myFilter 2020-09-04 23:25:27.361 INFO 16948 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor' 2020-09-04 23:25:27.493 INFO 16948 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2020-09-04 23:25:27.501 INFO 16948 --- [ main] com.example.DemoApplication : Started DemoApplication in 1.44 seconds (JVM running for 2.276) 2020-09-04 23:25:40.252 INFO 16948 --- [nio-8080-exec-2] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2020-09-04 23:25:40.253 INFO 16948 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2020-09-04 23:25:40.257 INFO 16948 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
postman访问:http://localhost:8080/hello/test1?name=Tony
后端结果:
MyFilter.doFilter URL:http://localhost:8080/hello/test1 HelloController.test1
postman结果
{
"id": null,
"name": "Tony",
"age": null
}
关闭SpringBoot
Disconnected from the target VM, address: '127.0.0.1:57939', transport: 'socket' MyFilter.destroy 2020-09-04 23:26:00.810 INFO 16948 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
实例2:多过滤器
代码
过滤器1
package com.example.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class MyFilter1 implements Filter {
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter1.init");
System.out.println(" 过滤器名:" + filterConfig.getFilterName());
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
// do something 处理request 或response
System.out.println("MyFilter1.doFilter");
if (servletRequest instanceof HttpServletRequest) {
System.out.println(" URL:" + ((HttpServletRequest)servletRequest).getRequestURL());
}
// 调用filter链中的下一个filter
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("MyFilter1.destroy");
}
}
过滤器2
package com.example.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class MyFilter2 implements Filter {
@Override
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter2.init");
System.out.println(" 过滤器名:" + filterConfig.getFilterName());
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
// do something 处理request 或response
System.out.println("MyFilter2.doFilter");
if (servletRequest instanceof HttpServletRequest) {
System.out.println(" URL:" + ((HttpServletRequest)servletRequest).getRequestURL());
}
// 调用filter链中的下一个filter
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("MyFilter2.destroy");
}
}
配置类
package com.example.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean registrationBean1() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter1());
filterRegistrationBean.addUrlPatterns("/*");
// filterRegistrationBean.setName("xxx"); //可设置过滤器名字
//过滤器执行顺序。(决定doFilter顺序,不决定init和destroy顺序)
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
@Bean
public FilterRegistrationBean registrationBean2() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter2());
filterRegistrationBean.addUrlPatterns("/*");
// filterRegistrationBean.setName("xxx"); //可设置过滤器名字
//过滤器执行顺序(决定doFilter顺序,不决定init和destroy顺序)
filterRegistrationBean.setOrder(2);
return filterRegistrationBean;
}
}
Controller
package com.example.controller;
import com.example.entity.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/test1")
public User test1(User user) {
System.out.println("HelloController.test1");
return user;
}
}
实体类
package com.example.entity;
import lombok.Data;
@Data
public class User {
private Integer id;
private String name;
private Integer age;
}
测试
测试1:启动、访问接口、关闭
启动SpringBoot
MyFilter2.init 过滤器名:myFilter2 MyFilter1.init 过滤器名:myFilter1
postman访问:http://localhost:8080/hello/test1?name=Tony
后端结果
MyFilter1.doFilter URL:http://localhost:8080/hello/test1 MyFilter2.doFilter URL:http://localhost:8080/hello/test1 HelloController.test1
postman结果
{
"id": null,
"name": "Tony",
"age": null
}
关闭SpringBoot
Disconnected from the target VM, address: '127.0.0.1:57939', transport: 'socket' MyFilter2.destroy MyFilter1.destroy 2020-09-04 23:26:00.810 INFO 16948 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
测试2:配置类setOrder的值调换顺序
配置类:
package com.example.filter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean registrationBean1() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter1());
filterRegistrationBean.addUrlPatterns("/*");
// filterRegistrationBean.setName("xxx"); //可设置过滤器名字
//过滤器执行顺序。(决定doFilter顺序,不决定init和destroy顺序)
filterRegistrationBean.setOrder(2);
return filterRegistrationBean;
}
@Bean
public FilterRegistrationBean registrationBean2() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter2());
filterRegistrationBean.addUrlPatterns("/*");
// filterRegistrationBean.setName("xxx"); //可设置过滤器名字
//过滤器执行顺序(决定doFilter顺序,不决定init和destroy顺序)
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
}
启动SpringBoot
MyFilter2.init 过滤器名:myFilter2 MyFilter1.init 过滤器名:myFilter1
postman访问:http://localhost:8080/hello/test1?name=Tony
后端结果
MyFilter2.doFilter URL:http://localhost:8080/hello/test1 MyFilter1.doFilter URL:http://localhost:8080/hello/test1 HelloController.test1
postman结果
{
"id": null,
"name": "Tony",
"age": null
}
关闭SpringBoot
Disconnected from the target VM, address: '127.0.0.1:57939', transport: 'socket' MyFilter2.destroy MyFilter1.destroy 2020-09-04 23:26:00.810 INFO 16948 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
实例3:拦截请求
如果想要拦截请求,直接报错,方法是:
- 拦截:直接return,不调用filterChain.doFilter(servletRequest,servletResponse);即可
- 报错:将报错直接写到HttpServletResponse里。

请先 !