咱們都知道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); } }