Spring中的Interceptor拦截器中使用@Autowired注解,在运行时会出现空指针
问题描述
我们一般在拦截器中会写一些逻辑处理,比如获取用户的登录信息,将信息存入ThreadLocal等等。
而获取用户信息的时候就有多种方式了。
比如:在session中获取,或者使用token去redis中获取。
这个问题就是使用token去redis中获取用户信息的时候遇到的。因为在获取时需要使用@Autowired将StringRedisTemplate注入。此时运行就遇到了空指针错误。
原因分析
原因:因为拦截器在其配置类里是使用new创建的,而使用new创建的类就不归spring管理了,所以在里面使用@Autowired也将报错。
配置类代码如下:
1 @Configuration 2 public class WebMvcConfig implements WebMvcConfigurer { 3 @Override 4 public void addInterceptors(InterceptorRegistry registry) { 5 registry.addInterceptor(new CustomerInterceptor()).addPathPatterns("/customer/**"); 6 registry.addInterceptor(new ManageInterceptor()).addPathPatterns("/manage/**"); 7 8 } 9 }
解决方案:
方案一:
将拦截器类中添加@Component注解,然后在WebMvcConfigure类中使用@Autowird,将拦截器对象注入进来
代码如下:
1 @Component 2 public class CustomerInterceptor extends HandlerInterceptorAdapter { 3 @Autowired 4 private StringRedisTemplate stringRedisTemplate ; 5 @Override 6 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 7 String token = request.getHeader("accessToken"); 8 if (token == null){ 9 PrintWriter out = response.getWriter(); 10 out.print(JSON.toJSON(ResultUtil.error("请进行登录"))); 11 return false; 12 } 13 if (TokenUtils.verify(token)){ 14 JSONObject object = JSONObject.fromObject(stringRedisTemplate.opsForValue().get(token)); 15 16 CustomerVo msg = (CustomerVo)JSONObject.toBean(object, CustomerVo.class); 17 18 CustomerThreadLocal.set(msg); 19 if (msg!=null){ 20 return true; 21 } 22 } 23 return false; 24 } 25 26 @Override 27 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 28 29 } 30 31 @Override 32 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 33 34 } 35 }
1 @Configuration 2 public class WebMvcConfig implements WebMvcConfigurer { 3 @Autowired 4 CustomerInterceptor customerInterceptor; 5 @Autowired 6 ManageInterceptor manageInterceptor; 7 @Override 8 public void addInterceptors(InterceptorRegistry registry) { 9 registry.addInterceptor(customerInterceptor).addPathPatterns("/customer/**"); 10 registry.addInterceptor(manageInterceptor).addPathPatterns("/manage/**"); 11 12 } 13 }
方案二:
无需在拦截器类上添加@Component直接,直接在WebMvcConfigure类中添加经由@Bean注解的返回拦截器对象的方法。
代码:
1 @Configuration 2 public class WebMvcConfig implements WebMvcConfigurer { 3 4 @Bean 5 public CustomerInterceptor customerInterceptor(){ 6 return new CustomerInterceptor(); 7 } 8 @Bean 9 public ManageInterceptor manageInterceptor(){ 10 return new ManageInterceptor(); 11 } 12 @Override 13 public void addInterceptors(InterceptorRegistry registry) { 14 registry.addInterceptor(customerInterceptor()).addPathPatterns("/customer/**"); 15 registry.addInterceptor(manageInterceptor()).addPathPatterns("/manage/**"); 16 17 } 18 }