返回值处理:将Controller中的方法在执行完成后,返回值处理器要将返回的类型转为前端需要的类型,如方法上加了@ResponseBody,就需要将Person转为JSON。
@ResponseBody
@GetMapping("/test/person")
public Person getPerson(){
Person person = new Person();
person.setAge(11);
person.setBirth(new Date());
person.setUserName("zhangsan");
return person;
}
1.1、jackson.jar+@ResponseBody
org.springframework.boot
spring-boot-starter-web
上面的web场景自动引入了json场景
org.springframework.boot
spring-boot-starter-json
2.3.4.RELEASE
compile
底层具体的依赖如下,框架已经帮忙引入, 自己只需要导入spring-boot-starter-web即可。
返回值处理器:
之前的流程在请求参数解析中,返回值在invokeAndHandle中
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = this.invokeForRequest(webRequest, mavContainer, providedArgs);
this.setResponseStatus(webRequest);
if (returnValue == null) {
if (this.isRequestNotModified(webRequest) || this.getResponseStatus() != null || mavContainer.isRequestHandled()) {
this.disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
//执行完目标方法之后,进行返回值处理
this.returnValueHandlers.handleReturnValue(returnValue, this.getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception var6) {
if (logger.isTraceEnabled()) {
logger.trace(this.formatErrorForReturnValue(returnValue), var6);
}
throw var6;
}
}
this.returnValueHandlers.handleReturnValue();中进行返回值处理。
returnValueHandlers是HandlerMethodReturnValueHandlerComposite类型,下图是所有的返回值处理器。
handleReturnValue方法的内部实现:
HandlerMethodReturnValueHandlerComposite类
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = this.selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
} else {
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
选择好对应的返回值处理器之后,调用handler.handleReturnValue进入到下面方法:
以处理@ResponseBody返回值类型的RequestResponseBodyMethodProcessor类为例
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// Try even with null return value. ResponseBodyAdvice could get involved.
// 使用消息转换器进行写出操作
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
返回值解析器原理
- selectHandler中,返回值处理器判断是否支持这种类型返回值 supportsReturnType
- 返回值处理器调用 handleReturnValue 进行处理
- RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。
- 利用MessageConverters将数据写为JSON
-
内容协商(浏览器默认会以请求头的方式告诉服务器他能接受的内容类型)
-
服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据,
-
SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter ,看谁能处理?
-
得到MappingJackson2HttpMessageConverter可以将对象写为json
-
利用MappingJackson2HttpMessageConverter将对象转为json再写出去。
-
-
- 利用MessageConverters将数据写为JSON
ModelAndView Model View ResponseEntity ResponseBodyEmitter StreamingResponseBody HttpEntity HttpHeaders Callable DeferredResult ListenableFuture CompletionStage WebAsyncTask 有 @ModelAttribute 且为对象类型的 @ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;1.3、HTTPMessageConverter原理 1.3.1 MessageConverter规范
HttpMessageConverter: 看是否支持将 此 Class类型的对象,转为MediaType类型的数据。
例子:Person对象转为JSON。或者 JSON转为Person
1.3.2 默认的MessageConverter0 - 只支持Byte类型的
1 - String
2 - String
3 - Resource
4 - ResourceRegion
5 - DOMSource.class SAXSource.class) StAXSource.class StreamSource.class Source.class
6 - MultiValueMap
7 - true
8 - true
9 - 支持注解方式xml处理的。
最终 MappingJackson2HttpMessageConverter 把对象转为JSON(利用底层的jackson的objectMapper转换的)
2、内容协商(writeWithMessageConverters的具体实现)根据客户端接受能力,返回不同媒体类型的数据。
2.1 引入xml依赖2.2 postman分别测试返回json和xmlcom.fasterxml.jackson.dataformat jackson-dataformat-xml
只需要改变请求头中Accept字段。Http协议中规定的,告诉服务器本客户端可以接收的数据类型。
2.4 内容协商原理1、判断当前响应头是否已经有确定的媒体类型。MediaType
2、获取客户端(PostMan、浏览器)支持接收的内容类型。(获取客户端Accept请求头字段)【application/xml】
List acceptableTypes;
try {
acceptableTypes = this.getAcceptableMediaTypes(request);
}
以上图PostMan为例,此时的acceptableTypes为application/xml
3、遍历循环所有当前系统的MessageConverter,看哪些MessageConverter支持操作Controller方法的返回类型,如Person类型。
4、找到支持操作Person类型的converter,把converter支持转化的媒体类型统计出来
ListproducibleTypes = this.getProducibleMediaTypes(request, valueType, (Type)targetType);
5、客户端需要【application/xml】,服务端能处理的类型producibleTypes :如下
6、进行内容协商的最佳匹配媒体类型,使用双层循环,找到服务器能实现客户端指定内容类型的类型。因为客户端可能允许接受多种类型,所有会选择最佳匹配媒体类型。
ListmediaTypesToUse = new ArrayList(); Iterator var15 = acceptableTypes.iterator();//客户端允许接受的类型迭代器 MediaType mediaType; while(var15.hasNext()) { mediaType = (MediaType)var15.next(); //服务器可以返回的类型迭代器 Iterator var17 = producibleTypes.iterator(); while(var17.hasNext()) { MediaType producibleType = (MediaType)var17.next(); if (mediaType.isCompatibleWith(producibleType)) { mediaTypesToUse.add(this.getMostSpecificMediaType(mediaType, producibleType)); } } }
7、用支持 将对象转为 最佳匹配媒体类型 的converter。调用它将他转化。
if (selectedMediaType != null) {
//在上一步的双层遍历结果中,选择一个最终确定的类型
selectedMediaType = selectedMediaType.removeQualityValue();
Iterator var23 = this.messageConverters.iterator();
//遍历所有messageConverters,看谁可以转化此类型
while(var23.hasNext()) {
converter = (HttpMessageConverter)var23.next();
genericConverter = converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter)converter : null;
if (genericConverter != null) {
if (((GenericHttpMessageConverter)converter).canWrite((Type)targetType, valueType, selectedMediaType)) {
break label183;
}
} else if (converter.canWrite(valueType, selectedMediaType)) {
break label183;
}
}
}
总结:先看客户端可以接受哪些类型,再看服务器端哪些MessageConverter可以处理Controller中方法的返回值类型(如上述方法的Person)。根据上一步的MessageConverter结果,看他们可以转化为哪些类型。再使用双层循环,循环遍历客户端接受的类型和服务器端能处理的类型,得到最终服务器能处理的客户端接受的哪些类型。最后,找到能处理最佳匹配类型(上一步的类型集合中根据权重排序选出最佳)的MessageConverter,进行转化。



