拦截器无法注入redisTemplate

1,986 阅读2分钟

在项目中需要做到一个登录拦截功能,需要把用户信息和验证的信息放到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正常注入。