什么是 interceptor
什么是 interceptor interceptor 和 filter 的区别和联系 ?
具体可以看看这篇文章 https://cloud.tencent.com/developer/article/1839568
如何使用
1、定义
@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 执行相关逻辑
// 返回 true 继续执行 返回 false 不继续执行
return true;
}
}
2、注册到 interceptors 里面
1)方式 1
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Resource
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor)
.addPathPatterns("/api/**");
}
}
2)方式2
@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {
// 注入 bean 的方式进行使用
@Bean
public MappedInterceptor someMethodName() {
return new MappedInterceptor(
// => maps to any repository
new String[]{"/api/**"},
new JwtInterceptor()
);
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 执行相关逻辑
// 返回 true 继续执行 返回 false 不继续执行 MVC 里面的代码
return true;
}
}
遇到的坑
然后遇到 BUG 了!遇到了 interceptor 不生效的问题,但是我访问的确实时 /api/user/login 啊?
具体代码
@RestController
@RequestMapping("/user")
@AllArgsConstructor
public class UserController {
private UserService userService;
@PostMapping("/login")
public BaseResponse<LoginUserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
ThrowUtils.throwIf(userLoginRequest == null, ErrorCode.PARAMS_ERROR);
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
LoginUserVO loginUserVO = userService.userLogin(userAccount, userPassword, request);
return ResultUtils.success(loginUserVO);
}
}
server:
port: 8123
servlet:
context-path: /api
使用 IDEA 自带的 HttpClient
进行测试
###
POST http://localhost:8123/api/user/login
Content-Type: application/json
{
"userAccount": "leikooo",
"userPassword": "11111111"
}
解决:
直接问 AI 源码里面的核心逻辑在哪个地方,AI 说在 AbstractHandlerMapping#getHandlerExecutionChain
直接 debug
1、双击 shift 在上面输入 AbstractHandlerMapping
2、找到 getHandlerExecutionChain 方法
3、此时进行请求
发现 adaptedInterceptors 里面有我们自定义的 jwtInterceptor 的 patternString 证明 jwtInterceptor 注册成功
进去具体看看 match 逻辑
获取到的 path 是 /user/login 怪不得匹配不上 /api/** 难道是 context-path 不生效吗?
4、修改 controller 代码试试
@RestController
@RequestMapping("/api/user")
@AllArgsConstructor
public class UserController {
private UserService userService;
@PostMapping("/login")
public BaseResponse<LoginUserVO> userLogin(@RequestBody UserLoginRequest userLoginRequest, HttpServletRequest request) {
ThrowUtils.throwIf(userLoginRequest == null, ErrorCode.PARAMS_ERROR);
String userAccount = userLoginRequest.getUserAccount();
String userPassword = userLoginRequest.getUserPassword();
LoginUserVO loginUserVO = userService.userLogin(userAccount, userPassword, request);
return ResultUtils.success(loginUserVO);
}
}
把 application.yml 对应的配置 context-path 给去掉
6、继续 debug 看看
发现 这个 path 有 /api 此时我们直接放行到下一个断点
发现可以正常走到我们自定义 interceptor 的 preHandle
总结
因为 context-path 写的路径不会生效导致无法正常匹配路径,写 context-path:/api ,真正匹配的时候其实只有 /user/login 匹配不上咱们定义的 /api/**
解决把路径写到 controller 的 RequestMapping 中,不知道有没有大佬有其他的解决办法