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

1、为什么要session共享

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

2、利用redis解决方案

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

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

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


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

    1、用户登录时候将csessionid存到redis
@RequestMapping(value="/login.aspx",method=RequestMethod.POST)
	public String login(String username, String password, String returnUrl, Model model
			, HttpServletRequest request, HttpServletResponse response) {
		// 判断用户名不能为空
		if (StringUtils.isNotBlank(username)) {
			// 判断密码不为空
			if (StringUtils.isNotBlank(password)) {
				// 用户名必须正确nu
				Buyer buyer = buyerService.selectBuyerByusername(username);
				if (null !=buyer) {
					// 密码必须正确
					if (encodePassword(password).equals(buyer.getPassword())) {
						// 保存用户名到session中    保存用户名到redis key == jsessionid
						//注意不能用jsessionid,他被request操作,用csession
						String csessionid = RequestUtils.getCSESSIONID(request, response);
						sessionProvider.setAttribute(csessionid, buyer.getUsername());
						// 回跳到之前的访问页面
						return "redirect:" + returnUrl;
					}else {
						model.addAttribute("error", "密码必须正确");
					}
				}else {
					model.addAttribute("error", "用户名必须正确");
				}
			} else {
				model.addAttribute("error", "密码不能为空");
			}
		}else {
			model.addAttribute("error", "用户名不能为空");
		}
		return"login";
	}
/**
	 * 获取请求中的csessionid,如果有直接使用,
	 * 没有的话创建一个csessionid,并保存到response,添加到浏览器
	 * @param request
	 * @param response  用于最后将cookie存到浏览器,所以需要response
	 * @return
	 */
	public static String getCSESSIONID(HttpServletRequest request,HttpServletResponse response) {
		// 1、获取Cookies (里面有jsession 购物车。。。)
		Cookie[] cookies = request.getCookies();
		if (null !=cookies && cookies.length>0) {
			for (Cookie cookie : cookies) {
				// 2、从 Cookie中获取CSESSIONID
				if (cookie.getName().equals("CSESSIONID")) {
					// 3、如果有 直接使用
					return cookie.getValue();
				}
			}
		}
		// 4、判断如果没有,创建一个CSESSIONID 保存CESSIONID到cookie,保存Cookie写回浏览器
		String csessionid = UUID.randomUUID().toString().replaceAll("-", "");
		Cookie cookie = new Cookie("CSESSIONID", csessionid);
		//设置路径
		cookie.setPath("/");
		//设置Cookie的存活时间     立即销毁0    关闭浏览器销毁-1      到时间了再消失>0   前提:没有清理Cookie
		cookie.setMaxAge(-1);
		response.addCookie(cookie);
		return csessionid;
	}
    2、写一个SessionProviderImpl类,将CSESSIONID信息存入redis
    
/**
 * 远程Session 保存到Redis中
 * @author Administrator
 *
 */
//@Service("sessionProvider") 实现类的实例化交给spring管理,可以设置存活时间session.xml
public class SessionProviderImpl implements SessionProvider{

	@Autowired
	private Jedis jedis;
	
	/**
	 *  保存用户到session
	 */
	@Override
	public void setAttribute(String key, String value) {
		// 保存用户名到redis key == jsessionid
		//保存
		jedis.set(key + ":" + Constants.BUYER_SESSION, value);
		// 时间30分钟
		jedis.expire(key + ":" + Constants.BUYER_SESSION, Constants.SESSION_TIME);
		
	}
	
	/**
	 *  获取用户名
	 */
	@Override
	public String getAttribute(String key) {
		String username = jedis.get(key + ":" + Constants.BUYER_SESSION);
		if (null !=username) {
			//不等于null,再设置一次session存活时间,保证session生存时间从最后一次登录计算
			jedis.expire(key + ":" + Constants.BUYER_SESSION, Constants.SESSION_TIME);
			return username;
		}
		return null;
	}
		
	// 保存验证码到session
	// 获取验证码
		
	/**
	 *  退出登录 让redis中session消失
	 * @param key
	 */
	public void logout(String key) {
		jedis.del(key + ":" + Constants.BUYER_SESSION);
	}

}
不通过注解方式注入,写配置文件session.xml
<!--session的实例化,不通过注解@service("sessionProvider")实现,改为交给spring管理  -->
		<bean id="sessionProvider" class="cn.dapeng.core.service.user.SessionProviderImpl">
			<!-- <property name="exp" value="1800"/> -->
		</bean>

    3、验证用户只需要通过CSESSIONID去查询用户的信息,比如验证登录,验证购物车。。
/**
	 * 判断是否登录,返回登录标志0,未登录;1,已登录
	 * @param request
	 * @param response
	 */
	@RequestMapping(value="/isLogin.aspx")
	@ResponseBody
	public MappingJacksonValue isLogin(String callback, HttpServletRequest request , HttpServletResponse response) {
		Integer result = 0;  //默认0,未登录
		String username = sessionProvider.getAttribute(RequestUtils.getCSESSIONID(request, response));
		if (null !=username) {
			result = 1;
		}
		/*// json 的返回方法,但是受到跨域问题,因此改为jsonp
		response.setContentType("application/json;charset=UTF-8");
		try {
			response.getWriter().write(result);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
		//返回jsonp,callback里接收ajax传过来的MappingJacksonValue
		 MappingJacksonValue mjv = new MappingJacksonValue(result);
		 mjv.setJsonpFunction(callback);
		 return mjv;
	}

*存入redis的数据结构




猜你喜欢

转载自blog.csdn.net/w20228396/article/details/79425078
今日推荐