统一拦截技术有两种,Filter过滤器和Interceptor拦截器,用于统一拦截到所有的请求校验令牌的有效性.两种只需要实现一种即可.
1. Filter过滤器
Filter表示过滤器,是 JavaWeb三大组件(Servlet、Filter、Listener)之一,可以把对资源的请求拦截下来,从而实现一些特殊的功能,比如完成一些通用的操作:登录校验、统一编码处理、敏感字符处理等.
1.1. 基本使用操作
- 第1步,定义过滤器:定义一个类,实现 Filter 接口,并重写其所有方法.
- 第2步,配置过滤器:Filter类上加 @WebFilter 注解,配置拦截资源的路径.引导类上加 @ServletComponentScan 开启Servlet组件支持.
1.1.1. 定义过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class DemoFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init ..."); }
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { System.out.println("拦截到了请求..."); }
public void destroy() { System.out.println("destroy ... "); } }
|
1.1.2. 配置过滤器
Filter的配置需要在Filter类上添加一个注解:@WebFilter,并指定属性urlPatterns,通过这个属性指定过滤器要拦截哪些请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @WebFilter(urlPatterns = "/*") public class DemoFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init ..."); }
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { System.out.println("拦截到了请求..."); }
public void destroy() { System.out.println("destroy ... "); } }
|
在Filter类上面加了@WebFilter注解之后,接下来我们还需要在启动类上面加上一个注解@ServletComponentScan,通过这个@ServletComponentScan注解来开启SpringBoot项目对于Servlet组件的支持.
1 2 3 4 5 6 7
| @ServletComponentScan @SpringBootApplication public class TliasManagementApplication { public static void main(String[] args) { SpringApplication.run(TliasManagementApplication.class, args); } }
|
1.2. 登录校验
- 获取请求url
- 判断请求url中是否包含login,如果包含,说明是登录操作,放行
- 获取请求头中的令牌(token)
- 判断令牌是否存在,如果不存在,响应 401
- 解析token,如果解析失败,响应 401
- 放行

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| package com.itheima.filter;
import com.itheima.utils.JwtUtils; import jakarta.servlet.*; import jakarta.servlet.annotation.WebFilter; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpStatus; import org.springframework.util.StringUtils; import java.io.IOException;
@Slf4j @WebFilter(urlPatterns = "/*") public class TokenFilter implements Filter {
@Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; String url = request.getRequestURL().toString();
if(url.contains("login")){ log.info("登录请求 , 直接放行"); chain.doFilter(request, response); return; }
String jwt = request.getHeader("token");
if(!StringUtils.hasLength(jwt)){ log.info("获取到jwt令牌为空, 返回错误结果"); response.setStatus(HttpStatus.SC_UNAUTHORIZED); return; }
try { JwtUtils.parseJWT(jwt); } catch (Exception e) { e.printStackTrace(); log.info("解析令牌失败, 返回错误结果"); response.setStatus(HttpStatus.SC_UNAUTHORIZED); return; }
log.info("令牌合法, 放行"); chain.doFilter(request , response); }
}
|
1.3. 执行流程
单个Filter会再初始化执行init(),放行执行doFilter(),销毁执行destroy()
多个Filter按照过滤器类名(字符串)的自然排序执行

2. Interceptor拦截器
拦截器是一种动态拦截方法调用的机制,类似于过滤器,是Spring框架中提供的,用来动态拦截控制器方法的执行
2.1. 基本使用操作
2.1.1. 定义拦截器
实现HandlerInterceptor接口,并重写其所有方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Component public class DemoInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle .... "); return true; }
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle ... "); }
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion .... "); } }
|
2.1.2. 注册配置拦截器
创建一个配置类 WebConfig,实现WebMvcConfigurer接口,并重写addInterceptors方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Configuration public class WebConfig implements WebMvcConfigurer {
@Autowired private DemoInterceptor demoInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(demoInterceptor).addPathPatterns("/**"); } }
|
2.2. 登录校验
和登录校验Filter过滤器当中的逻辑完全一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @Slf4j @Component public class TokenInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String url = request.getRequestURL().toString();
if(url.contains("login")){ log.info("登录请求 , 直接放行"); return true; }
String jwt = request.getHeader("token");
if(!StringUtils.hasLength(jwt)){ log.info("获取到jwt令牌为空, 返回错误结果"); response.setStatus(HttpStatus.SC_UNAUTHORIZED); return false; }
try { JwtUtils.parseJWT(jwt); } catch (Exception e) { e.printStackTrace(); log.info("解析令牌失败, 返回错误结果"); response.setStatus(HttpStatus.SC_UNAUTHORIZED); return false; }
log.info("令牌合法, 放行"); return true; }
}
|
1 2 3 4 5 6 7 8 9 10 11 12
| @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private TokenInterceptor tokenInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(tokenInterceptor).addPathPatterns("/**"); } }
|
2.3. 拦截器的使用细节
2.3.1. 2.5.4 拦截路径
通过addPathPatterns(“要拦截路径”)方法,就可以指定要拦截哪些资源.
还可以指定不拦截哪些资源,只需要调用excludePathPatterns(“不拦截路径”)方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Configuration public class WebConfig implements WebMvcConfigurer {
@Autowired private DemoInterceptor demoInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(demoInterceptor) .addPathPatterns("/**") .excludePathPatterns("/login"); } }
|
拦截路径 |
含义 |
举例 |
/* |
一级路径 |
能匹配/depts,/emps,/login,不能匹配 /depts/1 |
/** |
任意级路径 |
能匹配/depts,/depts/1,/depts/1/2 |
/depts/* |
/depts下的一级路径 |
能匹配/depts/1,不能匹配/depts/1/2,/depts |
/depts/** |
/depts下的任意级路径 |
能匹配/depts,/depts/1,/depts/1/2,不能匹配/emps/1 |
2.3.2. 执行流程
定义了拦截器后,会在执行Controller的方法之前,请求被拦截器拦截住.执行preHandle()方法,这个方法执行完成后需要返回一个布尔类型的值,如果返回true,就表示放行本次操作,才会继续访问controller中的方法;如果返回false,则不会放行(controller中的方法也不会执行).

3. 过滤器和拦截器之间的区别
- 接口规范不同:过滤器需要实现Filter接口,而拦截器需要实现HandlerInterceptor接口.
- 拦截范围不同:过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源.