最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot自定義內容協(xié)商的實現(xiàn)

 更新時間:2024年09月26日 10:05:32   作者:一只懶魚a  
在Spring Boot中,內容協(xié)商是一種機制,它允許服務器根據客戶端的請求選擇返回不同的表示形式,本文就來詳細的介紹一下SpringBoot自定義內容協(xié)商的實現(xiàn),感興趣的可以了解一下

現(xiàn)象演示

假設有一個需求是根據終端的不同,返回不同形式的數(shù)據,比如 PC 端需要以 HTML 格式返回數(shù)據,APP、小程序端需要以 JSON 格式返回數(shù)據。這時我們是 coding 幾個相似的接口?還是在一個接口里面做復雜判斷處理?兩個方案貌似都不理想,一旦需求改動,維護的東西就比較多,這時候我們利用 SpringBoot 的內容協(xié)商功能,就可以很好的簡化邏輯,案例演示如下:

創(chuàng)建實體類Dog

public class Dog {
    private String name;

    public Dog() {

    }

    public Dog(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                '}';
    }
}

創(chuàng)建Controller

@RestController
@RequestMapping("/content_negotiation")
public class ContentNegotiationController {

    @GetMapping("/simple")
    public Dog getDog() {
        return new Dog("wangcai");
    }
}

開啟參數(shù)形式內容協(xié)商

spring:
  mvc:
    contentnegotiation:
      favor-parameter: true

添加POM依賴 (讓 SpringBoot 有返回相關格式數(shù)據的能力) 

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

請求及響應

返回 JSON 格式的數(shù)據

返回 HTML 格式的數(shù)據

源碼解析

HandlerMethodReturnValueHandlerComposite#handleReturnValue

總體分為兩步:

  • 選擇一個 HandlerMethodReturnValueHandler 來處理當前返回值
  • 處理返回值

選擇 HandlerMethodReturnValueHandler

SpringBoot 會手動注冊的一些 HandlerMethodReturnValueHandler ,一共有15 個 (SpringBoot 版本 2.6.13),我們主要關注 RequestResponseBodyMethodProcessor 這個handler。

RequestResponseBodyMethodProcessor#supportsReturnType

如果接口方法含有 @ResponseBody 注解,或者相關Controller上含有 @ResponseBody 注解,則RequestResponseBodyMethodProcessor 都可以處理

處理返回值

writeWithMessageConverters 方法大概有以下幾個步驟:

  • 獲取 acceptableTypes
  • 獲取 producibleTypes
  • 獲取 mediaTypesToUse
  • 給 mediaTypesToUse 排序
  • 獲取 selectedMediaType
  • 寫出數(shù)據

獲取 acceptableTypes

分為兩個分支:

  • Response 是否指定 Content-Type,并且 Content-Type 的類型不是 */*,則直接跳轉到步驟6 (寫出數(shù)據)
  • 獲取 acceptableTypes

AbstractMessageConverterMethodProcessor#getAcceptableMediaTypes

默認情況下,只有 HeaderContentNegotiationStrategy ,因為我們在現(xiàn)象演示的時候,將屬性 spring.mvc.contentnegotiation.favor-parameter 設置為 true,所以多出來一個 ParameterContentNegotiationStrategy 。如果 ParameterContentNegotiationStrategy 的 resolveMediaTypes 方法的返回值不為 null 且不為 MEDIA_TYPE_ALL_LIST,則以 ParameterContentNegotiationStrategy 的 resolveMediaTypes 方法返回值為準,即 ParameterContentNegotiationStrategy 的優(yōu)先級高于 HeaderContentNegotiationStrategy

ParameterContentNegotiationStrategy#resolveMediaTypes

getMediaTypeKey

默認情況下,parameterName 的值為 format

修改 parameterName 默認值

spring:
  mvc:
    contentnegotiation:
      favor-parameter: true
      parameter-name: custom_format

resolveMediaTypeKey

就是以 parameterName 對應的屬性值為 key, 從 URL 中獲取 value,再以該 value 為 mediaTypeKey 從一個 map (mediaTypes)中獲取 MediaType

mediaTypes的初始賦值

WebMvcConfigurationSupport#mvcContentNegotiationManager

因為我們在現(xiàn)象演示的時候添加了相關POM依賴,所有 mediaTypes 的 內容如下所示:

即默認情況下,format 的參數(shù)值含義如下 :

  • json:acceptableTypes 為 [ application/json ]
  • xml:acceptableTypes 為 [ application/xml ]
  • 其他:acceptableTypes 為 [ */*]

也可以自定義key,配置如下所示,這時候如果參數(shù)攜帶 custom_format=lanyu,系統(tǒng)也會返回 application/xml 格式的數(shù)據

spring:
  mvc:
    contentnegotiation:
      favor-parameter: true
      parameter-name: custom_format
      media-types: {lanyu : application/xml}

HeaderContentNegotiationStrategy#resolveMediaTypes

HeaderContentNegotiationStrategy 的 resolveMediaTypes 方法比較簡單,就是獲取請求頭中 Accept 的值

獲取 producibleTypes

大概分為以下幾種情況

Request 域的 HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE 是否為 null

屬性值不為 null:返回指定的 mediaTypes

屬性值為 null

  • 是否存在 messageConverters 的 canWrite 方法返回 true
    • 存在:相關 messageConverters 的 getSupportedMediaTypes 方法返回值的集合
    • 不存在:MediaType.ALL

獲取 mediaTypesToUse

主要通過 isCompatibleWith 方法判斷  acceptableType 和 producibleType 是不是兼容的,主要有以下幾種情況 :

producibleType 為  null:返回false

producibleType 不為null

  • acceptableType 為 */* 或  producibleType為 */* :返回true
  • acceptableType 和 producibleType 都不為 */*
    • acceptableType 和 producibleType 的 type 一致
      • acceptableType 和 producibleType 的 subtype 一致 : 返回true
      • acceptableType 和 producibleType 的 subtype 不一致
        • acceptableType 或 producibleType 的 subtype 的 isWildcardSubtype 方法返回true
          • acceptableType 或 producibleType 的 subtype 為 *:返回true
          • acceptableType 的 subtype 以 *+ 開頭,并且 acceptableType 的后綴與producibleType一致:返回true
          • producibleType 的 subtype 以 *+ 開頭,并且 producibleType 的后綴與acceptableType 一致:返回true
          • 其他情況:返回false
        • acceptableType 與 producibleType 的 subtype 的 isWildcardSubtype 方法都返回false:返回false
    • acceptableType 和 producibleType 的 type 不一致:返回false

給 mediaTypesToUse 排序

排序規(guī)則1:

  • 權重越大優(yōu)先級越高
  • 參數(shù)個數(shù)越多優(yōu)先級越高

如果排序規(guī)則1未判斷出誰的優(yōu)先級高,則使用排序規(guī)則2,排序規(guī)則2如下:

  • 權重越大優(yōu)先級越高
  • type類型不為 *
  • subtype類型不為 * 或以 *+ 開頭
  • 參數(shù)個數(shù)越多優(yōu)先級越高

獲取 selectedMediaType

遍歷上一步經過排序的 mediaTypes,如果存在一個 mediaType 滿足以下條件,則直接返回

  • type 類型不為 * ,subtype 類型不為 * 且不以 *+ 開頭
  • MediaType 為 */* 或 application/*

寫出數(shù)據

如果存在一個 HttpMessageConverter 的 canWrite 方法返回 true,則使用 HttpMessageConverter 的 write 方法寫出數(shù)據

擴展:自定義HttpMessageConverter處理自定義協(xié)議

創(chuàng)建實體類Cat

public class Cat {
    private String name;

    public Cat() {

    }

    public Cat(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }
}

創(chuàng)建自定義HttpMessageConverter

public class LanyuHttpMessageConverter implements HttpMessageConverter {

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

    @Override
    public boolean canWrite(Class clazz, MediaType mediaType) {
        if (Cat.class == clazz) {
            return true;
        }
        return false;
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return Collections.singletonList(MediaType.parseMediaType("lanyu/custom"));
    }

    @Override
    public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return null;
    }

    @Override
    public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        try {
            Cat cat = (Cat) o;
            String data = "cat = {name : " + cat.getName() + "}";

            OutputStream outputStream = outputMessage.getBody();
            outputStream.write(data.getBytes());
            outputStream.flush();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

創(chuàng)建配置類

@Configuration
public class MessageConfig implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new LanyuHttpMessageConverter());
    }
}

接口及響應

@GetMapping("/custom_protocol")
public Cat getCustomProtocolData() {
    return new Cat("tom");
}

我們也可以讓我們自定義的協(xié)議支持 URL 傳參形式,配置如下

spring:
  mvc:
    contentnegotiation:
      favor-parameter: true
      parameter-name: custom_format
      media-types: {lanyu : lanyu/custom}

到此這篇關于SpringBoot自定義內容協(xié)商的實現(xiàn)的文章就介紹到這了,更多相關SpringBoot 內容協(xié)商內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 解決InputStream.available()獲取流大小問題

    解決InputStream.available()獲取流大小問題

    這篇文章主要介紹了解決InputStream.available()獲取流大小問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • JAVA 繼承基本類、抽象類、接口介紹

    JAVA 繼承基本類、抽象類、接口介紹

    Java是一個面向對象的語言,java面向對象一般有三大特征:封裝、繼承、多態(tài)
    2013-01-01
  • 關于文件上傳MultipartBody的使用方法

    關于文件上傳MultipartBody的使用方法

    這篇文章主要介紹了關于文件上傳MultipartBody的使用方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • java圖形界面AWT編寫計算器

    java圖形界面AWT編寫計算器

    這篇文章主要為大家詳細介紹了基于java語言下圖形界面AWT編寫計算器,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 淺談hibernate急迫加載問題(多重外鍵關聯(lián))

    淺談hibernate急迫加載問題(多重外鍵關聯(lián))

    這篇文章主要介紹了淺談hibernate急迫加載問題(多重外鍵關聯(lián)),具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • Java基于LoadingCache實現(xiàn)本地緩存的示例代碼

    Java基于LoadingCache實現(xiàn)本地緩存的示例代碼

    本文主要介紹了Java基于LoadingCache實現(xiàn)本地緩存的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • SpringMVC教程之json交互使用詳解

    SpringMVC教程之json交互使用詳解

    本篇文章主要介紹了SpringMVC教程之json使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Java實現(xiàn)矩形碰撞檢測

    Java實現(xiàn)矩形碰撞檢測

    這篇文章主要為大家詳細介紹了Java實現(xiàn)矩形碰撞檢測,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • SpringCloud微服務中跨域配置的方法詳解

    SpringCloud微服務中跨域配置的方法詳解

    在使用SpringCloud實現(xiàn)微服務時,經常會碰到前端頁面訪問多個二級域名的情況,跨域是首先要解決的問題。解決這個問題,可以從兩方面入手,一種方案是在微服務各自的業(yè)務模塊中實現(xiàn),即在SpringBoot層實現(xiàn),另外一種方案就是在Gateway層實現(xiàn)
    2023-02-02
  • java算法實現(xiàn)預測雙色球中獎號碼

    java算法實現(xiàn)預測雙色球中獎號碼

    這篇文章主要介紹了java算法實現(xiàn)預測雙色球中獎號碼的相關資料,需要的朋友可以參考下
    2015-12-12

最新評論

永福县| 房山区| 寿阳县| 景德镇市| 汤原县| 禄丰县| 罗定市| 宜昌市| 金山区| 雷州市| 乐平市| 满洲里市| 东阳市| 资阳市| 县级市| 富川| 达拉特旗| 麻栗坡县| 彭阳县| 清水河县| 清流县| 乌拉特前旗| 鄯善县| 杭锦后旗| 斗六市| 宁陵县| 庐江县| 隆德县| 桑植县| 扶沟县| 奈曼旗| 诸城市| 伊通| 花莲市| 屯留县| 五原县| 乌鲁木齐县| 海盐县| 庄浪县| 郧西县| 唐海县|