背景
最近学习了redis相关的一些知识,想着如何写一个小项目运用一下所学知识,偶然的一个机会想到了session。
传统的session是存储在每个项目所在服务器的本地的,这样会面临俩个问题:1.当同一个项目搭建了集群时候,多台机器的session无法共享。2.session数量太多时候影响服务器性能,影响项目正常运行。
这时候redis就派上用场了,只要所有服务都将session存储到一个redis服务器中,设置session自动过期时间,就可以很好的解决这些问题了。
我在这里写了一个基于redis的session验证系统,他会在你访问服务时验证你是否登陆。
基本思路
其实思路很简单,就是写一个传统的filter或者springmvc中的Interceptor(拦截器),当收到请求时经过这个拦截器,它会查询redis是否有相应的session,如果有则放行,如果没有则拒绝访问。
redis中有五种数据类型,但是我这里为了演示的简单起见就用了最基础的String类型。
默认cookie为:peerless=xxx
默认redis中的k-v对是:peerless.xxx - session的存储时间
代码实现
1.编写interceptor
package edu.hnu.tomato.peerlessacquaintance.interceptor;
import java.io.PrintWriter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import edu.hnu.tomato.peerlessacquaintance.pojo.ReturnData;
public class AcquaintanceInterceptor implements HandlerInterceptor {
private static final String cookieName="peerless";
//注入redis操作string的对象
@Autowired
private StringRedisTemplate redisTemplate;
public AcquaintanceInterceptor(){}
//构造器,用于传入你想自定义的cookiname
public AcquaintanceInterceptor(String cookieName){
this.cookieName=cookieName;
}
//拦截器的的拦截方法
@Override
public boolean preHandle(final HttpServletRequest request,
final HttpServletResponse response, final Object handler) throws Exception {
//获取这次请求的所有cookie
Cookie[] cookies=request.getCookies();
//遍历找到制定cookie
for (Cookie cookie : cookies) {
if (cookie.getName().equals(this.cookieName)) {
//redis查找对于cookie
//如果查到了则放行
String cookieMessage=redisTemplate.opsForValue().get(cookieName+"."+cookie.getValue());
if (cookieMessage==null) {
break;
}
return true;
}
}
//如果没有查到则拒绝请求
response.setContentType("text/xml;charset=utf-8");
//返回401 拒绝请求
response.setStatus(401);
PrintWriter pw = response.getWriter();
pw.write(“用户没有登陆”);
return false;
}
@Override
public void postHandle(final HttpServletRequest request,
final HttpServletResponse response, final Object handler,
final ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(final HttpServletRequest request,
final HttpServletResponse response, final Object handler, final Exception ex)
throws Exception {
}
}
2.注册interceptor
package edu.hnu.tomato.peerlessacquaintance.config;
import edu.hnu.tomato.peerlessacquaintance.interceptor.AcquaintanceInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
//这里注册一定要是容器里的那个interceotor 而不是自己new一个放进去
@Autowired
public AcquaintanceInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//添加拦截器
registry.addInterceptor(interceptor)
//添加需要拦截的路径
.addPathPatterns("/**/*");
}
}
完成这俩步,编写controller以后就可以测试看效果了,注意我这里默认的redis中的key是peerless.xxx value是存储这个session的时间。
总结
以上内容提供了利用redis存储session的基本思路,希望可以起到一个抛砖引玉的作用,大家可以在这个基础上自己进行发挥,比如把它写成一个starter,每个项目只需要引入依赖就可以自动配置等等,这里就不做具体的展开了