1.首先通过uuid生成唯一标识的token信息
String token = UUIDUtil.uuid();
2.然后把token信息连带着user用户信息放到缓存服务器中
redisService.set(MiaoshaUserKey.token, token, user);
3.再new出来一个cookie对象,往里面填充值,设置信息。
Cookie cookie = new Cookie(COOKI_NAME_TOKEN, token);
cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
cookie.setPath("/");
4.这时候算是存进去了token信息,我们需要登录的时候获取token信息。
public SeckillUser getByToke(String token) {
if(StringUtils.isEmpty(token)){
return null;
}
return redisService.get(SeckillUserKey.token, token, SeckillUser.class);
}
5.当我们登录成功后,跳转其它页面时,token信息已经塞到了http请求,拿到token信息后,通过token信息取出自己的user信息后,显示到界面。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.wings.seckill.domain.SeckillUser;
import com.wings.seckill.service.SeckillUserService;
@Controller
@RequestMapping("/goods")
public class GoodsController {
private static Logger log = LoggerFactory.getLogger(GoodsController.class);
@Autowired
private SeckillUserService seckillUserService;
@RequestMapping("/to_list")
public String toList(Model model,
@CookieValue(name = SeckillUserService.COOKIE_TOKEN_NAME, required = false) String cookieToken,
// @RequestParam 是为了兼容默写手机端会把cookie信息放入请求参数中
@RequestParam(name = SeckillUserService.COOKIE_TOKEN_NAME, required = false) String paramToken) {
if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)){
return "/login/to_login";
}
String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
SeckillUser seckillUser = seckillUserService.getByToke(token);
model.addAttribute("user", seckillUser);
return "goods_list";
}
}
像User这种,几乎每个Controller方法都要使用的对象,如果每个Controller的方法都通过以上方式获取,代码将相当臃肿。这时,可以使用SpringMVC中WebMvcConfigurerAdapter的addArgumentResolvers,向需要user对象的方法进行入参注入。
package com.imooc.miaosha.config;
import com.imooc.miaosha.access.AccessInterceptor;
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.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
/**
* Created by 张伟光 on 2019/5/18.
*/
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
UserArgumentResolever userArgumentResolever;
@Autowired
AccessInterceptor accessInterceptor;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(userArgumentResolever);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(accessInterceptor);
}
}
下面是用spring自定参数解析器,
接口说明:
supportsParameter:用于判定是否需要处理该参数分解,返回true为需要,并会去调用下面的方法resolveArgument。
resolveArgument:真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。
package com.wings.seckill.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.util.StringUtils;
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.wings.seckill.domain.SeckillUser;
import com.wings.seckill.service.SeckillUserService;
@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver{
@Autowired
private SeckillUserService seckillUserService;
@Override
public boolean supportsParameter(MethodParameter parameter) {
Class<?> clazz = parameter.getParameterType();
return clazz == SeckillUser.class;
}
@Override
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(SeckillUserService.COOKIE_TOKEN_NAME);
String cookieToken = getCookieValue(request, SeckillUserService.COOKIE_TOKEN_NAME);
if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)){
return null;
}
String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
return seckillUserService.getByToke(token, response);
}
private String getCookieValue(HttpServletRequest request, String cookieName) {
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
if(cookie.getName().equals(cookieName)){
return cookie.getValue();
}
}
}
return null;
}
}
这样控制器就变得干净了,可以直接获取了user信息。
【总结】
框架封装做好了,就会给开发人员留有更多的时间来做业务。