场景:比如说我们要实现一个集群环境,无非是把多个项目部署到多个tomcat下,然后按照一定的算法,轮询什么的随机访问多个tomcat服务器,但是问题也会有许多,比如说,我们最开始是把登陆人的信息存放到session中,但是如果是集群的情况下,比如我第一次登陆,把信息存放到session里面,但是我第二次访问的时候,访问到了第二台服务器,第二台服务器里面没有session信息,我们还得再登陆一遍,问题显而易见,session数据共享的问题。

解决思路:我们不要把信息存放到服务器的session中,要存放到一个公共的容器中,这个容器我们采用redis,然后我们每次取用户信息都去redis里面取,这不就解决了。问题又出现了,我们知道redis是key,value的数据结构,value是json格式化的用户对象信息,key呢?key当然要不一样了,因为许多登陆用户的的信息都会存在redis里面。别忘了,每个session都会有一个sessionId,这个sessionId是服务器给我们自动生成的。最开始我们都是用的这个,而且cookie每次访问服务器也会携带这个sessionId,这不是解决了?我们用sessionId来当key,User来当value,然后把这个sessionId写到本地的cookie中,每次访问服务器都从本地的cookie中取得这个sessionId,然后有了key,不就得到value了么。

需要注意的是,既然是单点登陆,顾名思义就是我登陆了这个一级域名下的服务器,然后再登陆它下面的二级域名,三级域名都不需要登陆,那这个cookie存的时候也需要讲究一下,需要把这个cooike存放到顶级域名下,他下面的子域名也就能得到这个cookie了。比如说两个域名

a.lzh.com和b.lzh.com  要实现单点登陆,就要把cookie存放到  .lzh.com  下(注意前面的点),ok。思路有了。看代码吧!!!

代码中有许多工具类,估计提供的不全,不过如果你看懂了我上面说的,你也应该知道大概具体啥意思。因为如果把每个包含的代码都贴出来,真的是好多啊。重点是理解。我其他博客也有相关的工具类。自己找找嘛。

补充:还有每次访问服务器都要把reidis的时间重新设置半小时。这个利用过滤器来实现。很简单。

CookieUtil.java

package com.mmall.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

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

/**
 * Created by 敲代码的卡卡罗特
 */
@Slf4j
public class CookieUtil {

private final static String COOKIE_DOMAIN = ".happymmall.com";   //顶级域名
    private final static String COOKIE_NAME = "mmall_login_token";   //存放在本地cookie的key

//根据request从cookie中读取token
    public static String readLoginToken(HttpServletRequest request){
        Cookie[] cks = request.getCookies();
        if(cks != null){
            for(Cookie ck : cks){
                log.info("read cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
                if(StringUtils.equals(ck.getName(),COOKIE_NAME)){
                    log.info("return cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
                    return ck.getValue();
                }
            }
        }
        return null;
    }

//X:domain=".happymmall.com"
    //a:A.happymmall.com            cookie:domain=A.happymmall.com;path="/"
    //b:B.happymmall.com            cookie:domain=B.happymmall.com;path="/"
    //c:A.happymmall.com/test/cc    cookie:domain=A.happymmall.com;path="/test/cc"
    //d:A.happymmall.com/test/dd    cookie:domain=A.happymmall.com;path="/test/dd"
    //e:A.happymmall.com/test       cookie:domain=A.happymmall.com;path="/test"
    
    
    //写入cookie
    public static void writeLoginToken(HttpServletResponse response,String token){
        Cookie ck = new Cookie(COOKIE_NAME,token);
        ck.setDomain(COOKIE_DOMAIN);
        ck.setPath("/");//代表设置在根目录
        ck.setHttpOnly(true);
        //单位是秒。
        //如果这个maxage不设置的话,cookie就不会写入硬盘,而是写在内存。只在当前页面有效。
        ck.setMaxAge(60 * 60 * 24 * 365);//如果是-1,代表永久
        log.info("write cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
        response.addCookie(ck);
    }

//删除cookie
    public static void delLoginToken(HttpServletRequest request,HttpServletResponse response){
        Cookie[] cks = request.getCookies();
        if(cks != null){
            for(Cookie ck : cks){
                if(StringUtils.equals(ck.getName(),COOKIE_NAME)){
                    ck.setDomain(COOKIE_DOMAIN);
                    ck.setPath("/");
                    ck.setMaxAge(0);//设置成0,代表删除此cookie。
                    log.info("del cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
                    response.addCookie(ck);
                    return;
                }
            }
        }
    }

}

UserController.java (用户登陆。退出方法)

/**
     * 用户登录
     * @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()){

//            session.setAttribute(Const.CURRENT_USER,response.getData());
            CookieUtil.writeLoginToken(httpServletResponse,session.getId());
            RedisShardedPoolUtil.setEx(session.getId(), JsonUtil.obj2String(response.getData()),Const.RedisCacheExtime.REDIS_SESSION_EXTIME);

}
        return response;
    }
    
    
     @RequestMapping(value = "logout.do",method = RequestMethod.GET)
    @ResponseBody
    public ServerResponse<String> logout(HttpSession session,HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse){
        String loginToken = CookieUtil.readLoginToken(httpServletRequest);
        CookieUtil.delLoginToken(httpServletRequest,httpServletResponse);
        RedisShardedPoolUtil.del(loginToken);

//        session.removeAttribute(Const.CURRENT_USER);

return ServerResponse.createBySuccess();
    }

SessionExpireFilter.java  (过滤器,每次访问服务器把redis的时间重置30分钟)

package com.mmall.controller.common;

import com.mmall.common.Const;
import com.mmall.pojo.User;
import com.mmall.util.CookieUtil;
import com.mmall.util.JsonUtil;
import com.mmall.util.RedisShardedPoolUtil;
import org.apache.commons.lang.StringUtils;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * Created by 敲代码的卡卡罗特
 */
public class SessionExpireFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;

String loginToken = CookieUtil.readLoginToken(httpServletRequest);

if(StringUtils.isNotEmpty(loginToken)){
            //判断logintoken是否为空或者"";
            //如果不为空的话,符合条件,继续拿user信息

String userJsonStr = RedisShardedPoolUtil.get(loginToken);
            User user = JsonUtil.string2Obj(userJsonStr,User.class);
            if(user != null){
                //如果user不为空,则重置session的时间,即调用expire命令
                RedisShardedPoolUtil.expire(loginToken, Const.RedisCacheExtime.REDIS_SESSION_EXTIME);
            }
        }
        filterChain.doFilter(servletRequest,servletResponse);
    }

@Override
    public void destroy() {

}
}

在tomcat集群下利用redis实现单点登陆相关推荐

  1. 解决apachenbsp;tomcat集群中sess…

    在部署的tomcat集群下的web工程项目的web.xml中添加<distributable/> 可以使用distributable元素来告诉servlet/JSP容器,编写的应用将在分布 ...

  2. nginx集群_windows环境下搭建简单Nginx+Tomcat集群

    通俗点将,负载均衡就是因为访问流量太大,导致项目访问不流畅.甚至宕掉,所以通过一种分流的方式来缓解这种情况. 一. 工具 nginx-1.8.0 apache-tomcat-6.0.33 二. 目标 ...

  3. 用Redis存储Tomcat集群的Session

    用Redis存储Tomcat集群的Session 作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs 前段时间,我花了不少时间来寻求一种方法,把新开发的代码推 ...

  4. windows下tomcat集群配置(两种方法)

    两种方法只是在配置上不同原理一样,因为apache2.X后其自身集成了mod_jk功能,相对于1.3版本,不需要再进行繁琐的worker.properties配置,配置过程大幅简化. 一.软件需求 操 ...

  5. Tomcat集群通过redis实现session共享

    Tomcat集群通过redis实现session共享 最近在XXX项目上做了tomcat集群的session共享,闲来无事鄙人将整个踩坑的过程粗糙的记录下来,给同学们分享一波,整个过程无硬编码,爽歪歪 ...

  6. Demo_mmall v2.0 (四) Tomcat集群演进及使用Redis进行session重构实现单点登录

    小谈mmall架构演进 上回书和上上回书说到redis的用法还有在代码里怎么操作Redis数据库,学完了得用啊.怎么用啊?这得从项目架构说起了. mmall是一个简单的用SSM搭建起来的基本只能本地玩 ...

  7. linux下使用nginx搭建集群,CentOS(linux) 下Nginx的安装(Nginx+Tomcat集群第一步)

    CentOS(linux) 下Nginx的安装(Nginx+Tomcat集群) CentOS 7.4(腾讯云) pcre库 zlib库 openssl Nginx服务器 安装gcc g++开发类库 y ...

  8. linux环境下通过nginx实现tomcat集群

    2019独角兽企业重金招聘Python工程师标准>>> linux环境下通过nginx实现tomcat集群 安装nginx之前需要pcre依赖和jvm-remote补丁 一.准备如下 ...

  9. Windows下搭建Tomcat集群的配置详解

    < Windows下搭建Tomcat集群基础入门详解 > 前言 在搭建 < Apache + Tomcat 实现Web服务器集群 > 前我们还需要实现 Tomcat集群实现Se ...

最新文章

  1. 2015.07.20MapReducer源码解析(笔记)
  2. 浅谈错排公式的推导及应用
  3. Leetcode No.145 **
  4. ABAP和XML数据格式互相转换的两种方式
  5. videowriter最小的编码格式_cv2.VideoWriter() 指定写入视频帧编码格式
  6. 求一个连通图的割点(去掉一个点后图不再连通)
  7. 常见的垃圾回收器算法有哪些,各有什么优劣?
  8. CUDA C编程权威指南 第四章 全局内存
  9. 基数排序(稍微困难)
  10. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_07 缓冲流_6_BufferedReader_字符缓冲输入流...
  11. 洛谷——P2026 求一次函数解析式
  12. arcgis使用教程和视频教程
  13. Java画十字_用Java绘制对角线
  14. oracle logged on,ORA-01012:not logged on的解决办法
  15. 《Visual Basic.Net 循序渐进》
  16. Kafka 概念、单机搭建与使用
  17. [wirteup] unctf-web-can_you_hacked_me
  18. iphone光感测试软件,苹果iPhone12增加人物检测辅助功能,利用激光雷达帮盲人群体...
  19. 802.11--802.11a协议
  20. 关于create-react-app搭建react环境并修改端口号

热门文章

  1. 基于Python的多元线性回归分析
  2. MIT-BIH心律失常数据库目录(译)
  3. 小熊的人生回忆(四)
  4. TeamViewer远程连接群辉
  5. IC卡、ID卡、M1卡、射频卡的区别是什么(射频卡是种通信技术)
  6. 机器视觉光源概述(选型参考)
  7. 网络推广主要工作是做什么的 有哪些?
  8. 3_使用seurat sct方法中的reference based处理大数据超过100000个细胞 science advance
  9. java时区问题_Java时区问题
  10. 设计模式之创建型——工厂模式(3种)