侧边栏壁纸
博主头像
coydone博主等级

记录学习,分享生活的个人站点

  • 累计撰写 306 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

数据响应与内容协商

coydone
2022-04-05 / 0 评论 / 0 点赞 / 327 阅读 / 4,420 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-04-24,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

数据响应

响应JSON

使用 jackson.jar+@ResponseBody 响应json数据。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
web场景自动引入了json场景
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
    <version>2.5.3</version>
    <scope>compile</scope>
</dependency>

给前端自动返回json数据;

返回值解析器

try {
    this.returnValueHandlers.handleReturnValue(
        returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}

@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
                              ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
    if (handler == null) {
        throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
    }
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

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);

    // 使用消息转换器进行写出操作
    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

返回值解析器原理

(1)返回值处理器判断是否支持这种类型返回值supportsReturnType。

(2)返回值处理器调用 handleReturnValue 进行处理。

(3)RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。

  • 利用 MessageConverters 进行处理将数据写为json。

    • 1、内容协商(浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型)
  • 2、服务器最终根据自己自身的能力,决定服务器能生产出什么样内容类型的数据,

    • 3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter(消息转换器),看谁能处理。

      • 1、得到MappingJackson2HttpMessageConverter可以将对象写为json。
    • 2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。

SpringMVC支持的返回值

ModelAndView
Model
View
ResponseEntity 
ResponseBodyEmitter
StreamingResponseBody
HttpEntity
HttpHeaders
Callable
DeferredResult
ListenableFuture
CompletionStage
WebAsyncTask
有 @ModelAttribute 且为对象类型的
@ResponseBody 注解 ---> RequestResponseBodyMethodProcessor

HTTPMessageConverter原理

MessageConverter规范

HttpMessageConverter:看是否支持将此 Class类型的对象,转为MediaType类型的数据。

例子:Person对象转为JSON。或者 JSON转为Person。

默认的MessageConverter

0 - 只支持Byte类型
1 - String
2 - String
3 - Resource
4 - ResourceRegion
5 - DOMSource.class\SAXSource.class\StAXSource.classStreamSource.class\Source.class
6 - MultiValueMap
7 - true 
8 - true
9 - 支持注解方式xml处理的。

最终 MappingJackson2HttpMessageConverter 把对象转为JSON(利用底层的jackson的objectMapper转换的)。

内容协商

根据客户端接收能力不同,返回不同媒体类型的数据。

1、引入xml依赖

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

2、postman分别测试返回json和xml

只需要改变请求头中Accept字段。Http协议中规定的,告诉服务器本客户端可以接收的数据类型。

3、开启浏览器参数方式内容协商功能

为了方便内容协商,开启基于请求参数的内容协商功能。

spring:
  contentnegotiation:
	favor-parameter: true  #开启请求参数内容协商模式

发请求: http://localhost:8080/test/person?format=jsonhttp://localhost:8080/test/person?format=xml

确定客户端接收什么样的内容类型;

1、Parameter策略优先确定是要返回json数据(获取请求头中的format的值)

2、最终进行内容协商返回给客户端json即可。

4、内容协商原理

①判断当前响应头中是否已经有确定的媒体类型。(MediaType)

②获取客户端(PostMan、浏览器)支持接收的内容类型。(获取客户端Accept请求头字段)【application/xml】

  • contentNegotiationManager内容协商管理器,默认使用基于请求头的策略。

  • HeaderContentNegotiationStrategy 确定客户端可以接收的内容类型。

③遍历循环所有当前系统的 MessageConverter,看谁支持操作这个对象(Person)

④找到支持操作Person的converter,把converter支持的媒体类型统计出来。

⑤客户端需要【application/xml】。服务端能力【10种、json、xml】

⑥进行内容协商的最佳匹配媒体类型

⑦用支持将对象转为最佳匹配媒体类型的converter。调用它进行转化。

导入了jackson处理xml的包,xml的converter就会自动进来。

WebMvcConfigurationSupport
    jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);

if (jackson2XmlPresent) {
    Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
    if (this.applicationContext != null) {
        builder.applicationContext(this.applicationContext);
    }
    messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
}

5、自定义 MessageConverter

实现多协议数据兼容。json、xml、x-xxx

@ResponseBody 响应数据出去调用 RequestResponseBodyMethodProcessor 处理。

1、Processor 处理方法返回值。通过 MessageConverter 处理。

2、所有 MessageConverter 合起来可以支持各种媒体类型数据的操作(读、写)。

3、内容协商找到最终的 MessageConverter。

一个入口给容器中添加一个 WebMvcConfigurer。

@Bean
public WebMvcConfigurer webMvcConfigurer(){
    return new WebMvcConfigurer() {
        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        }
    }
}
0

评论区