Spring MVC 中 HttpMessageConverter 轉換器

Rainbow-Sea發表於2024-07-13

1. Spring MVC 中 HttpMessageConverter 轉換器

@

目錄
  • 1. Spring MVC 中 HttpMessageConverter 轉換器
  • 2. 補充:什麼是 HTTP 訊息
  • 3. 轉換器
    • 3.1 轉換器轉換的是什麼
  • 4. Spring MVC中的 AJAX 請求
  • 5. @ResponseBody 將伺服器端的 return 返回值轉化為“字串(JSON格式的字串)”再返回給客戶端
  • 6. 補充:@RestController = (@Controller + @ResponseBody )
  • 7. @RequestBody 將前端的請求體的資訊轉換Java程式中的 POJO物件
    • 7.1 MappingJackson2HttpMessageConverter 將前端提交的 JSON 格式的字串,轉換為 Java程式中的POJO物件
  • 8. RequestEntity 類
  • 9. ResponseEntity 類
  • 10. 總結:
  • 11. 最後:


2. 補充:什麼是 HTTP 訊息

HTTP 訊息其實就是 HTTP 協議。HTTP 協議包括 請求協議響應協議
以下是一份HTTP POST請求協議:

POST /springmvc/user/login HTTP/1.1																												--請求行
Content-Type: application/x-www-form-urlencoded																						--請求頭
Content-Length: 32
Host: www.example.com
User-Agent: Mozilla/5.0
Connection: Keep-Alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
                                                                                          --空白行
username=admin&password=1234																															--請求體

以下是一份HTTP GET請求協議:

GET /springmvc/user/del?id=1&name=zhangsan HTTP/1.1																				--請求行
Host: www.example.com																																			--請求頭
User-Agent: Mozilla/5.0
Connection: Keep-Alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

以下是一份HTTP響應協議:

HTTP/1.1 200 OK																																					--狀態行
Date: Thu, 01 Jul 2021 06:35:45 GMT																											--響應頭
Content-Type: text/plain; charset=utf-8
Content-Length: 12
Connection: keep-alive
Server: Apache/2.4.43 (Win64) OpenSSL/1.1.1g
                                                                                        --空白行
<!DOCTYPE html>																																					--響應體
<html>
  <head>
    <title>hello</title>
  </head>
  <body>
    <h1>Hello World!</h1>
  </body>
</html>

3. 轉換器

HttpMessageConverter Spring MVC 中非常重要的一個介面。翻譯為:HTTP訊息轉換器。

該介面下提供了很多實現類,不同的實現類有不同的轉換方式。

在這裡插入圖片描述

3.1 轉換器轉換的是什麼

轉換的是HTTP協議Java程式中的物件之間的互相轉換。請看下圖:
在這裡插入圖片描述

上圖是我們之前經常寫的程式碼。請求體中的資料是如何轉換成 user 物件的,底層實際上使用了 HttpMessageConverter 介面的其中的一個實現類 FormHttpMessageConverter

透過上圖可以看出 FormHttpMessageConverter 是負責將 請求協議轉換為 Java物件 的。


在這裡插入圖片描述

上圖的程式碼也是之前我們經常寫的,Controller 返回值看做邏輯檢視名稱,檢視解析器將其轉換成物理檢視名稱,生成檢視物件,StringHttpMessageConverter 負責將檢視物件中的 HTML 字串寫入到 HTTP協議的響應體中。最終完成響應。

透過上圖可以看出 StringHttpMessageConverter 是負責將 Java物件 轉換為響應協議 的。

透過以上內容的學習,大家應該能夠了解到 HttpMessageConverter介面是用來做什麼的了:

在這裡插入圖片描述

如上圖所示:HttpMessageConverter 介面的可以將請求協議轉換成 Java物件;也可以把 Java物件轉換為響應協議。

HttpMessageConverter 是介面,Spring MVC 幫我們提供了非常多而豐富的實現類。每個實現類都有自己不同的轉換風格。

對於我們程式設計師來說,Spring MVC 已經幫助我們寫好了,我們只需要在不同的業務場景下,選擇合適的HTTP訊息轉換器即可。

怎麼選擇呢?當然是透過 Spring MVC 為我們提供的註解,我們透過使用不同的註解來啟用不同的訊息轉換器。

我們重點牢牢把握住下面的這兩個註解,兩個類

  • 兩個註解:

@ResponseBody

@RequestBody

  • 兩個類:

ResponseEntity

RequestEntity

4. Spring MVC中的 AJAX 請求

SpringMVC+Vue3+Thymeleaf+Axios傳送一個簡單的AJAX請求。

引入 Vue 和 Axios的js檔案:

在這裡插入圖片描述

匯入相關的 jar 依賴

在這裡插入圖片描述

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rainbowsea</groupId>
    <artifactId>springmvc-008</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>


    <dependencies>
        <!--springmvc依賴-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>6.1.4</version>
        </dependency>
        <!--logback依賴-->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!--servlet依賴-->
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>6.0.0</version>
            <scope>provided</scope>
        </dependency>
        <!--thymeleaf和spring6整合的依賴-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring6</artifactId>
            <version>3.1.2.RELEASE</version>
        </dependency>

        <!--        引入jackson依賴,可以將java物件轉換為json格式字串-->
        <!--        專門負責將Java物件轉換成JSON格式字串的元件,
        當然,它也可以將JSON格式的字串轉換成Java物件-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.17.0</version>
        </dependency>
    </dependencies>

</project>

web.xml 檔案的相關配置資訊內容:

在這裡插入圖片描述

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">


    <!--    字元編碼過濾器-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--    前端控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <!--        除了 jsp 頁面其他的都走這個-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>


    <!--    新增一個過濾器,這個過濾器是springmvc提前寫好的,直接用就行了,這個過濾器可以幫助你將請求
    POST轉換成PUT請求/DELETE請求-->
    <!--    同時注意:該過濾器一定要在字元編碼過濾器後面配置,不然,先設定的話,可能會出現獲取到的請求資料是亂碼-->

    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <!--        表示任意的 請求-->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

相關 springmvc.xml 檔案配置資訊的編寫:

其中重點是:靜態資源處理、開啟註解驅動、檢視控制器對映等相關配置。

在這裡插入圖片描述

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <!--    元件掃描-->
    <context:component-scan
            base-package="com.rainbowsea.springmvc.controller,com.rainbowsea.springmvc.service"></context:component-scan>

    <!--檢視解析器-->
    <bean id="thymeleafViewResolver" class="org.thymeleaf.spring6.view.ThymeleafViewResolver">
        <property name="characterEncoding" value="UTF-8"/>
        <property name="order" value="1"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring6.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">
                        <property name="prefix" value="/WEB-INF/thymeleaf/"/>
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML"/>
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>


    <!--    檢視控制器對映-->
    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>

    <!--    開啟註解驅動-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!--    靜態資源處理-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>


</beans>

Vue3 + Thymeleaf + Axios 傳送 AJAX 請求:

在這裡插入圖片描述

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首頁</title>
    <script th:src="@{/static/js/vue3.4.21.js}"></script>
    <script th:src="@{/static/js/axios.min.js}"></script>
</head>
<body>
<h1>使用 Vue3 + axios + Thymeleaf + SpringMVC 傳送 AJAX 請求</h1>
<hr>
<div id="app">
    <h1>{{message}}</h1>
    <button @click="getMessage">獲取訊息</button>
</div>

<script th:inline="javascript">
    Vue.createApp({
        data() {
            return {
                message: ''
            }
        },
        methods: {
            //非同步方法(ajax請求多數情況下都是非同步請求)
            async getMessage() {
                try {
                    // 傳送 ajax請求
                    // await axios.get('/springmvc/ajax')
                    //動態獲取 應用的根/springmvc/
                    const response = await axios.get([[@{/}]] + 'ajax')
                        // 將返回的資料交給 message
                        this.message = response.data
                }catch
                    (e)
                    {
                        console.error(e)
                    }
                }
            }
        }).mount("#app")
</script>


</body>
</html>

重點來了,Controller 怎麼寫呢?

之前我們都是傳統的請求,Controller 返回一個 邏輯檢視名 。然後交給 檢視解析器 —>進行解析,最後跳轉頁面。而 AJAX 請求是不需要跳轉頁面的,因為 AJAX 是頁面區域性重新整理,以前我們在 Servlet 中使用 response.getWriter( ).print("message") 的方式響應。在 Spring MVC 中怎麼辦呢?當然,我們在 Spring MVC 中也可以使用 Servelt 原生API 來完成整個功能,程式碼如下:

在這裡插入圖片描述

或者這樣也行:不需要有返回值

在這裡插入圖片描述


import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.io.IOException;
import java.io.PrintWriter;

@Controller  // 交給 Spring IOC 容器管理
public class AJAXController {

    @RequestMapping(value = "/ajax",method = RequestMethod.GET)
    public void ajax(HttpServletResponse response) throws IOException {
        PrintWriter writer = response.getWriter();
        writer.print("hell ajax,my name is Spring MVC");

    }

}

啟動伺服器測試:http://localhost:8080/springmvc/

在這裡插入圖片描述

注意:如果採用這種方式響應,則和 springmvc.xml 檔案中配置的檢視解析器沒有關係,不走檢視解析器了。

難道我們以後 AJAX 請求 要使用上面這種原生Servlet API嗎?

不需要,我們可以使用 SpringMVC 中提供的 HttpMessageConverter 訊息轉換器。

我們要向前端響應一個字串 "hell ajax,my name is Spring MVC" ,這個 "hell ajax,my name is Spring MVC" 就是響應協議中的響應體。
我們可以使用 @ResponseBody註解 來啟用對應的訊息轉換器。而這種訊息轉換器只負責將Controller返回的資訊以響應體的形式寫入響應協議。

5. @ResponseBody 將伺服器端的 return 返回值轉化為“字串(JSON格式的字串)”再返回給客戶端

在這裡插入圖片描述

上面的 AJAX 案例,Controller的程式碼可以修改為:

在這裡插入圖片描述



import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.io.PrintWriter;

@Controller  // 交給 Spring IOC 容器管理
public class AJAXController {


    @RequestMapping(value = "/ajax", method = RequestMethod.GET)
    @ResponseBody   // 由於你使用了 @ResponseBody 註解
    public String ajax() {
        // 當前處理器方法上新增了 @ResponseBoay 註解,
        // 那麼這個方法的返回值不再是邏輯檢視名稱了
        // 而是作為響應協議的響應體進行響應。
        return "hell ajax,my name is Spring MVC";
    }

最核心需要理解的位置是:return "hell ajax,my name is Spring MVC";

這裡的 "hell ajax,my name is Spring MVC" 不是邏輯檢視名稱了,而是作為響應體的內容進行響應。直接輸出到瀏覽器客戶端。

以上程式中使用的訊息轉換器是:StringHttpMessageConverter,為什麼會啟用這個訊息轉換器呢?因為你新增了 @ResponseBody 這個註解了。

啟動伺服器測試:http://localhost:8080/springmvc/

在這裡插入圖片描述


通常 AJAX 請求需要伺服器給返回一段JSON格式的字串,可以返回JSON格式的字串嗎?

這是完全可以的,此時底層使用的訊息轉換器還是:StringHttpMessageConverter

當然可以,程式碼如下:

在這裡插入圖片描述



import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.io.PrintWriter;

@Controller  // 交給 Spring IOC 容器管理
public class AJAXController {


    @RequestMapping(value = "/ajax", method = RequestMethod.GET)
    @ResponseBody   // 由於你使用了 @ResponseBody 註解
    public String ajax() {
        // 當前處理器方法上新增了 @ResponseBoay 註解,
        // 那麼這個方法的返回值不再是邏輯檢視名稱了
        // 而是作為響應協議的響應體進行響應。

        // JSON 格式的字串,然後響應到瀏覽器
        return "{\"username\":\"zhangsan\",\"password\":\"1234\"}";
        //return "hell ajax,my name is Spring MVC";
    }
}

啟動伺服器測試:http://localhost:8080/springmvc/

在這裡插入圖片描述

這是完全可以的,此時底層使用的訊息轉換器還是:StringHttpMessageConverter

那如果在程式中是一個POJO物件,怎麼將POJO物件 以 JSON格式 的字串響應給瀏覽器呢 ?兩種方式:

  • 第一種方式:自己寫程式碼 將POJO物件 轉換成JSON格式的字串(如上面所示 return "{"username":"zhangsan","password":"1234"}"; ),用上面的方式直接 return即可。

  • 第二種方式:啟用MappingJackson2HttpMessageConverter訊息轉換器。

第二種方式:啟用MappingJackson2HttpMessageConverter訊息轉換器。

啟用 MappingJackson2HttpMessageConverter 訊息轉換器的步驟如下:

第一步: 引入 jackson依賴,可以將 java物件 轉換為 json格式字串

在這裡插入圖片描述

  <!--        引入jackson依賴,可以將java物件轉換為json格式字串-->
        <!--        專門負責將Java物件轉換成JSON格式字串的元件,
        當然,它也可以將JSON格式的字串轉換成Java物件-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.17.0</version>
        </dependency>

第二步: 開啟註解驅動
這一步非常關鍵,開啟註解驅動後,在 HandlerAdapter 中會自動裝配一個訊息轉換器:MappingJackson2HttpMessageConverter

在這裡插入圖片描述

<mvc:annotation-driven/>

第三步: 我們想將以 POJO物件轉換為 JOSN 格式的字串,返回給客戶端,我們需要建立一個 POJO物件。

在這裡插入圖片描述

package com.rainbowsea.springmvc.pojo;

public class User {

    private Long id;
    private String name;
    private String password;


    public User() {
    }

    public User(Long id, String name, String password) {
        this.id = id;
        this.name = name;
        this.password = password;
    }


    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

第四步: 控制器方法使用 @ResponseBody 註解標註(非常重要),控制器方法返回這個POJO物件

在這裡插入圖片描述



import com.rainbowsea.springmvc.pojo.User;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.io.PrintWriter;

@Controller  // 交給 Spring IOC 容器管理
public class AJAXController {


    @RequestMapping(value = "/ajax", method = RequestMethod.GET)
    @ResponseBody   // 由於你使用了 @ResponseBody 註解
    public User ajax() {
        // 當前處理器方法上新增了 @ResponseBoay 註解,
        // 那麼這個方法的返回值不再是邏輯檢視名稱了
        // 而是作為響應協議的響應體進行響應。

        // 將 POJO物件轉換為 JSON格式的字串,然後響應到瀏覽器端
        User user = new User(111L, "李華", "123");
        return user;


        // JSON 格式的字串,然後響應到瀏覽器
        //return "{\"username\":\"zhangsan\",\"password\":\"1234\"}";

        //return "hell ajax,my name is Spring MVC";
    }


}

啟動伺服器測試:http://localhost:8080/springmvc/

在這裡插入圖片描述

以上程式碼底層啟動的就是: MappingJackson2HttpMessageConverter 訊息轉換器。

它的功能很強大,可以將 POJO物件轉換成 JSON格式的字串,響應給前端。

其實這個訊息轉換器MappingJackson2HttpMessageConverter 本質上只是比: StringHttpMessageConverter 稍微多了一個 JSON 字串的轉換,其他的還是一樣的。

6. 補充:@RestController = (@Controller + @ResponseBody )

在這裡插入圖片描述

因為我們現代的開發方式都是基於 AJAX 方式的,因此 @ResponseBody註解非常重要,很常用。 為了方便,Spring MVC中提供了一個註解 @RestController。這一個註解代表了:@Controller + @ResponseBody。 @RestController標註在類上即可。

被它標註的@RestController中所有的方法上都會自動標註 @ResponseBody

在這裡插入圖片描述


import com.rainbowsea.springmvc.pojo.User;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.io.PrintWriter;


@RestController  // @Controller + @ResponseBody
public class AJAXController {


    @RequestMapping(value = "/ajax", method = RequestMethod.GET)
    public User ajax() {
        // 當前處理器方法上新增了 @ResponseBoay 註解,
        // 那麼這個方法的返回值不再是邏輯檢視名稱了
        // 而是作為響應協議的響應體進行響應。

        // 將 POJO物件轉換為 JSON格式的字串,然後響應到瀏覽器端
        User user = new User(111L, "李華", "123");
        return user;
    }
}

在這裡插入圖片描述

7. @RequestBody 將前端的請求體的資訊轉換Java程式中的 POJO物件

在這裡插入圖片描述

該註解只能使用在處理器方法的形參上,
這個註解的作用是直接將請求體傳遞給Java程式,在Java程式中可以直接使用一個String 型別的變數接收這個請求體的內容。
底層使用的HTTP訊息轉換器是:FormHttpMessageConvertor

在這裡插入圖片描述

沒有保持一致的話,會賦值失敗。

在這裡插入圖片描述

在這裡插入圖片描述

在沒有使用 @RequestBody 這個註解的時候:

當請求體提交的資料是:

在這裡插入圖片描述

username=admin&password=123

那麼 Spring MVC會自動使用 FormHttpMessageConverter訊息轉換器,將請求體轉換成 對應的 POJO物件,這裡是 user物件。

package com.rainbowsea.springmvc.controller;


import com.rainbowsea.springmvc.pojo.User;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.net.URI;


@Controller  // 交給 Spring IOC 容器管理
public class RequestBodyController {
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public String saveUser( User user) {
        // @RequestBody 將 將請求體轉換成user物件。在方法上使用
        System.out.println(user);
        // 不是邏輯檢視,是普通字串,因為前端傳送的請求是 AJAX 請求
        return "ok";

    }


}

在這裡插入圖片描述

當使用這個註解的時候:這個註解只能出現在方法的引數上。

在這裡插入圖片描述


import com.rainbowsea.springmvc.bean.User;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.net.URI;


@Controller  // 交給 Spring IOC 容器管理
public class RequestBodyController {

    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public String save(@RequestBody String requestBodyStr) {
        // @RequestBody 將 將請求體轉換成user物件。在方法上使用
         System.out.println("請求體:" + requestBodyStr);

        return "ok";

    }
}

在這裡插入圖片描述

Spring MVC仍然會使用 FormHttpMessageConverter訊息轉換器,將請求體直接以字串形式傳遞給 requestBodyStr 變數。

7.1 MappingJackson2HttpMessageConverter 將前端提交的 JSON 格式的字串,轉換為 Java程式中的POJO物件

如果在請求體中提交的是一個 JSON 格式的字串,這個 JSON 字串傳遞給 Spring MVC 之後,能不能將 JSON 字串轉換成 POJO 物件呢?

答案是:可以的

此時必須使用 @RequetBody 註解來完成,並且底層使用的訊息轉換器是:MappingJackson2HttpMessageConverter 。實現步驟如下:

  1. 第一步:引入 jackson 依賴

在這裡插入圖片描述

  1. 第二步:開啟註解驅動

在這裡插入圖片描述

  1. 第三步:建立POJO類,將POJO類作為控制器方法的引數,並使用 @RequestBody 註解標註該引數。

在這裡插入圖片描述


import com.rainbowsea.springmvc.pojo.User;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.net.URI;


@Controller  // 交給 Spring IOC 容器管理
public class RequestBodyController {
    @RequestMapping(value = "/save2", method = RequestMethod.POST)
    public String saveUser(@RequestBody User user) {
        // @RequestBody 將 將請求體轉換成user物件。在方法上使用
        System.out.println(user);
        System.out.println(user.getName());
        System.out.println(user.getPassword());
        // 不是邏輯檢視,是普通字串,因為前端傳送的請求是 AJAX 請求
        return "ok";

    }
}

第四步:在前端 請求體中提交 json格式 的資料。

在這裡插入圖片描述

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首頁</title>
    <script th:src="@{/static/js/vue3.4.21.js}"></script>
    <script th:src="@{/static/js/axios.min.js}"></script>
</head>
<body>
<h1>使用 Vue3 + axios + Thymeleaf + SpringMVC 傳送 AJAX 請求</h1>
<hr>
<div id="app">
    <h1>{{message}}</h1>
    <button @click="getMessage">獲取訊息</button>
</div>



<script th:inline="javascript">

    // 傳送 ajax post 請求,並且在請求體當中提交json資料
    // 注意:name ,password 要於對應將 json 轉換為 Bean物件上的屬性名一致
    let jsonObj = {"name": "李華", "password": "123"}
    Vue.createApp({
        data() {
            return {
                message: ''
            }
        },
        methods: {
            //非同步方法(ajax請求多數情況下都是非同步請求)
            async getMessage() {
                console.log("sendjson")
                try {
                    // 傳送 ajax請求
                    // await axios.get('/springmvc/ajax')
                    //動態獲取 應用的根/springmvc/
                    const response = await axios.post([[@{/}]] + 'save2',JSON.stringify(jsonObj),{
                        headers
                :
                    {
                        // 請求體的狀態資訊
                        "Content-Type"
                    :
                        "application/json"
                    }
                })

                    // 將返回的資料交給 message
                    this.message = response.data
                } catch
                    (e) {
                    console.error(e)
                }
            }
        }
    }).mount("#app")
</script>

</body>
</html>

測試結果:

在這裡插入圖片描述

8. RequestEntity 類

RequestEntity 不是一個註解,是一個普通的類,這個類的例項封裝了整個請求協議:包括請求行,請求頭,請求體所有資訊。

該 RequestEntity 類出現在控制器方法的引數上。

在這裡插入圖片描述

使用測試:如下是對應的 html 頁面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首頁</title>
    <script th:src="@{/static/js/vue3.4.21.js}"></script>
    <script th:src="@{/static/js/axios.min.js}"></script>
</head>
<body>
<h1>使用 Vue3 + axios + Thymeleaf + SpringMVC 傳送 AJAX 請求</h1>
<hr>
<div id="app">
    <h1>{{message}}</h1>
    <button @click="getMessage">獲取訊息</button>
</div>



<script th:inline="javascript">

    // 傳送 ajax post 請求,並且在請求體當中提交json資料
    // 注意:name ,password 要於對應將 json 轉換為 Bean物件上的屬性名一致
    let jsonObj = {"name": "李華", "password": "123"}
    Vue.createApp({
        data() {
            return {
                message: ''
            }
        },
        methods: {
            //非同步方法(ajax請求多數情況下都是非同步請求)
            async getMessage() {
                console.log("sendjson")
                try {
                    // 傳送 ajax請求
                    // await axios.get('/springmvc/ajax')
                    //動態獲取 應用的根/springmvc/
                    const response = await axios.post([[@{/}]] + 'save2',JSON.stringify(jsonObj),{
                        headers
                :
                    {
                        // 請求體的狀態資訊
                        "Content-Type"
                    :
                        "application/json"
                    }
                })

                    // 將返回的資料交給 message
                    this.message = response.data
                } catch
                    (e) {
                    console.error(e)
                }
            }
        }
    }).mount("#app")
</script>

</body>
</html>

在這裡插入圖片描述

package com.rainbowsea.springmvc.controller;


import com.rainbowsea.springmvc.pojo.User;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.net.URI;


@Controller  // 交給 Spring IOC 容器管理
public class RequestBodyController {
    @RequestMapping(value = "/save2", method = RequestMethod.POST)
    public String saveUser(RequestEntity<User> requestEntity) {
        // 獲取請求方法
        HttpMethod method = requestEntity.getMethod();
        System.out.println(method);

        // 獲取請求URL
        URI url = requestEntity.getUrl();
        System.out.println(url);

        // 獲取請求頭
        HttpHeaders headers = requestEntity.getHeaders();
        System.out.println(headers);

        // 獲取請求頭中的內容型別
        MediaType contentType = headers.getContentType();
        System.out.println(contentType);

        // 獲取請求體:
        User user = requestEntity.getBody();
        System.out.println(user);


        return "ok";

    }

}

測試結果:

在這裡插入圖片描述

9. ResponseEntity 類

在這裡插入圖片描述

ResponseEntity 不是註解,而是一個類。使用該類的例項可以封裝響應協議,包括:狀態行,響應頭,響應體。 也就是說:如果你想定製屬於自己的響應協議,可以使用該類。

舉例:這裡假如我們有這麼一個需求:

前端提交一個 id,後端根據 id 進行查詢,如果返回 null,請在前端顯示 404 錯誤,如果返回不是 null,則輸出返回 User 物件。

前端頁面設定:

在這裡插入圖片描述

後端處理:

首先編寫一個 Service 進行一個查詢處理,這裡我們就簡單判斷一下,就不連線資料庫了。

在這裡插入圖片描述

package com.rainbowsea.springmvc.service;


import com.rainbowsea.springmvc.pojo.User;
import org.springframework.stereotype.Service;


// 注意使用了註解,要用上元件掃描上
@Service
public class UserService {


    public User getById(Long id) {
        if(id == 1) {
            return new User(11L,"張三","123");
        }
        return null;
    }
}

最後是對應 Controller 控制器的編寫

在這裡插入圖片描述

在這裡插入圖片描述

package com.rainbowsea.springmvc.controller;



import com.rainbowsea.springmvc.pojo.User;
import com.rainbowsea.springmvc.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class UserController {

    @Autowired  // Spring 自動賦值,管理
    private UserService userService;

    @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
    public ResponseEntity<User> getById(@PathVariable("id") Long id) {
        User user = userService.getById(id);
        if(user == null) {
            // HttpStatus.NOT_FOUND  找不到錯誤  HTTP ERROR 404
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
        } else {
            return ResponseEntity.ok(user);
        }

    }

}

測試:當使用者存在時

在這裡插入圖片描述

測試:當使用者不存在時

在這裡插入圖片描述

10. 總結:

  1. HTTP 協議包括 請求協議響應協議
  2. @ResponseBody 將伺服器端的 return 返回值轉化為“字串(JSON格式的字串)”再返回給客戶端。
  3. @ResponseBody 將POJO物件 以 JSON格式 的字串響應給瀏覽器
    1. 第一種方式:自己寫程式碼 將POJO物件 轉換成JSON格式的字串(如上面所示 return "{"username":"zhangsan","password":"1234"}"; ),用上面的方式直接 return即可。
    2. 第二種方式:啟用MappingJackson2HttpMessageConverter訊息轉換器。
    3. 需要注意的時需要新增:涉及到 JSON格式的轉換,都需要匯入相關的jar包,以及開啟註解驅動。
  4. @RestController = (@Controller + @ResponseBody ), 被它標註的@RestController中所有的方法上都會自動標註 @ResponseBody
  5. @RequestBody 將前端的請求體的資訊轉換Java程式中的 POJO物件,該註解只能使用在處理器方法的形參上,還可以將 前端的請求體直接以字串形式傳遞給 requestBodyStr 變數。
  6. @RequetBody 註解將前端提交的 JSON 格式的字串,轉換為 Java程式中的POJO物件,涉及到 JSON格式的轉換,都需要匯入相關的jar包,以及開啟註解驅動。
  7. RequestEntity 類是一個普通的類,這個類的例項封裝了整個請求協議:包括請求行,請求頭,請求體所有資訊。 該 RequestEntity 類出現在控制器方法的引數上。
  8. ResponseEntity 是一個類。使用該類的例項可以封裝響應協議,包括:狀態行,響應頭,響應體。 也就是說:如果你想定製屬於自己的響應協議,可以使用該類。
  9. 無論是那個,只要涉及到 JSON格式的轉換,都需要匯入相關的jar包,以及開啟註解驅動。

11. 最後:

“在這個最後的篇章中,我要表達我對每一位讀者的感激之情。你們的關注和回覆是我創作的動力源泉,我從你們身上吸取了無盡的靈感與勇氣。我會將你們的鼓勵留在心底,繼續在其他的領域奮鬥。感謝你們,我們總會在某個時刻再次相遇。”

在這裡插入圖片描述

相關文章