在项目中需要做到一个登录拦截功能,需要把用户信息和验证的信息放到redis中,最后发现在LoginInterceptor中注入redisTemplate一直无法注入进来,最后查资料发现springboot拦截器是在Bean实例化前之前执行的,所以导致Bean实例无法注入
- 发现问题
/**
* @program: fuxi
* @description
* @author: shenjiayu
* @create: 2020-03-26 19:11
**/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object object) throws Exception {
String token = request.getHeader("token");// 从 http 请求头中取出 token
// 如果不是映射到方法直接通过
if(!(object instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod=(HandlerMethod)object;
Method method=handlerMethod.getMethod();
//检查是否有passtoken注释,有则跳过认证
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.required()) {
return true;
}
}
//认证
JSONObject respJson = new JSONObject();
if (token!=null){
String userInfo = stringRedisTemplate.opsForValue().get(Constant.REDIS_PREFIX+token);
String PCuserInfo = stringRedisTemplate.opsForValue().get(Constant.REDIS_PREFIX+"PC:"+token);
if (StringUtils.isNotBlank(userInfo)||StringUtils.isNotBlank(PCuserInfo)){
return true;
}else{
respJson.put("loginStatus","-1");
respJson.put("loginMsg","登录过期,请重新登录!");
}
}else{
respJson.put("loginStatus","-1");
respJson.put("loginMsg","无Token,请重新登录!");
}
response.setContentType("application/json; charset=utf-8");
PrintWriter writer = response.getWriter();
BaseResp baseResp = new BaseResp(ReturnCodeEnum.SUCCESS.getCode(),respJson,ReturnCodeEnum.SUCCESS.getMsg());
writer.print(JSONObject.toJSONString(baseResp));
writer.close();
response.flushBuffer();
return false;
}
}
配置拦截器,配置config类拦截相应url
/**
* @program: fuxi
* @description
* @author: shenjiayu
* @create: 2020-03-26 18:53
**/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
// 设置跨域访问
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "TRACE")
.allowCredentials(true);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/weekly/*","/code/*","/file/sys/*","/checkpreload.htm","/index.html");
}
}
在调用被拦截的接口过程中发现控制台报空指针错误,断点发现每次进来的redisTemplate都是null。
- 解决问题:
确认拦截器的执行是在Bean实例化之前,所以需要在拦截器执行时实例化拦截器Bean,改造拦截器配置类,先实例化拦截器然后再获取,修改配置类
/**
* @program: fuxi
* @description
* @author: shenjiayu
* @create: 2020-03-26 18:53
**/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public LoginInterceptor getLoginInterceptor(){
return new LoginInterceptor();
}
// 设置跨域访问
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "TRACE")
.allowCredentials(true);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getLoginInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/weekly/*","/code/*","/file/sys/*","/checkpreload.htm","/index.html");
}
}
再进行访问就可以正常访问到,redisTemplate正常注入。