在业务逻辑中,会有这样的场景:
将用户信息存到session中,将用户信息存储在session中,为保证用户信息安全,将cookie的值设置为uuid,将存储用户信息的session的key设置为cookie的uuid。
@Override
public RespBean doLogin(LoginVo loginVo, HttpServletRequest request, HttpServletResponse response) {
String mobile = loginVo.getMobile();
String password = loginVo.getPassword();
/*if (StringUtils.isBlank(mobile) || StringUtils.isBlank(password)) {
return RespBean.error(RespBeanEnum.LOGINERROR);
}
if (!ValidatorUtil.isMobile(mobile)){
log.info("{}",ValidatorUtil.isMobile(mobile));
return RespBean.error(RespBeanEnum.MOBILEERROR);
}*/
User user = userMapper.selectById(mobile);
if (null == user) {
throw new GlobalException(RespBeanEnum.LOGINERROR);
}
String pass = Md5Util.formPassToDBPass(password, user.getSalt());
if (!pass.equals(user.getPassword())) {
throw new GlobalException(RespBeanEnum.LOGINERROR);
}
//使用uuid作为session的键,并将其存到cookie中
String ticket = UUIDUtil.uuid();
CookieUtil.setCookie(request,response,"userTicket",ticket);
//将用户对象存入session,用uuid做为键
request.getSession().setAttribute(ticket,user);
return RespBean.success(ticket);
}
这种场景下,不设置登录拦截器的情况下,在各种业务逻辑中需要判断用户是否登录或要将用户返回到页面,则要在每个controller中获取cookie,然后用cookie得到session中存储的用户信息。
@GetMapping("toList") //使用注解获取cookie的值
public String toList(HttpSession session, Model model,@CookieValue("userTicket") String ticket) {
//从cookie中获取uuid
if (StringUtils.isBlank(ticket)) {
return "login";
}
//用获取的uuid取出session中的用户对象
User user = (User) session.getAttribute(ticket);
if (null == user) {
return "login";
}
model.addAttribute("user",user);
return "goodsList";
}
如果只是一个业务这么写没得问题,但事情往往没有这么简单,为满足代码复用及代码优雅,需要简化写法。
在springboot中可以配置自定义用户参数,相当于拦截controller方法中的User参数,自己注入User的返回对象。
使用自定义用户参数的业务代码获取用户对象只需要把用户对象放到controller方法的参数列表中:
@PostMapping("doSeckill")
public String doSecKill(Model model, User user,Long goodsId) {
if (null == user) {
return "login";
}
model.addAttribute("user",user);
return "orderDetail";
}
配置方法如下:(与拦截器配置和静态资源映射配置相似)
- 新建WebConfig类实现WebMvcConfigurer接口
- 重写addArgumentResolvers方法
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Resource
private UserArgumentResolver userArgumentResolver;
/**
* 添加自定义控制器参数拦截
* @param resolvers
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(userArgumentResolver);
System.out.println("argumentResolvers"+resolvers);
}
}
- 创建自定义拦截参数类:UserArgumentResolver并实现HandlerMethodArgumentResolver
- 重写supportsParameter方法和resolveArgument方法。(supportsParameter方法返回true执行下面的resolveArgument方法) ----在resolveArgument方法中书写获取cookie的值进而获取session中用户信息并进行返回。
@Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {
@Resource
private UserService userService;
/**
* 返回true执行下面的resolveArgument方法
* @param methodParameter
* @return
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
Class<?> clazz = methodParameter.getParameterType();
System.err.println("拦截到user");
return clazz == User.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 userTicket = CookieUtil.getCookieValue(request, "userTicket");
System.err.println("用户参数拦截:"+userTicket);
//获取不到cookie中的用户凭证
if (StringUtils.isBlank(userTicket)) {
return null;
}
return userService.getUserByCookie(userTicket, request, response);
}
}
- 最后在WebConfig 类中注入UserArgumentResolver ,并添加到addArgumentResolvers方法中。
现在只需要在controller对应的业务逻辑方法的参数列表中声明User即可自动调用resolveArgument方法得到用户对象。