介绍 SpringMvc 如何处理参数解析 和 如何处理返回值的。
文章最后列举了HandlerMethodArgumentResolver 接口和 HandlerMethodReturnValueHandler 接口的实现类列表
SpringMVC请求过程
- 前端请求 首先被 DispatcherServlet 截获,DispatcherServlet 通过 handlerMapping 获得HandlerExecutionChain,然后获得 HandlerAdapter。
- HandlerAdapter 在内部对于每个请求,都会实例化一个 ServletInvocableHandlerMethod 进行处理,ServletInvocableHandlerMethod 在进行处理的时候,会分两部分(参数值和返回值)分别对请求跟响应进行处理。
- 之后 HandlerAdapter 得到 ModelAndView ,然后做相应的处理。
ServletInvocableHandlerMethod 分析
ServletInvocableHandlerMethod 在处理时,将 方法参数的处理 交给 HandlerMethodArgumentResolver 处理,而方法的返回值会交给 HandlerMethodReturnValueHandler 处理。
- HandlerMethodArgumentResolver 请求方法参数的处理
- HandlerMethodReturnValueHandler 响应返回值的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { public Object invokeForRequest( NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } return doInvoke(args); } public void invokeAndHandle( ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest);
if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; }
mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }
|
RequestResponseBodyMethodProcessor详解
本文以 RequestResponseBodyMethodProcessor 为例讲解 。
HandlerMethodArgumentResolver接口
定义了两个方法:
1 2 3 4 5 6 7 8 9 10 11 12
| public interface HandlerMethodArgumentResolver { boolean supportsParameter(MethodParameter parameter); @Nullable Object resolveArgument( MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
|
HandlerMethodReturnValueHandler接口
定义了两个方法:
1 2 3 4 5 6 7 8 9 10 11
| public interface HandlerMethodReturnValueHandler { boolean supportsReturnType(MethodParameter returnType); void handleReturnValue( @Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
}
|
AbstractMessageConverterMethodArgumentResolver
HandlerMethodArgumentResolver接口的抽象类: 仅仅引入了HttpMessageConverter,即具体的转换工作由这些HttpMessageConverter来完成。
简单介绍AbstractMessageConverterMethodArgumentResolver中其他关联的类:
- HttpMessageConverter : 消息转换器。将 Request的 body 转换为想要的结果。常接触到的例子。FastJsonHttpMessageConverter 将 json字符串转换为对应的类对象。
- RequestBodyAdvice: 在消息转换器的作用前后执行。常用于 请求的加解密,与ControllerAdvice注解同时使用。
AbstractMessageConverterMethodArgumentResolver源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| public abstract class AbstractMessageConverterMethodArgumentResolver implements HandlerMethodArgumentResolver { @Nullable protected <T> Object readWithMessageConverters( HttpInputMessage inputMessage, MethodParameter parameter, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
MediaType contentType; boolean noContentType = false; try { contentType = inputMessage.getHeaders().getContentType(); } catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } if (contentType == null) { noContentType = true; contentType = MediaType.APPLICATION_OCTET_STREAM; }
Class<?> contextClass = parameter.getContainingClass(); Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null); if (targetClass == null) { ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter); targetClass = (Class<T>) resolvableType.resolve(); } HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null); Object body = NO_VALUE; EmptyBodyCheckingHttpInputMessage message; try { message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
for (HttpMessageConverter<?> converter : this.messageConverters) { Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass(); GenericHttpMessageConverter<?> genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null); if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) : (targetClass != null && converter.canRead(targetClass, contentType))) { if (message.hasBody()) { HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType); body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse)); body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType); } else { body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType); } break; } } } catch (IOException ex) { throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage); }
if (body == NO_VALUE) { if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) || (noContentType && !message.hasBody())) { return null; } throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes); }
MediaType selectedContentType = contentType; Object theBody = body; LogFormatUtils.traceDebug(logger, traceOn -> { String formatted = LogFormatUtils.formatValue(theBody, !traceOn); return "Read \"" + selectedContentType + "\" to [" + formatted + "]"; });
return body; } }
|
AbstractMessageConverterMethodProcessor抽象类
在 AbstractMessageConverterMethodArgumentResolver抽象类 的基础上,添加HandlerMethodReturnValueHandler接口。
因此 AbstractMessageConverterMethodProcessor类 不仅可以用来转换请求数据,也可以用来转换响应数据。
RequestResponseBodyMethodProcessor类
继承自 AbstractMessageConverterMethodProcessor,专注解析 包含@RequestBody 和 @ResponseBody注解的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); } @Override public boolean supportsReturnType(MethodParameter returnType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); } @Override public Object resolveArgument( MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { }
@Override protected <T> Object readWithMessageConverters( NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException,HttpMessageNotReadableException { }
@Override public void handleReturnValue( @Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException,HttpMessageNotWritableException { }
|
相关接口的实现类总览
HandlerMethodArgumentResolver实现类
实现类 |
说明 |
RequestParamMethodArgumentResolver |
支持带有@RequestParam注解的参数或带有MultipartFile类型的参数 |
RequestParamMapMethodArgumentResolver |
支持带有@RequestParam注解的参数 && @RequestParam注解的属性value存在 && 参数类型是实现Map接口的属性 |
PathVariableMethodArgumentResolver |
支持带有@PathVariable注解的参数 且如果参数实现了Map接口,@PathVariable注解需带有value属性 |
MatrixVariableMethodArgumentResolver |
支持带有@MatrixVariable注解的参数 且如果参数实现了Map接口,@MatrixVariable注解需带有value属性 |
RequestResponseBodyMethodProcessor |
本章已分析过 |
ServletRequestMethodArgumentResolver |
参数类型是实现或继承或是WebRequest、ServletRequest、MultipartRequest、HttpSession、Principal、Locale、TimeZone、InputStream、Reader、HttpMethod这些类。(这就是为何我们在Controller中的方法里添加一个HttpServletRequest参数,Spring会为我们自动获得HttpServletRequest对象的原因) |
ServletResponseMethodArgumentResolver |
参数类型是实现或继承或是ServletResponse、OutputStream、Writer这些类 |
RedirectAttributesMethodArgumentResolver |
参数是实现了RedirectAttributes接口的类 |
HttpEntityMethodProcessor |
参数类型是HttpEntity |
HandlerMethodReturnValueHandler实现类
实现类 |
说明 |
ModelAndViewMethodReturnValueHandler |
返回值类型是ModelAndView或其子类 |
ModelMethodProcessor |
返回值类型是Model或其子类 |
ViewMethodReturnValueHandler |
返回值类型是View或其子类 |
HttpHeadersReturnValueHandler |
返回值类型是HttpHeaders或其子类 |
ModelAttributeMethodProcessor |
返回值有@ModelAttribute注解 |
ViewNameMethodReturnValueHandler |
返回值是void或String |
接口总览小结
从名字我们也看的出来
- Resolver结尾的是实现了HandlerMethodArgumentResolver接口的类
- Handler结尾的是实现了HandlerMethodReturnValueHandler接口的类
- Processor结尾的是实现了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler的类
来源
https://www.cnblogs.com/fangjian0423/p/springMVC-request-param-analysis.html