该方案的实现场景是:现有一个tomcat分布式集群,由nginx来进行负载均衡,需要不同tomcat之间session共享。即用户登录请求经由nginx转发给了一个tomcat后,要求所有的tomcat都有该用户登录的token、session,下次请求转发到其他的tomcat时,仍然认为该用户是登陆状态。
为了解决这个session共享的问题,我使用了cookie来解决。用cookie来存储用户的sessionId,登陆后在服务器的redis缓存中也生成一个由sessionId、User对象组成的键值对,redis缓存每个tomcat均可以读取到。当下次再进行其他请求的时候,就会从cookie里读取出登录的信息和User对象,并且将sessionId和redis缓存中的进行比较,如果相同,就认为已经登录。
这里还要考虑session的有效期,一般是30 min。redis可以设置值的有效期,很好地解决了这个问题。可以在存入时将值的有效期设为30 min。
这是整个过程的流程图。
具体实现需要配置nginx,进行vitual host的配置。这里我的域名暂时还没有备案完成,就修改本地的host文件模拟一下。
在win10的hosts文件中添加:
127.0.0.1 www.mmall.com
将www.mmall.com
这个域名指向本地,用来测试。
首先是nginx的vhost里的文件。
upstream www.mmall.com{
server www.mmall.com:8080 weight=1;
server www.mmall.com:9080 weight=1;
}
server{
listen 80;
autoindex on;
server_name mmall.com www.mmall.com;
access_log g:access.log combined;
index index.html index.htm index.jsp index.php;
location / {
proxy_pass http://www.mmall.com;
add_header Access-Control-Allow-Origin *;
}
}
这里给两个tomcat分配了权重,使得访问本地的时候会负载均衡,请求会分发到不同的tomcat。
这里是Controller中的实现。这里面JsonUtil工具类中的obj2String(),作用是将某个对象转换为json字符串。RedisUtil也是封装的工具类。
/**
* 用户登录
* @param username
* @param password
* @param session
* @return
*/
@RequestMapping(value = "login.do", method = RequestMethod.POST)
@ResponseBody
public ServerResponse<User> login(String username, String password, HttpSession session, HttpServletResponse httpServletResponse){
ServerResponse<User> response = iUserService.login(username,password);
if( response.isSuccess() ){
//若登录成功
//向浏览器cookie写入sessionId
CookieUtil.writeLoginToken(httpServletResponse, session.getId