160_SpringBoot_web_数据响应与内容协商

举报
alexsully 发表于 2021/09/24 09:23:15 2021/09/24
【摘要】 数据响应与内容协商

数据响应与内容协商

给前端自动返回json数据

@Controller
public class ResponseTestController {

    @ResponseBody  //利用返回值处理器里面的消息转换器进行处理
    @GetMapping(value = "/test/person")
    public Person getPerson(){
        Person person = new Person();
        person.setAge(35);
        person.setBirth(new Date());
        person.setUserName("alex");
        return person;  //json 类型{"userName":"alex","age":35,"birth":"2021-09-23T11:18:12.819+00:00","pet":null}
    }
}

1 返回值解析器

2 返回值解析器原理

1 返回值处理器判断是否支持这种类型返回值 supportsReturnType
2 返回值处理器调用 handleReturnValue 进行处理
3 RequestResponseBodyMethodProcessor 可以处理返回值标了@ResponseBody 注解的。
  1 利用 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原理

HttpMessageConverter: 看是否支持将 此 Class类型的对象,转为MediaType类型的数据。
例子:Person对象转为JSON。或者 JSON转为Person

默认的MessageConverter

0 - 只支持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转换的)

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

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

开启浏览器参数方式内容协商功能 开启基于请求参数的内容协商功能

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

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

内容协商原理

1 判断当前响应头中是否已经有确定的媒体类型。MediaType
2 获取客户端(PostMan、浏览器)支持接收的内容类型。(获取客户端Accept请求头字段)【application/xml】
contentNegotiationManager 内容协商管理器 默认使用基于请求头的策略
HeaderContentNegotiationStrategy  确定客户端可以接收的内容类型 

3 遍历循环所有当前系统的 MessageConverter,看谁支持操作这个对象(Person)
4 找到支持操作Person的converter,把converter支持的媒体类型统计出来。
5 客户端需要【application/xml】。服务端能力【10种、json、xml】

6 进行内容协商的最佳匹配媒体类型
7 用 支持 将对象转为 最佳匹配媒体类型 的converter。调用它进行转化

自定义 MessageConverter SpringMVC的什么功能。一个入口给容器中添加一个  WebMvcConfigurer
实现多协议数据兼容。json、xml、x-alex
0  @ResponseBody 响应数据出去 调用 RequestResponseBodyMethodProcessor 处理
1 Processor 处理方法返回值。通过 MessageConverter 处理
2 所有 MessageConverter 合起来可以支持各种媒体类型数据的操作(读、写)
3 内容协商找到最终的 messageConverter;

public class AlexMessageConverter implements HttpMessageConverter<Person> {

    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return clazz.isAssignableFrom(Person.class);
    }

    /**
     * 服务器要统计所有MessageConverter都能写出哪些内容类型
     *
     * application/x-alex
     * @return
     */
    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return MediaType.parseMediaTypes("application/x-alex");
    }

    @Override
    public Person read(Class<? extends Person> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    public void write(Person person, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        //自定义协议数据的写出
        String data = person.getUserName()+";"+person.getAge()+";"+person.getBirth();


        //写出去
        OutputStream body = outputMessage.getBody();
        body.write(data.getBytes());
    }
}

    @Bean
    public WebMvcConfigurer webMvcConfigurer(){
        return new WebMvcConfigurer() {

            /**
             * 自定义内容协商策略
             * @param configurer
             */
            @Override
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
                //Map<String, MediaType> mediaTypes
                Map<String, MediaType> mediaTypes = new HashMap<>();
                mediaTypes.put("json",MediaType.APPLICATION_JSON);
                mediaTypes.put("xml",MediaType.APPLICATION_XML);
                mediaTypes.put("gg",MediaType.parseMediaType("application/x-alex"));
                //指定支持解析哪些参数对应的哪些媒体类型
                ParameterContentNegotiationStrategy parameterStrategy = new ParameterContentNegotiationStrategy(mediaTypes);
//                parameterStrategy.setParameterName("ff");

                HeaderContentNegotiationStrategy headeStrategy = new HeaderContentNegotiationStrategy();

                configurer.strategies(Arrays.asList(parameterStrategy,headeStrategy));
            }

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。