高并发秒杀系统方案(分布式session)
编程要有一个习惯:做参数校验
所谓的分布式session:就是用redis统一管理session。
我们这里的思路是:把token写入cookie中,客户端在随后的访问中携带cookie,服务端就能根据cookie中携带的token去redis中查找到user信息。
这里要注意:session的有效期是用户最后的访问时间加session的过期时间
关键代码:
//生成cookie String token = UUIDUtil.uuid(); addCookie(response, token, user); return true; } 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); }
UserArgumentResolver:
package com.imooc.miaosha.config; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; 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.imooc.miaosha.domain.MiaoshaUser; import com.imooc.miaosha.service.MiaoshaUserService; @Service public class UserArgumentResolver implements HandlerMethodArgumentResolver { @Autowired MiaoshaUserService userService; public boolean supportsParameter(MethodParameter parameter) { Class<?> clazz = parameter.getParameterType(); return clazz==MiaoshaUser.class; } public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); String paramToken = request.getParameter(MiaoshaUserService.COOKI_NAME_TOKEN); String cookieToken = getCookieValue(request, MiaoshaUserService.COOKI_NAME_TOKEN); if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)) { return null; } String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken; return userService.getByToken(response, token); } private String getCookieValue(HttpServletRequest request, String cookiName) { Cookie[] cookies = request.getCookies(); for(Cookie cookie : cookies) { if(cookie.getName().equals(cookiName)) { return cookie.getValue(); } } return null; } }
WebConfig:
package com.imooc.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.WebMvcConfigurerAdapter; @Configuration public class WebConfig extends WebMvcConfigurerAdapter{ @Autowired UserArgumentResolver userArgumentResolver; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(userArgumentResolver); } }
经过这样的配置以后,就可以直接获取user而不用通过token再获取user了: