咱们都知道SpringMvc的Controller的方法上能够接收各类各样的参数,好比HttpServletRequest
或HttpServletResponse
,各类注解@RequestParam
、@RequestHeader
、@RequestBody
、@PathVariable
、@ModelAttribute
,这些参数是从哪里获取的?java
这些参数都是由不一样的参数解析器为咱们解析出来的,能够解析类也能够解析带注解的类
request
、response
等参数作一系列操做来获取该类对象)自定义配置类实现WebMvcConfigurer
接口,重写其中的addArgumentResolvers
方法来添加本身的解析类(经过自动注入的方法注入)web
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private SecKillUserArgumentResolvers secKillUserArgumentResolvers; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(secKillUserArgumentResolvers); } }
HandlerMethodArgumentResolver处理器方法解析器
接口,并实现其中的supportsParameter
和resolveArgument
方法HandlerMethodArgumentResolver
的接口定义以下:redis
(1)supportsParameter
用于判断是否支持对某种参数的解析(支持则返回true)cookie
(2)resolveArgument
将请求中的参数值解析为某种对象(具体的操做获取解析对象)app
下面这个自定义解析器用于获取User对象(经过token获取保存在redis中的user),无需每次使用resquest和response在controller方法内部获取,能够直接获取到做为参数传入ide
/** * 自定义参数解析器 * 解析每次都要获取的user自动传入,无需每次获取 */ @Component public class SecKillUserArgumentResolvers implements HandlerMethodArgumentResolver { @Autowired private UserService userService; @Override public boolean supportsParameter(MethodParameter methodParameter) { Class<?> c = methodParameter.getParameterType(); return c == 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); assert request != null; String paramToken = request.getParameter(UserServiceImpl.COOKIE_NAME_TOKEN);//COOKIE_NAME_TOKEN="token" String cookieToken = getCookieValue(request); if(StringUtils.isEmpty(cookieToken)&&StringUtils.isEmpty(paramToken)){//经过两种方式获取,若是都获取失败则返回null return null; }else { String token = StringUtils.isEmpty(paramToken)?cookieToken:paramToken; return UserService.getUserByToken(response,token); } } //遍历cookie获取名称相同的那个cookie的值 private String getCookieValue(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); for(Cookie cookie:cookies){ if(cookie.getName().equals(SecKillUserServiceImpl.COOKIE_NAME_TOKEN)){ return cookie.getValue(); } } return null; } }
到此,一个自定义参数解析器就实现好了,咱们能够经过传入参数的形式直接经过解析器帮咱们获取到
@RequestMapping("/to_list") public String toList(Model model,User user){ }
Model
对象参数就能够直接使用它,咱们看看它的参数解析器ModelAttributeMethodProcessor
类ui
public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(ModelAttribute.class) || this.annotationNotRequired && !BeanUtils.isSimpleProperty(parameter.getParameterType()); } @Nullable public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer"); Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory"); String name = ModelFactory.getNameForParameter(parameter); ModelAttribute ann = (ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class); if (ann != null) { mavContainer.setBinding(name, ann.binding()); } Object attribute = null; BindingResult bindingResult = null; if (mavContainer.containsAttribute(name)) { attribute = mavContainer.getModel().get(name); } else { try { attribute = this.createAttribute(name, parameter, binderFactory, webRequest); } catch (BindException var10) { if (this.isBindExceptionRequired(parameter)) { throw var10; } if (parameter.getParameterType() == Optional.class) { attribute = Optional.empty(); } bindingResult = var10.getBindingResult(); } } if (bindingResult == null) { WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name); if (binder.getTarget() != null) { if (!mavContainer.isBindingDisabled(name)) { this.bindRequestParameters(binder, webRequest); } this.validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) { throw new BindException(binder.getBindingResult()); } } if (!parameter.getParameterType().isInstance(attribute)) { attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter); } bindingResult = binder.getBindingResult(); } Map<String, Object> bindingResultModel = bindingResult.getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); return attribute; }
RequestParamMethodArgumentResolver
类,基于注解的方式this
若是传入参数parameter上有该注解,则能够解析code
public boolean supportsParameter(MethodParameter parameter) { if (parameter.hasParameterAnnotation(RequestParam.class)) { if (!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) { return true; } else { RequestParam requestParam = (RequestParam)parameter.getParameterAnnotation(RequestParam.class); return requestParam != null && StringUtils.hasText(requestParam.name()); } } else if (parameter.hasParameterAnnotation(RequestPart.class)) { return false; } else { parameter = parameter.nestedIfOptional(); if (MultipartResolutionDelegate.isMultipartArgument(parameter)) { return true; } else { return this.useDefaultResolution ? BeanUtils.isSimpleProperty(parameter.getNestedParameterType()) : false; } } }
PathVariableMethodArgumentResolver
类,也是基于注解,与RequestParam相似对象
public boolean supportsParameter(MethodParameter parameter) { if (!parameter.hasParameterAnnotation(PathVariable.class)) { return false; } else if (!Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) { return true; } else { PathVariable pathVariable = (PathVariable)parameter.getParameterAnnotation(PathVariable.class); return pathVariable != null && StringUtils.hasText(pathVariable.value()); } }
@Target(value = ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface ParamModel { }
public class MyArgumentResolver implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter methodParameter) { return methodParameter.hasParameterAnnotation(ParamModel.class);//带有注解就解析 } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { //实现解析对象代码 }
WebMvcConfigurer
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private MyArgumentResolvers myArgumentResolvers; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(myArgumentResolvers); } }