我们项目中经常会用到拦截器来做Controller层处理前后的操作,把自己项目中的一个拦截器拿出来做一个学习笔记。
该拦截器功能
在请求到达Controller层之前,我们要做token的校验来确认客户端的身份,token保存在redis里面,下面就是基本代码。
拦截器代码
//该注解标明是一个配置类,同时把该类注入到Spring容器中
@Configuration
//自己定义的拦截器要实现HandlerInterceptor接口
public class SNDInterceptor implements HandlerInterceptor {
private SecurityService securityService;
//使用构造方法注入的方式注入,当只有一个构造器时,@Autowired注解可以省略
public SNDInterceptor(SecurityService securityService){
this.securityService = securityService;
}
/**
* 日志对象
*/
private static final Logger LOGGER = LoggerFactory.getLogger(SNDInterceptor.class);
//controller执行之前执行,如果返回值是true则代表方形,返回false则代表拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
try {
//判断是否是映射到方法上,如果不是直接放行
if(!(handler instanceof HandlerMethod)){
return true;
}
//获取存储在redis中的Session字符串,并且在security中检查我们处理请求时出现的异常,比如
//securityService.auth(request)方法就是判断token是否存在,是否过期以及设置新的token到期时间等
String session = securityService.auth(request);
//返回不为空,就把session到设置响应头中并放行
if (null != session) {
response.setHeader("X-Auth-User", URLEncoder.encode(session, "utf8"));
}
return true;
} catch (UnAuthorizedException e) {
//这里面设置处理异常
response.setStatus(HttpStatus.OK.value());
this.returnJson(response,JSONUtil.toJsonStr(SNDApiResponse.error( e.getMessage())));
return false;
} catch (Exception e) {
LOGGER.error("Do auth failed...", e);
response.setStatus(HttpStatus.OK.value());
this.returnJson(response,JSONUtil.toJsonStr(SNDApiResponse.error( e.getMessage())));
return false;
}
}
//执行完controller执行之后、视图渲染前调用,可以在该方法里获取或者修改model
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
//一般用于清理资源
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
private void returnJson(HttpServletResponse response, String json) throws Exception{
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
try {
writer = response.getWriter();
writer.print(json);
} catch (IOException e) {
LOGGER.error("response error",e);
} finally {
if (writer != null){
writer.close();
}
}
}
}
配置好自己的拦截器之后,要把他进行配置之后才能生效,所以我们要新建一个配置类,把拦截器配置进来并设置相关配置
@Configuration
public class SNDWebMvcConfigurer implements WebMvcConfigurer {
@Autowired
private SecurityService securityService;
//获取拦截器对象
public SNDInterceptor setBean(){
return new SNDInterceptor(securityService);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//把我们的拦截器配置进来
registry.addInterceptor(setBean())
//该方法用于添加拦截路径,这里的/**代表拦截所有对象
.addPathPatterns("/**")
//添加放行的访问路径
.excludePathPatterns("/login","/auth","/user/online","/user/detail",
"/swagger-resources/**","/doc.html","/webjars/**","/sendsms","/user/detailByUserNo","/city/check","/province/detailByName");
}
//这个方法用于设置解决跨域
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET","POST","PUT","OPTIONS","DELETE","PATCH")
.allowedHeaders("token")
.allowCredentials(true)
.maxAge(3600);
}
}
总结:
1、自己先创建一个拦截器,并把它交给spring管理,且要实现HandlerInterceptor接口,并重写里面的三大方法preHandler/postHandle/afterCompletion,其中,preHandler是常用方法,仅方法具有返回值,返回ture代表放行,返回false表示拦截。
2、讲拦截器注入到我们的配置类中,该配置类要实现WebMvcConfigurer 这个接口,重写addInterceptor方法,把我们的拦截器注入进来,并配置拦截和放行的接口即可使用。