session共享解决办法 --------------- 商城session共享redis解决

1、为什么要session共享

分布式开发项目中,用户通过浏览器登录商城,实际上会被转发到不同的服务器,当用户登录进入服务器A,session保存了用户的信息,用户再次点击页面被转发到服务器B,这时问题来了,服务器B没有该用户的session信息,无法验证通过,用户被踢回到登录页面,这样体验效果非常不好,甚至无法验证用户,购物车里面商品都不存在了。

2、利用redis解决方案

 

session共享解决办法 --------------- 商城session共享redis解决_ide_02

用户第一次进入商城首页,给一个CSESSIONID,(不用JSESSIONID的原因),用户添加商品,各种需要记录的操作,都与这个CSESSIONID关联起来;

当使用登录操作时候,将这个用户的信息,如用户名等存入到redis中,通过K_V,将CSESSIONID加一个标志作为key,将用户信息作为value;

当用户点击页面被转发到其他服务器时候,在需要验证是否同一个用户时,就可以从redis中取出value,进行验证用户信息,实现共享。

 

3、具体案例及实现java代码

    1、用户登录时候将csessionid存到redis
  1.  
    @RequestMapping(value="/login.aspx",method=RequestMethod.POST)
  2.  
    public String login(String username, String password, String returnUrl, Model model
  3.  
    , HttpServletRequest request, HttpServletResponse response) {
  4.  
    // 判断用户名不能为空
  5.  
    if (StringUtils.isNotBlank(username)) {
  6.  
    // 判断密码不为空
  7.  
    if (StringUtils.isNotBlank(password)) {
  8.  
    // 用户名必须正确nu
  9.  
    Buyer buyer = buyerService.selectBuyerByusername(username);
  10.  
    if (null !=buyer) {
  11.  
    // 密码必须正确
  12.  
    if (encodePassword(password).equals(buyer.getPassword())) {
  13.  
    // 保存用户名到session中 保存用户名到redis key == jsessionid
  14.  
    //注意不能用jsessionid,他被request操作,用csession
  15.  
    String csessionid = RequestUtils.getCSESSIONID(request, response);
  16.  
    sessionProvider.setAttribute(csessionid, buyer.getUsername());
  17.  
    // 回跳到之前的访问页面
  18.  
    return "redirect:" + returnUrl;
  19.  
    }else {
  20.  
    model.addAttribute("error", "密码必须正确");
  21.  
    }
  22.  
    }else {
  23.  
    model.addAttribute("error", "用户名必须正确");
  24.  
    }
  25.  
    } else {
  26.  
    model.addAttribute("error", "密码不能为空");
  27.  
    }
  28.  
    }else {
  29.  
    model.addAttribute("error", "用户名不能为空");
  30.  
    }
  31.  
    return"login";
  32.  
    }
 
  1.  
    /**
  2.  
    * 获取请求中的csessionid,如果有直接使用,
  3.  
    * 没有的话创建一个csessionid,并保存到response,添加到浏览器
  4.  
    * @param request
  5.  
    * @param response 用于最后将cookie存到浏览器,所以需要response
  6.  
    * @return
  7.  
    */
  8.  
    public static String getCSESSIONID(HttpServletRequest request,HttpServletResponse response) {
  9.  
    // 1、获取Cookies (里面有jsession 购物车。。。)
  10.  
    Cookie[] cookies = request.getCookies();
  11.  
    if (null !=cookies && cookies.length>0) {
  12.  
    for (Cookie cookie : cookies) {
  13.  
    // 2、从 Cookie中获取CSESSIONID
  14.  
    if (cookie.getName().equals("CSESSIONID")) {
  15.  
    // 3、如果有 直接使用
  16.  
    return cookie.getValue();
  17.  
    }
  18.  
    }
  19.  
    }
  20.  
    // 4、判断如果没有,创建一个CSESSIONID 保存CESSIONID到cookie,保存Cookie写回浏览器
  21.  
    String csessionid = UUID.randomUUID().toString().replaceAll("-", "");
  22.  
    Cookie cookie = new Cookie("CSESSIONID", csessionid);
  23.  
    //设置路径
  24.  
    cookie.setPath("/");
  25.  
    //设置Cookie的存活时间 立即销毁0 关闭浏览器销毁-1 到时间了再消失>0 前提:没有清理Cookie
  26.  
    cookie.setMaxAge(-1);
  27.  
    response.addCookie(cookie);
  28.  
    return csessionid;
  29.  
    }
 
    2、写一个SessionProviderImpl类,将CSESSIONID信息存入redis
    
  1.  
    /**
  2.  
    * 远程Session 保存到Redis中
  3.  
    * @author Administrator
  4.  
    *
  5.  
    */
  6.  
    //@Service("sessionProvider") 实现类的实例化交给spring管理,可以设置存活时间session.xml
  7.  
    public class SessionProviderImpl implements SessionProvider{
  8.  
     
  9.  
    @Autowired
  10.  
    private Jedis jedis;
  11.  
     
  12.  
    /**
  13.  
    * 保存用户到session
  14.  
    */
  15.  
    @Override
  16.  
    public void setAttribute(String key, String value) {
  17.  
    // 保存用户名到redis key == jsessionid
  18.  
    //保存
  19.  
    jedis.set(key + ":" + Constants.BUYER_SESSION, value);
  20.  
    // 时间30分钟
  21.  
    jedis.expire(key + ":" + Constants.BUYER_SESSION, Constants.SESSION_TIME);
  22.  
     
  23.  
    }
  24.  
     
  25.  
    /**
  26.  
    * 获取用户名
  27.  
    */
  28.  
    @Override
  29.  
    public String getAttribute(String key) {
  30.  
    String username = jedis.get(key + ":" + Constants.BUYER_SESSION);
  31.  
    if (null !=username) {
  32.  
    //不等于null,再设置一次session存活时间,保证session生存时间从最后一次登录计算
  33.  
    jedis.expire(key + ":" + Constants.BUYER_SESSION, Constants.SESSION_TIME);
  34.  
    return username;
  35.  
    }
  36.  
    return null;
  37.  
    }
  38.  
     
  39.  
    // 保存验证码到session
  40.  
    // 获取验证码
  41.  
     
  42.  
    /**
  43.  
    * 退出登录 让redis中session消失
  44.  
    * @param key
  45.  
    */
  46.  
    public void logout(String key) {
  47.  
    jedis.del(key + ":" + Constants.BUYER_SESSION);
  48.  
    }
  49.  
     
  50.  
    }
 
不通过注解方式注入,写配置文件session.xml
  1.  
    <!--session的实例化,不通过注解@service("sessionProvider")实现,改为交给spring管理 -->
  2.  
    <beanid="sessionProvider"class="cn.dapeng.core.service.user.SessionProviderImpl">
  3.  
    <!-- <property name="exp" value="1800"/> -->
  4.  
    </bean>
 

    3、验证用户只需要通过CSESSIONID去查询用户的信息,比如验证登录,验证购物车。。
  1.  
    /**
  2.  
    * 判断是否登录,返回登录标志0,未登录;1,已登录
  3.  
    * @param request
  4.  
    * @param response
  5.  
    */
  6.  
    @RequestMapping(value="/isLogin.aspx")
  7.  
    @ResponseBody
  8.  
    public MappingJacksonValue isLogin(String callback, HttpServletRequest request , HttpServletResponse response) {
  9.  
    Integer result = 0; //默认0,未登录
  10.  
    String username = sessionProvider.getAttribute(RequestUtils.getCSESSIONID(request, response));
  11.  
    if (null !=username) {
  12.  
    result = 1;
  13.  
    }
  14.  
    /*// json 的返回方法,但是受到跨域问题,因此改为jsonp
  15.  
    response.setContentType("application/json;charset=UTF-8");
  16.  
    try {
  17.  
    response.getWriter().write(result);
  18.  
    } catch (IOException e) {
  19.  
    // TODO Auto-generated catch block
  20.  
    e.printStackTrace();
  21.  
    }*/
  22.  
    //返回jsonp,callback里接收ajax传过来的MappingJacksonValue
  23.  
    MappingJacksonValue mjv = new MappingJacksonValue(result);
  24.  
    mjv.setJsonpFunction(callback);
  25.  
    return mjv;
  26.  
    }
 
*存入redis的数据结构
session共享解决办法 --------------- 商城session共享redis解决_服务器_03

 




 

  •                     <li class="tool-item tool-active is-like "><a href='javascript:void(0)'>

 

1、为什么要session共享

分布式开发项目中,用户通过浏览器登录商城,实际上会被转发到不同的服务器,当用户登录进入服务器A,session保存了用户的信息,用户再次点击页面被转发到服务器B,这时问题来了,服务器B没有该用户的session信息,无法验证通过,用户被踢回到登录页面,这样体验效果非常不好,甚至无法验证用户,购物车里面商品都不存在了。

2、利用redis解决方案

 

session共享解决办法 --------------- 商城session共享redis解决_ide_02

用户第一次进入商城首页,给一个CSESSIONID,(不用JSESSIONID的原因),用户添加商品,各种需要记录的操作,都与这个CSESSIONID关联起来;

当使用登录操作时候,将这个用户的信息,如用户名等存入到redis中,通过K_V,将CSESSIONID加一个标志作为key,将用户信息作为value;

当用户点击页面被转发到其他服务器时候,在需要验证是否同一个用户时,就可以从redis中取出value,进行验证用户信息,实现共享。

 

3、具体案例及实现java代码

    1、用户登录时候将csessionid存到redis
  1.  
    @RequestMapping(value="/login.aspx",method=RequestMethod.POST)
  2.  
    public String login(String username, String password, String returnUrl, Model model
  3.  
    , HttpServletRequest request, HttpServletResponse response) {
  4.  
    // 判断用户名不能为空
  5.  
    if (StringUtils.isNotBlank(username)) {
  6.  
    // 判断密码不为空
  7.  
    if (StringUtils.isNotBlank(password)) {
  8.  
    // 用户名必须正确nu
  9.  
    Buyer buyer = buyerService.selectBuyerByusername(username);
  10.  
    if (null !=buyer) {
  11.  
    // 密码必须正确
  12.  
    if (encodePassword(password).equals(buyer.getPassword())) {
  13.  
    // 保存用户名到session中 保存用户名到redis key == jsessionid
  14.  
    //注意不能用jsessionid,他被request操作,用csession
  15.  
    String csessionid = RequestUtils.getCSESSIONID(request, response);
  16.  
    sessionProvider.setAttribute(csessionid, buyer.getUsername());
  17.  
    // 回跳到之前的访问页面
  18.  
    return "redirect:" + returnUrl;
  19.  
    }else {
  20.  
    model.addAttribute("error", "密码必须正确");
  21.  
    }
  22.  
    }else {
  23.  
    model.addAttribute("error", "用户名必须正确");
  24.  
    }
  25.  
    } else {
  26.  
    model.addAttribute("error", "密码不能为空");
  27.  
    }
  28.  
    }else {
  29.  
    model.addAttribute("error", "用户名不能为空");
  30.  
    }
  31.  
    return"login";
  32.  
    }
 
  1.  
    /**
  2.  
    * 获取请求中的csessionid,如果有直接使用,
  3.  
    * 没有的话创建一个csessionid,并保存到response,添加到浏览器
  4.  
    * @param request
  5.  
    * @param response 用于最后将cookie存到浏览器,所以需要response
  6.  
    * @return
  7.  
    */
  8.  
    public static String getCSESSIONID(HttpServletRequest request,HttpServletResponse response) {
  9.  
    // 1、获取Cookies (里面有jsession 购物车。。。)
  10.  
    Cookie[] cookies = request.getCookies();
  11.  
    if (null !=cookies && cookies.length>0) {
  12.  
    for (Cookie cookie : cookies) {
  13.  
    // 2、从 Cookie中获取CSESSIONID
  14.  
    if (cookie.getName().equals("CSESSIONID")) {
  15.  
    // 3、如果有 直接使用
  16.  
    return cookie.getValue();
  17.  
    }
  18.  
    }
  19.  
    }
  20.  
    // 4、判断如果没有,创建一个CSESSIONID 保存CESSIONID到cookie,保存Cookie写回浏览器
  21.  
    String csessionid = UUID.randomUUID().toString().replaceAll("-", "");
  22.  
    Cookie cookie = new Cookie("CSESSIONID", csessionid);
  23.  
    //设置路径
  24.  
    cookie.setPath("/");
  25.  
    //设置Cookie的存活时间 立即销毁0 关闭浏览器销毁-1 到时间了再消失>0 前提:没有清理Cookie
  26.  
    cookie.setMaxAge(-1);
  27.  
    response.addCookie(cookie);
  28.  
    return csessionid;
  29.  
    }
 
    2、写一个SessionProviderImpl类,将CSESSIONID信息存入redis
    
  1.  
    /**
  2.  
    * 远程Session 保存到Redis中
  3.  
    * @author Administrator
  4.  
    *
  5.  
    */
  6.  
    //@Service("sessionProvider") 实现类的实例化交给spring管理,可以设置存活时间session.xml
  7.  
    public class SessionProviderImpl implements SessionProvider{
  8.  
     
  9.  
    @Autowired
  10.  
    private Jedis jedis;
  11.  
     
  12.  
    /**
  13.  
    * 保存用户到session
  14.  
    */
  15.  
    @Override
  16.  
    public void setAttribute(String key, String value) {
  17.  
    // 保存用户名到redis key == jsessionid
  18.  
    //保存
  19.  
    jedis.set(key + ":" + Constants.BUYER_SESSION, value);
  20.  
    // 时间30分钟
  21.  
    jedis.expire(key + ":" + Constants.BUYER_SESSION, Constants.SESSION_TIME);
  22.  
     
  23.  
    }
  24.  
     
  25.  
    /**
  26.  
    * 获取用户名
  27.  
    */
  28.  
    @Override
  29.  
    public String getAttribute(String key) {
  30.  
    String username = jedis.get(key + ":" + Constants.BUYER_SESSION);
  31.  
    if (null !=username) {
  32.  
    //不等于null,再设置一次session存活时间,保证session生存时间从最后一次登录计算
  33.  
    jedis.expire(key + ":" + Constants.BUYER_SESSION, Constants.SESSION_TIME);
  34.  
    return username;
  35.  
    }
  36.  
    return null;
  37.  
    }
  38.  
     
  39.  
    // 保存验证码到session
  40.  
    // 获取验证码
  41.  
     
  42.  
    /**
  43.  
    * 退出登录 让redis中session消失
  44.  
    * @param key
  45.  
    */
  46.  
    public void logout(String key) {
  47.  
    jedis.del(key + ":" + Constants.BUYER_SESSION);
  48.  
    }
  49.  
     
  50.  
    }
 
不通过注解方式注入,写配置文件session.xml
  1.  
    <!--session的实例化,不通过注解@service("sessionProvider")实现,改为交给spring管理 -->
  2.  
    <beanid="sessionProvider"class="cn.dapeng.core.service.user.SessionProviderImpl">
  3.  
    <!-- <property name="exp" value="1800"/> -->
  4.  
    </bean>
 

    3、验证用户只需要通过CSESSIONID去查询用户的信息,比如验证登录,验证购物车。。
  1.  
    /**
  2.  
    * 判断是否登录,返回登录标志0,未登录;1,已登录
  3.  
    * @param request
  4.  
    * @param response
  5.  
    */
  6.  
    @RequestMapping(value="/isLogin.aspx")
  7.  
    @ResponseBody
  8.  
    public MappingJacksonValue isLogin(String callback, HttpServletRequest request , HttpServletResponse response) {
  9.  
    Integer result = 0; //默认0,未登录
  10.  
    String username = sessionProvider.getAttribute(RequestUtils.getCSESSIONID(request, response));
  11.  
    if (null !=username) {
  12.  
    result = 1;
  13.  
    }
  14.  
    /*// json 的返回方法,但是受到跨域问题,因此改为jsonp
  15.  
    response.setContentType("application/json;charset=UTF-8");
  16.  
    try {
  17.  
    response.getWriter().write(result);
  18.  
    } catch (IOException e) {
  19.  
    // TODO Auto-generated catch block
  20.  
    e.printStackTrace();
  21.  
    }*/
  22.  
    //返回jsonp,callback里接收ajax传过来的MappingJacksonValue
  23.  
    MappingJacksonValue mjv = new MappingJacksonValue(result);
  24.  
    mjv.setJsonpFunction(callback);
  25.  
    return mjv;
  26.  
    }
 
*存入redis的数据结构
session共享解决办法 --------------- 商城session共享redis解决_服务器_03

 




 

  •                     <li class="tool-item tool-active is-like "><a href='javascript:void(0)'>