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-scanbase-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')// 將返回的數據交給 messagethis.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;}@Overridepublic 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
。實現步驟如下:
- 第一步:引入 jackson 依賴
- 第二步:開啟注解驅動
- 第三步:創建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"}})// 將返回的數據交給 messagethis.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"}})// 將返回的數據交給 messagethis.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);// 獲取請求URLURI 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 404return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);} else {return ResponseEntity.ok(user);}}}
測試:當用戶存在時
測試:當用戶不存在時
10. 總結:
- HTTP 協議包括
請求協議
和響應協議
。- @ResponseBody 將服務器端的 return 返回值轉化為“字符串(JSON格式的字符串)”再返回給客戶端。
- @ResponseBody 將POJO對象 以 JSON格式 的字符串響應給瀏覽器
- 第一種方式:自己寫代碼 將POJO對象 轉換成JSON格式的字符串(如上面所示 return “{“username”:“zhangsan”,“password”:“1234”}”; ),用上面的方式直接 return即可。
- 第二種方式:啟用
MappingJackson2HttpMessageConverter
消息轉換器。- 需要注意的時需要添加:涉及到 JSON格式的轉換,都需要導入相關的jar包,以及開啟注解驅動。
- @RestController = (@Controller + @ResponseBody ), 被它標注的@RestController中所有的方法上都會自動標注 @ResponseBody
- @RequestBody 將前端的請求體的信息轉換Java程序中的 POJO對象,該注解只能使用在處理器方法的形參上,還可以將 前端的請求體直接以字符串形式傳遞給 requestBodyStr 變量。
@RequetBody
注解將前端提交的 JSON 格式的字符串,轉換為 Java程序中的POJO對象,涉及到 JSON格式的轉換,都需要導入相關的jar包,以及開啟注解驅動。- RequestEntity 類是一個普通的類,這個類的實例封裝了整個請求協議:包括請求行,請求頭,請求體所有信息。 該 RequestEntity 類出現在控制器方法的參數上。
- ResponseEntity 是一個類。使用該類的實例可以封裝響應協議,包括:狀態行,響應頭,響應體。 也就是說:如果你想定制屬于自己的響應協議,可以使用該類。
- 無論是那個,只要涉及到 JSON格式的轉換,都需要導入相關的jar包,以及開啟注解驅動。
11. 最后:
“在這個最后的篇章中,我要表達我對每一位讀者的感激之情。你們的關注和回復是我創作的動力源泉,我從你們身上吸取了無盡的靈感與勇氣。我會將你們的鼓勵留在心底,繼續在其他的領域奮斗。感謝你們,我們總會在某個時刻再次相遇。”