中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring?Boot數據響應問題實例分析

發布時間:2022-03-14 15:48:47 來源:億速云 閱讀:222 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“Spring Boot數據響應問題實例分析”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Spring Boot數據響應問題實例分析”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

    前言

    響應頁面指的是我們如何發送一個請求,跳轉到指定頁面。將會在后面的視圖解析中說明。 響應頁面常見于開發單體應用。 響應數據常見于開發前后端分離的應用。后端代碼主要用來接收請求。前端頁面給我們發送過來請求,給前端響應json數據。或者給前端響應xml、圖片、音視頻數據。

    在前后端分離開發過程中,后端一般會將數據集封裝成一個JSON對象響應給前端 ,一般只需要標準ResponseBody即可給前端返回數據

    1、響應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.3.4.RELEASE</version>
        <scope>compile</scope>
    </dependency>

    控制層代碼如下:引入了依賴后,給方法上標注@ResponseBody,就可以給前端自動返回JSON數據。

    @Controller
    public class ResponseTestController {
        @ResponseBody //原理就是利用返回值處理器里面消息轉換器進行處理
        @GetMapping("/test/person")
        public Person getPerson(){
            Person person = new Person();
            person.setAge(28);
            person.setBirth(new Date());
            person.setUserName("zhangsan");
            return person;
        }
    
    }

    測試:

    Spring?Boot數據響應問題實例分析

    2、原理解析

    • 返回值處理器判斷是否支持這種類型返回值supportsReturnType

    • 返回值處理器調用handleReturnValue進行處理

    • RequestResponseBodyMethodProcessor可以處理返回值標了@ResponseBody注解的。

      • 內容協商(瀏覽器默認會以請求頭的方式告訴服務器他能接受什么樣的內容類型)

      • 服務器最終根據自己自身的能力,決定服務器能生產出什么樣內容類型的數據,

      • SpringMVC會挨個遍歷所有容器底層的HttpMessageConverter,看誰能處理?(也就是把對象轉換成為json數據)

      • 得到MappingJackson2HttpMessageConverter消息轉換器可以將對象寫為json

      • 利用MappingJackson2HttpMessageConverter將對象轉為json再寫出去。

      • 利用MessageConverters進行處理將數據寫為json

    SpringMVC到底支持哪些返回值

    • ModelAndView //包含數據和頁面

    • Model

    • View

    • ResponseEntity

    • ResponseBodyEmitter

    • StreamingResponseBody

    • HttpEntity

    • HttpHeaders

    • Callable //異步

    • DeferredResult

    • ListenableFuture

    • CompletionStage

    • WebAsyncTask

    • 有 @ModelAttribute 且為對象類型的

    • @ResponseBody 注解 ---> RequestResponseBodyMethodProcessor;處理器//即在方法上或者類上是否標注@ResponseBody

    HTTPMessageConverter原理

    MessageConverter規范

    Spring?Boot數據響應問題實例分析

    HttpMessageConverter:看是否支持將 此 Class類型的對象,轉為MediaType類型的數據。 例子:CanWrite將Person對象轉為JSON。canRead或者 JSON轉為Person

    默認的MessageConverter

    Spring?Boot數據響應問題實例分析

    • 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轉換的)

    3、內容協商

    3.1、概述

    根據客戶端接收能力不同【有的只接收xml,有的只接收json】,返回不同媒體類型的數據。比如返回xml數據給前

    引入支持XML依賴:

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

    重新編譯該項目運行 ,返回了xml數據

    Spring?Boot數據響應問題實例分析

    3.2、postman分別測試返回json和xml

    在上面的測試中,此時如果我用postman發送相同的請求,則得到的是json數據,為啥同樣的請求,方式不一樣,返回的數據不一樣呢。原因就是請求頭中規定的數據響應先后順序

    查看請求頭

    Spring?Boot數據響應問題實例分析

    內容協商Accept中,瀏覽器具備什么類型數據的接收能力,可以看到xml數據是優先被接收的。

    可用Postman軟件分別測試返回json和xml:只需要改變請求頭中Accept字段(application/json、application/xml)。Http協議中規定的,告訴服務器本客戶端可以接收的數據類型

    Spring?Boot數據響應問題實例分析

    3.3、開啟瀏覽器參數方式內容協商功能

    為了方便內容協商,開啟基于請求參數的內容協商功能。

    spring:
        contentnegotiation:
          favor-parameter: true  #開啟請求參數內容協商模式

    發請求:

    • json類型: http://localhost:8080/test/person?format=json

    • xml類型:http://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

    5.1、概述

    實現多協議數據兼容。json、xml、x-guigu

    • @ResponseBody 響應數據出去 調用 RequestResponseBodyMethodProcessor 處理

    • Processor 處理方法返回值。通過 MessageConverter 處理

    • 所有 MessageConverter 合起來可以支持各種媒體類型數據的操作(讀、寫)

    • 內容協商找到最終的 messageConverter;

    要自定義SpringMVC的什么功能,即通過一個入口給容器中添加一個 WebMvcConfigurer

    假設你想基于自定義請求參數的自定義內容協商功能。換句話,在地址欄輸入http://localhost:8080/test/person?format=gg返回數據,跟http://localhost:8080/test/person且請求頭參數`Accept:application/x-guigu`的返回自定義協議數據的一致。

    演示

    通過上文分析,我們只需要實現WebMvcConfigurer接口,并實現了configureMessageConverters方法,就可以達到自定義消息轉換器的目的。例如,我不想用jackson了,想用fastjson的消息轉換器,我們可以添加fastjson相關的MessageConverter就可以了

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
            FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
            List<MediaType> fastMediaTypes = new ArrayList<>();
            fastMediaTypes.add(MediaType.TEXT_HTML);
            fastMediaTypes.add(MediaType.APPLICATION_JSON);
            fastConverter.setSupportedMediaTypes(fastMediaTypes);
            FastJsonConfig fastJsonConfig = new FastJsonConfig();
            fastJsonConfig.setSerializerFeatures(
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteDateUseDateFormat);
            SerializeConfig serializeConfig = SerializeConfig.globalInstance;
            serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
            serializeConfig.put(Long.class, ToStringSerializer.instance);
            serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
            fastJsonConfig.setSerializeConfig(serializeConfig);
            fastConverter.setFastJsonConfig(fastJsonConfig);
            converters.add(fastConverter);
        }
    }

    測試

    @Data
    public class Person {
        private String userName;
        private Integer age;
        //使用fastjson的注解進行轉換
        @JSONField(format = "yyyy-MM-dd")
        private Date birth;
        private Pet pet;
    }

    Spring?Boot數據響應問題實例分析

    5.2、自定義的Converter

    除此之外,這些都是默認的,我們可以進行擴展,如下實現自定義的設置轉化,如下,利用這個代碼:

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

    測試

    @Configuration(proxyBeanMethods = false)
    public class WebConfig {
        @Bean
        public WebMvcConfigurer webMvcConfigurer(){
            return new WebMvcConfigurer() {
    
                @Override
                public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
                    converters.add(new GuiguMessageConverter());
                }
            }
        }
    }
    /**
     * 自定義的Converter
     */
    public class GuiguMessageConverter 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-guigu
         * @return
         */
        @Override
        public List<MediaType> getSupportedMediaTypes() {
            return MediaType.parseMediaTypes("application/x-guigu");
        }
    
        @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());
        }
    }

    測試:

    import java.util.Date;
    
    @Controller
    public class ResponseTestController {
    
        /**
         * 1、瀏覽器發請求直接返回 xml    [application/xml]        jacksonXmlConverter
         * 2、如果是ajax請求 返回 json   [application/json]      jacksonJsonConverter
         * 3、如果硅谷app發請求,返回自定義協議數據  [appliaction/x-guigu]   xxxxConverter
         *          屬性值1;屬性值2;
         *
         * 步驟:
         * 1、添加自定義的MessageConverter進系統底層
         * 2、系統底層就會統計出所有MessageConverter能操作哪些類型
         * 3、客戶端內容協商 [guigu--->guigu]
         *
         * 作業:如何以參數的方式進行內容協商
         * @return
         */
        @ResponseBody  //利用返回值處理器里面的消息轉換器進行處理
        @GetMapping(value = "/test/person")
        public Person getPerson(){
            Person person = new Person();
            person.setAge(28);
            person.setBirth(new Date());
            person.setUserName("zhangsan");
            return person;
        }
    }

    日后開發要注意,有可能我們添加的自定義的功能會覆蓋默認很多功能,導致一些默認的功能失效。

    讀到這里,這篇“Spring Boot數據響應問題實例分析”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    柘荣县| 云南省| 通城县| 托克逊县| 右玉县| 隆林| 南陵县| 台中市| 炉霍县| 金阳县| 南通市| 宜兰市| 湘乡市| 通渭县| 嘉善县| 红河县| 元氏县| 老河口市| 芒康县| 桦川县| 开化县| 龙门县| 唐山市| 大荔县| 竹北市| 隆德县| 渭南市| 石屏县| 山东省| 建德市| 武邑县| 垣曲县| 新营市| 黎川县| 佛教| 台江县| 汉寿县| 阿拉尔市| 自贡市| 霞浦县| 三穗县|