SpringBoot内容协商机制

1、是什么?

SpringBoot内容协商机制是一种实现了内容协商(Content Negotiation)的Web服务器,它可以根据客户端请求的不同,将响应返回给客户端。

在传统的Web服务器中,如果客户端请求的URL与服务器上的URL不一致,服务器就会返回一个错误响应,告诉客户端所请求的URL不存在或者不合法。而SpringBoot内容协商机制则可以根据客户端请求的URL和服务器上的规则,动态地将响应返回给客户端,使得客户端可以成功地获取到所请求的数据。

SpringBoot内容协商机制的实现,可以使得服务器的负载减轻,提高服务器的可扩展性和可维护性,同时也可以提高客户端的响应速度和用户体验。

2、能干啥?

SpringBoot内容协商机制可以实现以下功能:

1、根据URL的不同,将响应返回给客户端;
2、动态地将响应返回给客户端,使得客户端可以成功地获取到所请求的数据;
3、提高服务器的负载能力,提高服务器的可扩展性和可维护性;
4、提高客户端的响应速度和用户体验。
5、根据响应头的“Accept”字段的不同,选择不同的处理方式;
6、......
总之,SpringBoot内容协商机制可以帮助Web服务器更好地处理不同来源的数据,提高服务的质量和可靠性。

3、怎么玩?

首先明确一下,SpringBoot默认是以JSON形式处理数据

(1) 基于请求头Accept的内容协商机制(SpringBoot默认开启)

例如:当我们请求头携带Accept:applicatiom/json时服务端会给我们返回json数据
image

当我们请求头携带Accept:applicatiom/xml时服务端会给我们返回xml数据
image

(2) 基于请求参数的内容协商机制(需要手动开启)

例如:发送请求 http://localhost:8080/json?format=json ,优先返回 json 类型数据

当然想要实现基于请求参数的内容协商,需要进行以下几个配置

1.导入依赖

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

2.加入注解

@JacksonXmlRootElement // 支持写出xml文档
@Data
@AllArgsConstructor
public class User {

    private Integer id;
    private String name;
    private String email;
}

3.编写配置

spring:
  mvc:
    contentnegotiation:
      favor-parameter: true # 开启基于请求参数的内容协商功能。 默认参数名:format。 默认此功能不开启
      parameter-name: ly # 指定内容协商时使用的参数名。默认是 format

接下来就会有如下的效果了
json:
image

xml:
image

4、如何自定义内容返回?

例如:增加yaml返回支持,我想实现一个返回yaml格式的内容协商机制

(1) 导入依赖
<dependency>
	<groupId>com.fasterxml.jackson.dataformat</groupId>
	<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
(2) 添加配置
spring:
  mvc:
    contentnegotiation:
      favor-parameter: true # 开启基于请求参数的内容协商功能。 默认参数名:format。 默认此功能不开启
      parameter-name: ly # 指定内容协商时使用的参数名。默认是 format
      media-types:
        yaml: application/yaml # 添加一种新的媒体配置
(3) 自定义一个HttpMessageConverter
package com.ly.component;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import com.ly.entity.User;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
 * @author ly (个人博客:https://www.cnblogs.com/ybbit)
 * @date 2023-06-22  20:49
 * @tags 喜欢就去努力的争取
 */
public class YamlHttpMessageConverter extends AbstractHttpMessageConverter {

    private ObjectMapper objectMapper = null;

    public YamlHttpMessageConverter() {
        super(new MediaType("application", "yaml", StandardCharsets.UTF_8));
        var factory = new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);
        this.objectMapper = new ObjectMapper(factory);
    }

    @Override
    protected boolean supports(Class clazz) {
        // 只要是对象类型都支持
        return true;
    }

    /**
     * 读数据的规则
     *
     * @param clazz
     * @param inputMessage
     * @return
     * @throws IOException
     * @throws HttpMessageNotReadableException
     */
    @Override
    protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        User user = null;
        try (InputStream is = inputMessage.getBody()) {
            ObjectReader objectReader = this.objectMapper.readerFor(clazz);
            user = objectReader.readValue(is, User.class);
            System.out.println("user = " + user);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return user;
    }

    /**
     * 写数据的规则
     *
     * @param methodReturnValue
     * @param outputMessage
     * @throws IOException
     * @throws HttpMessageNotWritableException
     */
    @Override
    protected void writeInternal(Object methodReturnValue, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        try (OutputStream os = outputMessage.getBody()) {
            this.objectMapper.writeValue(os, methodReturnValue);
        }
    }
}

image

posted @ 2023-06-22 22:23  我也有梦想呀  阅读(24)  评论(0编辑  收藏  举报