Interceptor 拦截器
概念
Interceptor(拦截器)是一种面向对象编程(OOP)和软件开发中广泛使用的设计模式,特别是基于请求-响应的应用程序中,如Web应用、RestfulAPI等。
主要用途:
- 日志记录:在请求到达控制器之前或响应发送给客户端之后记录请求和响应的详细信息。
- 权限检查:在请求被处理之前验证用户是否具有执行该操作的权限。
- 事务管理:管理数据库事务的开始、提交或回滚,确保数据一致性。
- 性能监控:测量请求处理时间,监控应用程序性能。
- 请求预处理:修改请求参数或执行其他前置处理。
- 响应后处理:修改响应内容或执行其他后置处理。
使用方法
首先创建一个拦截器类,并且实现HanderInterceptor接口:
这里我们要知道HandlerInterceptor
接口中定义了三个方法,这些方法分别在请求处理的不同阶段被调用:
- preHandle : 此方法在请求处理之前调用(Controller方法调用之前)。它返回一个布尔值,
true
表示继续流程(如调用下一个Interceptor或处理器),false
表示流程中断(不会继续调用其他的Interceptor或处理器),此时需要通过response来直接写入响应。 - postHandle : 此方法在请求处理之后调用,但在视图被渲染之前(Controller方法调用之后)。它允许你修改Controller处理后的ModelAndView对象,但此时请求已经处理完毕,不能改变响应的状态码或头部信息。
- afterCompletion : 此方法在整个请求结束之后被调用,也就是在
DispatcherServlet
渲染了对应的视图执行之后。这个方法可以用来进行资源清理工作。与postHandle
方法不同的是,此时已经离开了DispatcherServlet
的请求处理流程,可以修改响应的状态码或头部信息,但无法修改ModelAndView对象。
代码如下:
public class MyInterceptor implement HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return HandlerInterceptor.super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
然后我们根据自己的需要修改对应的方法的内容
最后我们需要在WebMvcConfig
配置类中添加这个拦截器
在实现接口中,有一个addInterceptors
方法
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//分别设置添加的拦截器,拦截的请求路径,忽略的请求路径
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("css/*.css");
//下面可以配置多个,只需要在后面继续add
}
}
实际应用案例
JWT校验:
package com.angelday.store.interceptor;
import com.angelday.constant.JwtClaimsConstant;
import com.angelday.context.BaseContext;
import com.angelday.properties.JwtProperties;
import com.angelday.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* jwt令牌校验的拦截器
*/
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {
@Autowired
private JwtProperties jwtProperties;
/**
* 校验jwt
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断当前拦截到的是Controller的方法还是其他资源
if (!(handler instanceof HandlerMethod)) {
//当前拦截到的不是动态方法,直接放行
return true;
}
//1、从请求头中获取令牌
String token = request.getHeader(jwtProperties.getAdminTokenName());
//2、校验令牌
try {
log.info("jwt校验:{}", token);
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
Long empId = Long.valueOf(claims.get(JwtClaimsConstant.STF_ID).toString());
log.info("当前员工id:", empId);
BaseContext.setCurrentId(empId);
//3、通过,放行
return true;
} catch (Exception ex) {
//4、不通过,响应401状态码
response.setStatus(401);
return false;
}
}
}
优点
- 解耦:拦截器允许在不修改原有业务逻辑代码的情况下增加新功能。
- 灵活性:可以根据需要轻松地添加、删除或重新排序拦截器。
- 重用性:拦截器可以被多个请求或控制器共享。
总之,Interceptor是一种强大的设计模式,用于在请求处理流程中插入自定义行为,从而在不修改业务逻辑代码的情况下扩展应用程序的功能。