(7)SprintBoot 2.X 自定义参数解析器
1.为什么引入参数解析器
- 想办法在直接在controller的请求的方法上面直接注入MiaoshaUser(用户的信息),直接通过方法的参数就可以将获取用户的信息,从而简化代码。就像SpringMVC中的controller 方法中可以有很多参数可以直接使用(例如request和response对象),有些参数不需要传值,就可以直接获取到一样
- 避免在GoodsController中的每个@RequestMapping(“to_list”,“detail”)等等重复下述与业务逻辑无关的代码
if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)){
return "login";
}
String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
MiaoshaUser user = userService.getByToken(response,token);
2.代码实现
2.1 HandlerMethodArgumentResolver接口
- HandlerMethodArgumentResolver接口,通过实现这个接口的类,就是解析器。按照我们的期望,它中间的函数应该能得到必要信息,从而按照自定义逻辑计算并返回一个值。
- MethodParameter 是spring对被注解修饰过参数的包装,从其中能拿到参数的反射相关信息。
- supportsParameter() 传入一个参数,用以判断此参数是否能够使用该解析器。
- resolveArgument() 就是之前讨论的解析函数,传入必要信息,计算并返回一个值。
- 综合来看,框架会将每一个MethodParameter传入supportsParameter测试是否能够被处理,如果能够,就使用resolveArgument处理。
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception;
}
2.2 创建一个UserArgumentResolver类
- 实现接口HandlerMethodArgumentResolver,然后重写里面的方法resolveArgument和supportsParameter方法
- 实现思路: 先获取到已有参数HttpServletRequest,从中获取到token,再用token作为key从redis拿到User,而HttpServletResponse作用是为了延迟有效期
@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver{
@Autowired
MiaoshaUserService miaoshaUserService;
public boolean supportsParameter(MethodParameter parameter) {
Class<?> clazz=parameter.getParameterType();
return clazz==MiaoshaUser.class;
}
public Object resolveArgument(MethodParameter arg0, ModelAndViewContainer arg1, NativeWebRequest webRequest,
WebDataBinderFactory arg3) throws Exception {
HttpServletRequest request=webRequest.getNativeRequest(HttpServletRequest.class);
HttpServletResponse response=webRequest.getNativeResponse(HttpServletResponse.class);
String paramToken=request.getParameter(MiaoshaUserService.COOKIE1_NAME_TOKEN);
String cookieToken=getCookieValue(request,MiaoshaUserService.COOKIE1_NAME_TOKEN);
if(StringUtils.isEmpty(cookieToken)&&StringUtils.isEmpty(paramToken))
{
return null;
}
String token=StringUtils.isEmpty(paramToken)?cookieToken:paramToken;
MiaoshaUser user=miaoshaUserService.getByToken(token,response);
return user;
}
public String getCookieValue(HttpServletRequest request, String cookie1NameToken) {
Cookie[] cookies=request.getCookies();
if(cookies!=null) {
for(Cookie cookie :cookies) {
if(cookie.getName().equals(cookie1NameToken)) {
System.out.println("getCookieValue:"+cookie.getValue());
return cookie.getValue();
}
}
}
return null;
}
}
2.3 注册解析器
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter{
@Autowired
UserArgumentResolver userArgumentResolver;
@Autowired
AccessInterceptor accessInterceptor;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(userArgumentResolver);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(accessInterceptor);
}
}
2.4 业务逻辑代码的使用
- 改变SpringMVC的Controller传入参数,实现可以User替换Token做为参数从登陆页面传到商品列表页面
@RequestMapping("/to_list")
public String toList(Model model,MiaoshaUser user) {
model.addAttribute("user", user);
List<GoodsVo> goodsList= goodsService.getGoodsVoList();
model.addAttribute("goodsList", goodsList);
return "goods_list";
}