使用redis实现分布式会话
拦截流程
创建受限资源拦截器
@Component //标注一个类为Spring容器的Bean
public class CheckTokenInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate stringRedisTemplate;
//受限资源拦截器,访问的前提是已经登录,故在此处检查token
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String method = request.getMethod();
if("OPTIONS".equalsIgnoreCase(method)){
return true;
}
String token = request.getHeader("token");
if(token == null){
ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_NOT, "请先登录!", null);
doResponse(response,resultVO);
}else{
//若有token,则将此token与redis中的token进行对比查找
String s = stringRedisTemplate.boundValueOps(token).get();
if(s==null){
//此token未查找到,两种可能,1、没登录过 2、登录过期了
ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_NOT, "请先登录!", null);
doResponse(response,resultVO);
}else {
//在redis中找到了,那么重新调整一下此token的过期时间
stringRedisTemplate.boundValueOps(token).expire(30, TimeUnit.MINUTES);
return true;
}
}
return false;
}
private void doResponse(HttpServletResponse response,ResultVO resultVO) throws IOException {
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
String s = new ObjectMapper().writeValueAsString(resultVO);//将Java对象转为Json格式的数据,用于后端Servlet向AJAX传递Json数据
out.print(s);
out.flush();
out.close();
}
}
创建非受限资源拦截器
主要负责检测请求中是否含有token,若有token,且此token在redis中存在,则刷新此token的过期时间
//用于拦截非受限资源,若有token则重新设置过期时间
@Component
public class SetTimeInterceptor implements HandlerInterceptor {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String method = request.getMethod();
if("OPTIONS".equalsIgnoreCase(method)){
return true;
}
String token = request.getHeader("token");
if(token!=null){
String s = stringRedisTemplate.boundValueOps(token).get();
if(s!=null){
stringRedisTemplate.boundValueOps(token).expire(30, TimeUnit.MINUTES);
}
}
//此拦截器负责给token延长过期时间(有token且redis中找得到就延长,没有token就不延长),因此无论如何都是返回true
return true;
}
}
配置拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private CheckTokenInterceptor checkTokenInterceptor;
@Autowired
private SetTimeInterceptor setTimeInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截受限资源路径(访问条件:已登录)
registry.addInterceptor(checkTokenInterceptor)
.addPathPatterns("/shopcart/**")
.addPathPatterns("/orders/**")
.addPathPatterns("/useraddr/**")
.excludePathPatterns("/user/**");
//拦截所有资源路径(主要是为了拦截非限制资源)
registry.addInterceptor(setTimeInterceptor).addPathPatterns("/**");
}
}