HandlerMethodArgumentResolver(三):基于消息转换器的参数处理器【享学Spring MVC】 (2)

此处理器用于解析@RequestPart参数类型,它和多部分文件上传有关。关于Spring MVC中的文件上传,此处就不便展开了。后面有个专题专门讲解Spring MVC中的上传、下载~

AbstractMessageConverterMethodProcessor(重点)

命名为Processor说明它既能处理入参,也能处理返回值,当然本文的关注点是方法入参(和HttpMessageConverter相关)。

请求body体一般是一段字符串/字节流,查询参数可以看做URL的一部分,这两个是位于请求报文的不同地方。

表单参数可以按照一定格式放在请求体中,也可以放在url上作为查询参数。

响应body体则是response返回的具体内容,对于一个普通的html页面,body里面就是页面的源代码。对于HttpMessage响应体里可能就是个json串(但无强制要求)。

响应体一般都会结合Content-Type一起使用,告诉客户端只有知道这个头了才知道如何渲染。

AbstractMessageConverterMethodProcessor源码稍显复杂,它和Http协议、内容协商有很大的关联:

// @since 3.1 public abstract class AbstractMessageConverterMethodProcessor extends AbstractMessageConverterMethodArgumentResolver implements HandlerMethodReturnValueHandler { // 默认情况下:文件们后缀是这些就不弹窗下载 private static final Set<String> WHITELISTED_EXTENSIONS = new HashSet<>(Arrays.asList("txt", "text", "yml", "properties", "csv", "json", "xml", "atom", "rss", "png", "jpe", "jpeg", "jpg", "gif", "wbmp", "bmp")); private static final Set<String> WHITELISTED_MEDIA_BASE_TYPES = new HashSet<>(Arrays.asList("audio", "image", "video")); private static final List<MediaType> ALL_APPLICATION_MEDIA_TYPES = Arrays.asList(MediaType.ALL, new MediaType("application")); private static final Type RESOURCE_REGION_LIST_TYPE = new ParameterizedTypeReference<List<ResourceRegion>>() { }.getType(); // 用于给URL解码 decodingUrlPathHelper.decodeRequestString(servletRequest, filename); private static final UrlPathHelper decodingUrlPathHelper = new UrlPathHelper(); // rawUrlPathHelper.getOriginatingRequestUri(servletRequest); private static final UrlPathHelper rawUrlPathHelper = new UrlPathHelper(); static { rawUrlPathHelper.setRemoveSemicolonContent(false); rawUrlPathHelper.setUrlDecode(false); } // 内容协商管理器 private final ContentNegotiationManager contentNegotiationManager; // 扩展名的内容协商策略 private final PathExtensionContentNegotiationStrategy pathStrategy; private final Set<String> safeExtensions = new HashSet<>(); protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters) { this(converters, null, null); } // 可以指定内容协商管理器ContentNegotiationManager protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable ContentNegotiationManager contentNegotiationManager) { this(converters, contentNegotiationManager, null); } // 这个构造器才是重点 protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters, @Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice) { super(converters, requestResponseBodyAdvice); // 可以看到:默认情况下会直接new一个 this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager()); // 若管理器里有就用管理器里的,否则new PathExtensionContentNegotiationStrategy() this.pathStrategy = initPathStrategy(this.contentNegotiationManager); // 用safeExtensions装上内容协商所支持的所有后缀 // 并且把后缀白名单也加上去(表示是默认支持的后缀) this.safeExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions()); this.safeExtensions.addAll(WHITELISTED_EXTENSIONS); } // ServletServerHttpResponse是对HttpServletResponse的包装,主要是对响应头进行处理 // 主要是处理:setContentType、setCharacterEncoding等等 // 所以子类若要写数据,就调用此方法来向输出流里写吧~~~ protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequest) { HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); Assert.state(response != null, "No HttpServletResponse"); return new ServletServerHttpResponse(response); } // 注意:createInputMessage()方法是父类提供的,对HttpServletRequest的包装 // 主要处理了:getURI()、getHeaders()等方法 // getHeaders()方法主要是处理了:getContentType()... protected <T> void writeWithMessageConverters(T value, MethodParameter returnType, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); writeWithMessageConverters(value, returnType, inputMessage, outputMessage); } // 这个方法省略 // 这个方法是消息处理的核心之核心:处理了contentType、消息转换、内容协商、下载等等 // 注意:此处并且还会执行RequestResponseBodyAdviceChain,进行前后拦截 protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { ... } }

本类的核心是各式各样的HttpMessageConverter消息转换器,因为最终的write都是交给它们去完成。
此抽象类里,它完成了内容协商~

关于内容协商的详解,强烈建议你点击 这里 。另外 这篇文章也深入的分析了AbstractMessageConverterMethodProcessor这个类,可以作为参考。

既然父类都已经完成了这么多事,那么子类自然就非常的简单的。看看它的两个具体实现子类:

RequestResponseBodyMethodProcessor

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywsgx.html