最近在做微服务间用户权限打通的时候,由于当初设计的问题,用户的信息没有存在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容器管理,因此拦截器中的属性注入自然就不会发生问题了。