在登录之后,可能服务器是分布式的,因此不能通过一个本地的session来管理登录信息,导致登录的信息不能传递,即在这台服务器上可以得到用户登录信息,但在那台就得不到。因此,需要设置分布式的session,方法是,使用一个token,存在客户端的本地cookie,当接收请求时,从客户端将cookie值传过去,或者将token值存到缓存中,从缓存中取值。
-
起步
在登录的时候,当登录成功后,便随机生成一个token值,将该值存到redis缓存中,并将该值存到cookie中,返回到客户端。
private void addCookie(HttpServletResponse response,String token, MiaoshaUser user){ //将token存入缓存中 redisService.set(MiaoshaUserKey.token,token,user); //将token存入COOKIE中 Cookie cookie=new Cookie(COOKI_NAME_TOKEN,token); cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds()); cookie.setPath("/"); response.addCookie(cookie); }
该方法在MiaoshaUserService中的login方法中调用。
-
跳转
登录以后,要跳转到商品页面,但需要把商品页面传过来,一种是一个机器的,可以直接传过去,但如果是分布式的,只能通过token来获取。
@Controller @RequestMapping("/goods") public class GoodsController { @RequestMapping("/to_list") public String list(Model model, MiaoshaUser user){ model.addAttribute("user",user); return "goods_list"; } }
这种方法是无法获取user的值的。
-
取值
@Controller @RequestMapping("/goods") public class GoodsController { @Autowired private MiaoshaUserService miaoshaUserService; @RequestMapping("/to_list") public String list(HttpServletResponse response,Model model, @CookieValue(value = MiaoshaUserService.COOKI_NAME_TOKEN) String token){ MiaoshaUser user = miaoshaUserService.getByToken(response, token); model.addAttribute("user",user); return "goods_list"; } }
获取到cookie的值就可以获取user对象了。
但上述方法不够降低耦合,因此,采用配置参数的方法。
-
定义一个web的配置类
@Configuration public class WebConfig extends WebMvcConfigurerAdapter{ @Autowired UserArgumentResolver userArgumentResolver; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(userArgumentResolver); } }
-
配置类的handle方法
public class UserArgumentResolver implements HandlerMethodArgumentResolver { @Autowired MiaoshaUserService userService; @Override public boolean supportsParameter(MethodParameter methodParameter) { Class<?> clazz = methodParameter.getParameterType(); return clazz==MiaoshaUser.class; } @Override public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception { HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class); HttpServletResponse response = nativeWebRequest.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类是个web的配置类。我们之所以能实现在controller拿到参数的转换值,就是一堆类在内部发挥看不见的作用,而通过WebConfig可以实现,自己配置那些参数的转化,它继承了一个WebMvcConfigurerAdapter类,该类是个抽象类,定义了很多可以配置的方法,而我们对参数进行配置,则只需要添加一个HandlerMethodArgumentResolver接口的实现类。
而第二个类就是该接口的实现类,可以实现具体拿到参数后进行的逻辑操作,比如,在该类中,我们拿到了request、reponse对象,然后得到token在reques的值和cookie中的值。然后,将token对应的user对象取出来。因此,我们在controller类中,只需要配置user的参数就可以取到user的值。