I think this kind of parser is a supplement to the parsing of interface parameters based on key value, which relies on the relevant annotation of parsing interface parameters based on key value. Once upon a time, have you ever thought of encapsulating @ RequestParam into a Map and analyzing it yourself? The same type of processor gives this ability to @ RequestHeader, @ PathVariable, @ MatrixVariable~
@Override public boolean supportsParameter(MethodParameter parameter) { PathVariable ann = parameter.getParameterAnnotation(PathVariable.class); return (ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) && !StringUtils.hasText(ann.value())); } /** * Return a Map with all URI template variables or an empty map. */ @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { @SuppressWarnings("unchecked") Map<String, String> uriTemplateVars = (Map<String, String>) webRequest.getAttribute( HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); if (!CollectionUtils.isEmpty(uriTemplateVars)) { return new LinkedHashMap<>(uriTemplateVars); } else { return Collections.emptyMap(); } }
1. Processor processing description
- Must be annotated with @ PathVariable annotation and its parameter type is map
2. Parameter analysis process
- Use Map to install and return all path parameters
@Override public boolean supportsParameter(MethodParameter parameter) { RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class); return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) && !StringUtils.hasText(requestParam.name())); } @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter); if (MultiValueMap.class.isAssignableFrom(parameter.getParameterType())) { // MultiValueMap Class<?> valueType = resolvableType.as(MultiValueMap.class).getGeneric(1).resolve(); if (valueType == MultipartFile.class) { MultipartRequest multipartRequest = MultipartResolutionDelegate.resolveMultipartRequest(webRequest); return (multipartRequest != null ? multipartRequest.getMultiFileMap() : new LinkedMultiValueMap<>(0)); } else if (valueType == Part.class) { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); if (servletRequest != null && MultipartResolutionDelegate.isMultipartRequest(servletRequest)) { Collection<Part> parts = servletRequest.getParts(); LinkedMultiValueMap<String, Part> result = new LinkedMultiValueMap<>(parts.size()); for (Part part : parts) { result.add(part.getName(), part); } return result; } return new LinkedMultiValueMap<>(0); } else { Map<String, String[]> parameterMap = webRequest.getParameterMap(); MultiValueMap<String, String> result = new LinkedMultiValueMap<>(parameterMap.size()); parameterMap.forEach((key, values) -> { for (String value : values) { result.add(key, value); } }); return result; } } else { // Regular Map Class<?> valueType = resolvableType.asMap().getGeneric(1).resolve(); if (valueType == MultipartFile.class) { MultipartRequest multipartRequest = MultipartResolutionDelegate.resolveMultipartRequest(webRequest); return (multipartRequest != null ? multipartRequest.getFileMap() : new LinkedHashMap<>(0)); } else if (valueType == Part.class) { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); if (servletRequest != null && MultipartResolutionDelegate.isMultipartRequest(servletRequest)) { Collection<Part> parts = servletRequest.getParts(); LinkedHashMap<String, Part> result = new LinkedHashMap<>(parts.size()); for (Part part : parts) { if (!result.containsKey(part.getName())) { result.put(part.getName(), part); } } return result; } return new LinkedHashMap<>(0); } else { Map<String, String[]> parameterMap = webRequest.getParameterMap(); Map<String, String> result = new LinkedHashMap<>(parameterMap.size()); parameterMap.forEach((key, values) -> { if (values.length > 0) { result.put(key, values[0]); } }); return result; } } }
1. Processor processing description
- Use @ RequestParam annotation and the parameter type is map
2. Parameter analysis process
- It can't transmit a key with multiple values. If the same key appears, the value of the key at the top shall prevail. The Map instance is a LinkedHashMap < string, string > instance
2, case
@ResponseBody @GetMapping("/test") public Object test(@RequestParam Map<String,Object> params) { System.out.println(params); return params; }
Search path / test? Name = FSX & age = 18 & age = 28, console output is as follows:
age can only take one of these values
3,RequestHeaderMapMethodArgumentResolverGet all the request header information at one time: write multi value map (linked multi value map) / httpheaders / map for data type expenditure
@Override public boolean supportsParameter(MethodParameter parameter) { return (parameter.hasParameterAnnotation(RequestHeader.class) && Map.class.isAssignableFrom(parameter.getParameterType())); } @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Class<?> paramType = parameter.getParameterType(); if (MultiValueMap.class.isAssignableFrom(paramType)) { MultiValueMap<String, String> result; if (HttpHeaders.class.isAssignableFrom(paramType)) { result = new HttpHeaders(); } else { result = new LinkedMultiValueMap<>(); } for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) { String headerName = iterator.next(); String[] headerValues = webRequest.getHeaderValues(headerName); if (headerValues != null) { for (String headerValue : headerValues) { result.add(headerName, headerValue); } } } return result; } else { Map<String, String> result = new LinkedHashMap<>(); for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) { String headerName = iterator.next(); String headerValue = webRequest.getHeader(headerName); if (headerValue != null) { result.put(headerName, headerValue); } } return result; } }
1. Processor processing description
- The @ RequestHeader must be annotated and the parameter is of type map
2, case
@ResponseBody @GetMapping("/test") public Object test(@RequestHeader Map<String, Object> headers) { headers.forEach((k, v) -> System.out.println(k + "-->" + v)); return headers; }
Console output:
host-->localhost:8080 connection-->keep-alive cache-control-->max-age=0 upgrade-insecure-requests-->1 . . . .
However, it is strongly not recommended to use Map directly, but use HttpHeaders type. Write @ RequestHeader HttpHeaders headers in this way. It is more convenient to get them.
4,MapMethodProcessorIt deals with the Map type, but without any annotation. Its execution order is very backward, so it's a bit of understatement.
The processor also explains why you can easily get the value of the model by writing a Map, HashMap, ModelMap, etc. on the input parameter~
@Override public boolean supportsParameter(MethodParameter parameter) { return Map.class.isAssignableFrom(parameter.getParameterType()); } @Override @Nullable public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { Assert.state(mavContainer != null, "ModelAndViewContainer is required for model exposure"); return mavContainer.getModel(); }
1. Processor processing description
- This processor, which is very late in spring's parameter processing chain, deals with map types without any annotation
2. Parameter analysis process
- Return the Model directly
Slightly.
qq_41071876 Published 1 original article, praised 0 and visited 14 Private letter follow