最近在做微服务间用户权限打通的时候,由于当初设计的问题,用户的信息没有存在Redis中,而是由请求头携带的,因此需要在用户首次访问的时候缓存用户信息到Redis中,但是redisTemplate却无法注入到拦截其中,核心代码如下所示:
SessionInterceptor.java


package cn.lz.conf.auth;

import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import cn.hutool.json.JSONUtil;
import cn.lz.dh.common.utils.effi.PipelineUtil;
import cn.lz.dh.feign.dragon.dto.User;


/**
 * 
* Copyright: Copyright (c) 2019 Jun_Zhou
* 
* @ClassName: SessionInterceptor.java
* @Description: Session拦截器,当用户首次访问的时候,
* 				根据用户名或者Id查询用户详情并缓存于Redis中[k(用户Id)->V(用户详情)];
* 
* @version: v1.0.0
* @author: JunZhou
* @Email: 1769676159@qq.com
* @Site: CERNO
* @date: 2019年5月14日 上午10:25:38
 */
public class SessionInterceptor implements HandlerInterceptor
{
	@Autowired
	RedisTemplate<String, String>	redisTemplate;
	
	//设置默认的额过期时间为15分钟;
	private Long					timeout				= (long) (15 * 60);
	
	//缓存空间名称;
	private static final String		CACHE_NAME_SPACE	= "efffi:user:";
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception
	{
		//当前服务不存在登陆请求,因此不用考虑登陆请求造成的死循环问题;
		String userId = request.getHeader("userid");
		String userName = request.getHeader("userName");
		Boolean hadCachedCurrentUserInfo = hadCachedCurrentUserInfo(userName, userId);
		if (!hadCachedCurrentUserInfo)
		{
			//当没有缓存当前用户详情的时候调用第三方服务查询用户详情;
			User userDetail = PipelineUtil.parseUserInfoFromResEntity(userId);
			ValueOperations<String, String> opsForValue = getValueOperations();
			if (userDetail != null)
			{
				String jsonPrettyStr = JSONUtil.toJsonPrettyStr(userDetail);
				//缓存用户信息到redis中;
				opsForValue.set(CACHE_NAME_SPACE + userId, jsonPrettyStr, timeout, TimeUnit.SECONDS);
			}
		}
		return true;
	}
	
	/**
	 * 该方法将在Controller执行之后,返回视图之前执行,modelAndView表示请求Controller处理之后返回的Model和View对象,所以可以在
	 * 这个方法中修改modelAndView的属性,从而达到改变返回的模型和视图的效果。
	 */
	@Override
	public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception
	{}
	
	@Override
	public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception
	{}
	
	/**
	 *  判断当前用户信息是否被缓存,用于加快访问效率;
	 * @param userName:用户名;
	 * @param userid : 用户Id;
	 * @return:用户信息是否被缓存的标志【true/false】;
	 */
	public Boolean hadCachedCurrentUserInfo(String userName, String userid)
	{
		Boolean hadCachedCurrentUserInfo = true;
		//从Redis中获取指定key的值;
		ValueOperations<String, String> opsForValue = getValueOperations();
		Object object = opsForValue.get(CACHE_NAME_SPACE + userid);
		//根据请求头信息中的用户信息判断session中是否存在有效的用户信息;
		if (null == object)
		{
			hadCachedCurrentUserInfo = false;
		}
		return hadCachedCurrentUserInfo;
	}
	
	/**
	 * 获取redis中的对象操作句柄;
	 * @return
	 */
	public ValueOperations<String, String> getValueOperations()
	{
		ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
		return opsForValue;
	}
}

SessionConfiguration.java


package cn.lz.conf.auth;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;


/**
 * 
* Copyright: Copyright (c) 2019 Jun_Zhou
* 
* @ClassName: SessionConfiguration.java
* @Description: 用户信息Redis缓存相关的配置类;
* 
* @version: v1.0.0
* @author: JunZhou
* @Email: 1769676159@qq.com
* @Site: CERNO
* @date: 2019年5月14日 下午12:38:53
*/
@Configuration
public class SessionConfiguration extends WebMvcConfigurerAdapter
{
  【-->
		@Bean
		public SessionInterceptor getSessionInterceptor()
		{
			return new SessionInterceptor();
		}
	<--】
	@Override
	public void addInterceptors(InterceptorRegistry registry)
	{
		registry.addInterceptor(getSessionInterceptor()).addPathPatterns("/**");
	}
}

最终调试发现,由于拦截器加载的时间点在springcontext之前,所以在拦截器中注入自然为null 。
因此解决方法在配置拦截器链的类中先注入这个拦截器,代码如下:

【-->
		@Bean
		public SessionInterceptor getSessionInterceptor()
		{
			return new SessionInterceptor();
		}
	<--】

这样,就相当于将当前拦截器交给了Spring的IOC容器管理,因此拦截器中的属性注入自然就不会发生问题了。

参考文章:
记录解决一个springboot拦截器无法注入redisTemplate操作工具类问题
Spring boot整合redis过程中,发现自定义的拦截器注入不了redis接口service。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐