2018-12-12 分部式session
2018-12-12 本文已影响0人
培根好吃
1.分布式session上
1.1 service层用户登录之后生成一个sessionId token
package com.ryan.miaosha.util;
import java.util.UUID;
public class UUIDUtil {
public static String uuid() {
return UUID.randomUUID().toString().replace("-", "");
}
}
1.2 redis中写入MiaoshaUserKey
package com.ryan.miaosha.redis;
public class MiaoshaUserKey extends BasePrefix{
private static final int TOKEN_EXPIRE=3600*24*2;
private MiaoshaUserKey(int expiredSeconds,String prefix) {
super(expiredSeconds,prefix);
}
public static MiaoshaUserKey getByToken=new MiaoshaUserKey(TOKEN_EXPIRE,"token");
}
1.3 service层 将它存储在cookie上,传给客户端
客户端每次写数据都是在cookie中写入
package com.ryan.miaosha.service;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ryan.miaosha.dao.MiaoshaUser;
import com.ryan.miaosha.dao.MiaoshaUserDao;
import com.ryan.miaosha.domain.CodeMsg;
import com.ryan.miaosha.exception.GlobalException;
import com.ryan.miaosha.redis.MiaoshaUserKey;
import com.ryan.miaosha.redis.RedisService;
import com.ryan.miaosha.util.MD5Util;
import com.ryan.miaosha.util.UUIDUtil;
import com.ryan.miaosha.vo.LoginVo;
@Service
public class MiaoshaService {
public static final String COOKIE_NAME_TOKEN="token";
@Autowired
MiaoshaUserDao miaoshaUserDao;
@Autowired
RedisService redisService;
public MiaoshaUser getById(long id) {
return miaoshaUserDao.selectById(id);
}
public boolean login(HttpServletResponse response, LoginVo vo) {
MiaoshaUser user = getById(Long.parseLong(vo.getMobile()));
if(user==null) {
throw new GlobalException(CodeMsg.USER_NOT_EXIST);
}
String saltDB = user.getSalt();
String passwordDB = user.getPassword();
String webPass = vo.getPassword();
String passValidated=MD5Util.WebPassToDB(webPass, saltDB);
if(!passValidated.equals(passwordDB)) {
throw new GlobalException(CodeMsg.PASSWORD_ERROR);
}
//利用工具UUIDUtil生成uuid
String token=UUIDUtil.uuid();
//将token以及对应的用户存入session redis
redisService.set(MiaoshaUserKey.getByToken, token, user);
//将token存入cookie,传回客户端
Cookie cookie=new Cookie(COOKIE_NAME_TOKEN, token);
//设置过期时间 ,与session相同 设置路径 根目录 添加http响应 添加cookie
cookie.setMaxAge(MiaoshaUserKey.getByToken.expiredSeconds());
cookie.setPath("/");
response.addCookie(cookie);
return true;
}
}
1.4 从controller层中把从客户端传来的cookie数据读出
@RequestMapping("/to_list")
String toLogin(Model model,
@CookieValue(value=MiaoshaService.COOKIE_NAME_TOKEN,required=false) String cookieToken,
@RequestParam(value=MiaoshaService.COOKIE_NAME_TOKEN,required=false) String paramToken) {
if(StringUtils.isEmpty(paramToken)&&StringUtils.isEmpty(cookieToken))
return "login";
String token=StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
MiaoshaUser user=miaoshaUserService.getByToken(token);
model.addAttribute("user", user);
return "goods_list";
}
1.5 service层中再增加一个方法:根据token获取到user ,在goods_list html中展示出来
public MiaoshaUser getByToken(String token) {
if(StringUtils.isEmpty(token)) {
return null;
}
return redisService.get(MiaoshaUserKey.getByToken, token, MiaoshaUser.class);
}
1.6 goods_list html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>登录</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'hello:'+${user.nickname}">
</body>
</html>
1.7 为了满足每次访问页面时,以最后一次登录时的cookie过期时间为准,我们需要在获取redis中的用户user之后再写入一次cookie
1. MiaoshaUser user=miaoshaUserService.getByToken(response,token);
2.
private void addCookie(HttpServletResponse response, String token, MiaoshaUser user) {
redisService.set(MiaoshaUserKey.token, token, user);
Cookie cookie = new Cookie(COOKI_NAME_TOKEN, token);
cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
cookie.setPath("/");
response.addCookie(cookie);
}
public MiaoshaUser getByToken(HttpServletResponse response,String token) {
if(StringUtils.isEmpty(token)) {
return null;
}
// 判断user是否为空,如果不为空,则再将token 及用户存入一次cookie;达到以最后一次登录为基准
MiaoshaUser user=redisService.get(MiaoshaUserKey.getByToken, token, MiaoshaUser.class);
if(user!=null) {
addCookie(response,token,user);
}
return user;
}
1.8 创建一个WebConfig 类配置handler里面的参数
package com.ryan.miaosha.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer{
/*这个参数解析器 可以根据handler方法上的参数类型 设置参数,
* @RequestMapping("/to_list")
String toLogin(HttpServletResponse response,Model model)
里面的response model 都是由它这个方法来赋值的
*/
@Autowired
UserArgumentResolver userArgumentResolver;
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userArgumentResolver);
}
}
1.3 创建一个HandlerMethodArgumentResolver接口的实现类UserArgumentResolver,用来给WebConfig传参数
package com.ryan.miaosha.config;
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.core.MethodParameter;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import com.alibaba.druid.util.StringUtils;
import com.ryan.miaosha.dao.MiaoshaUser;
import com.ryan.miaosha.redis.RedisService;
import com.ryan.miaosha.service.MiaoshaService;
@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver{
@Autowired
MiaoshaService miaoshaUserService;
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> clazz = parameter.getParameterType();
return clazz==MiaoshaUser.class;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest nativeRequest = webRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse nativeResponse = webRequest.getNativeResponse(HttpServletResponse.class);
String paramToken = nativeRequest.getParameter(MiaoshaService.COOKIE_NAME_TOKEN);
String cookieToken=getCookieTk(nativeRequest,MiaoshaService.COOKIE_NAME_TOKEN);
if(StringUtils.isEmpty(paramToken)&&StringUtils.isEmpty(cookieToken))
return null;
String token=StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
return miaoshaUserService.getByToken(nativeResponse, token);
}
private String getCookieTk(HttpServletRequest nativeRequest,String cookieNameToken) {
Cookie[] cookies = nativeRequest.getCookies();
for(Cookie cookie:cookies) {
if(cookie.getName().equals(cookieNameToken))
return cookie.getValue();
}
return null;
}
}
1.3