文章目錄
- 1. 請求映射路徑
- 2. 請求參數
-
- 2.1 get 請求發送普通參數
- 2.2 post 請求發送普通參數
- 2.3 五種類型的參數傳遞
-
- 2.4.1 普通參數
- 2.4.2 POJO 資料類型
- 2.4.3 嵌套 POJO 類型參數
- 2.4.4 數組類型參數
- 2.4.5 集合類型參數
- 3. json 資料傳輸參數(重點)
-
- 3.1 傳輸 json 普通數組
- 3.2 傳輸 json 對象
- 3.3 傳輸 json 對象數組
- 4. 日期類型參數傳遞
- 5. 響應 json 資料
-
- 5.1 響應 / 跳轉頁面(了解)
- 5.2 響應文本資料(了解)
- 5.3 響應 json 資料
-
- 5.3.1 響應 POJO 對象
- 5.3.2 響應 POJO 對象集合
- 5.3.3 @ResponseBody 注解
1. 請求映射路徑
環境準備:
(1) pom.xml
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<name>springmvc03_request_mapping</name>
<groupId>com.itheima</groupId>
<artifactId>springmvc03_request_mapping</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--導入springmvc與servlet的依賴-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope><!--防止與tomcat插件沖突-->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<!--tomcat插件-->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port><!--tomcat端口号-->
<path>/</path><!--虛拟目錄-->
</configuration>
</plugin>
</plugins>
</build>
</project>
(2) ServletControllerInitConfig
// 定義一個servlet容器啟動的配置類
// 要繼承AbstractAnnotationConfigDispatcherServletInitializer
public class ServletControllerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
//加載Spring配置類
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
//加載SpringMVC配置類
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
//設定哪些請求由springMVC處理
@Override
protected String[] getServletMappings() {
//所有請求都由springMVC處理
return new String[]{"/"};
}
}
(3) SpringMvcConfig
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}
(4) UserController
//使用Controller定義bean
@Controller
public class UserController {
// 目前操作的請求映射路徑:使用者發出哪個請求能調用到這個方法
@RequestMapping("/user/save")
// 設定目前操作的傳回值類型
// 把傳回的東西整體作為響應的内容給到外面
@ResponseBody
// 處理請求的方法
// 傳回值為String:執行完這個方法,要對外傳回json資料
public String save(){
System.out.println("user save ...");
return "{'module':'user save'}";
}
@RequestMapping("/user/delete")
@ResponseBody
public String delete(){
System.out.println("user delete ...");
return "{'module':'user delete'}";
}
}
(5) BookController
@Controller
public class BookController {
@RequestMapping("/book/save")
@ResponseBody
public String save(){
System.out.println("book save...");
return "{'module':'book save'}";
}
}
在 UserController 和 BookController 中,都有 save 方法,若兩者的請求映射路徑都為 “/save”,則兩者的通路路徑就都成了 http://localhost/save,會沖突。
解決方法就是如上面代碼一樣,設定子產品名作為請求映射路徑的前置。這樣,通路路徑就分别為:http://localhost/user/save,http://localhost/book/save。
這樣在同一個子產品中出現命名沖突的情況就比較少了。
問題是解決了,但是每個方法前面都需要進行修改,寫起來比較麻煩而且還有很多重複代碼,如果 “/user” 後期發生變化,所有的方法都需要改,耦合度太高。
優化方案: 把請求映射路徑的字首寫到類上面,這樣方法上隻寫剩餘路徑即可。
//使用Controller定義bean
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'module':'user save'}";
}
@RequestMapping("/delete")
@ResponseBody
public String delete(){
System.out.println("user delete ...");
return "{'module':'user delete'}";
}
}
@Controller
@RequestMapping("/book")
public class BookController {
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("book save...");
return "{'module':'book save'}";
}
}
2. 請求參數
2.1 get 請求發送普通參數
//使用Controller定義bean
@Controller
public class UserController {
@RequestMapping("/commonParam")
@ResponseBody
public String save(String name){
System.out.println("普通參數傳遞 name="+name+" age="+age);
return "{'module':'common param'}";
}
}
用 postman 發送帶參數的 get 請求,收到請求結果:
同時,處理請求的方法也接收到參數,輸出:
GET 請求中文亂碼
如果請求中傳遞的參數有中文,那麼接收到的參數會出現中文亂碼問題。
如發送請求: http://localhost/commonParam?name=張三&age=18,處理請求的方法接收的參數會是:
原因在于:雖然 Tomcat 8.5 以後的版本已經處理了中文亂碼的問題,但是 IDEA 中的 Tomcat 插件目前隻到 Tomcat7,是以需要修改 pom.xml 來解決 GET 請求中文亂碼問題。
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<name>springmvc04_request_param</name>
<groupId>com.itheima</groupId>
<artifactId>springmvc04_request_param</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--導入springmvc與servlet的依賴-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope><!--防止與tomcat插件沖突-->
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<!--tomcat插件-->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port><!--tomcat端口号-->
<path>/</path><!--虛拟目錄-->
<uriEncoding>UTF-8</uriEncoding><!--通路路徑編解碼字元集-->
</configuration>
</plugin>
</plugins>
</build>
</project>
2.2 post 請求發送普通參數
背景代碼不區分 get 請求和 post 請求,是以仍用前面的代碼來處理 post 請求。
用 postman 發送帶參數的 post 請求:
收到請求結果:
同時,處理請求的方法也接收到參數,輸出:
post 請求中文亂碼
post 請求發送中文參數時,處理請求的方法列印擷取的參數也會出現亂碼問題。
解決方法:在 ServletContainersInitConfig 中配置過濾器。
// 定義一個servlet容器啟動的配置類
// 要繼承AbstractAnnotationConfigDispatcherServletInitializer
public class ServletControllerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
//加載Spring配置類
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
//加載SpringMVC配置類
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
//設定哪些請求由springMVC處理
@Override
protected String[] getServletMappings() {
//所有請求都由springMVC處理
return new String[]{"/"};
}
//亂碼處理
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
2.3 五種類型的參數傳遞
前面我們已經能夠使用 GET 或 POST 來發送請求和資料,但所攜帶的資料都是比較簡單,接下來在這個基礎上,我們來研究一些比較複雜的參數傳遞,常見的參數種類有:
- 普通參數
- POJO 類型參數
- 嵌套 POJO 類型參數
- 數組類型參數
- 集合類型參數
這些參數如何發送,背景該如何接收?下面将逐個介紹(都以 get 請求為例,post 請求同理)。
2.4.1 普通參數
普通參數 url 位址傳參,請求參數名與形參變量名相同,定義形參即可接收參數。
請求結果:
控制台輸出:
如果位址參數名與形參不同該如何解決?
如:送出請求
http://localhost/commonParam?userName=tom&age=18
解決方案:使用
@RequestParam
注解
2.4.2 POJO 資料類型
簡單資料類型一般處理的是參數個數比較少的請求,如果參數比較多,那麼背景接收參數的時候就比較複雜,這個時候可以使用 POJO 資料類型(實體類)。
POJO 參數:若請求參數名與形參對象屬性名相同,POJO 類型的形參就可接收到參數。
請求結果:
控制台輸出:
2.4.3 嵌套 POJO 類型參數
請求結果:
控制台輸出:
2.4.4 數組類型參數
舉個簡單的例子,如果前端需要擷取使用者的愛好,愛好絕大多數情況下都是多個,如何發送請求資料和接收資料呢?
數組參數:請求參數名與形參對象屬性名相同,且請求參數為多個同名參數,定義數組類型即可接收參數。
請求結果:
控制台輸出:
2.4.5 集合類型參數
數組能接收多個值,那麼集合是否也可以實作這個功能呢?
注:同名請求參數可以使用
@RequestParam
注解映射到對應名稱的集合對象中作為資料。對于簡單資料類型使用數組會比集合更簡單些。
請求結果:
控制台輸出:
3. json 資料傳輸參數(重點)
現在比較流行的開發方式為異步調用,前背景以異步方式進行交換,傳輸的資料使用的是 json。是以前端如果發送的是 json 資料,後端該如何接收?
三種常見的 json 資料類型:
json 普通數組
(["value1","value2","value3",...])
json 對象
({key1:value1,key2:value2,...})
json 對象數組
([{key1:value1,...},{key2:value2,...}])
對于上述資料,前端如何發送,後端如何接收?
3.1 傳輸 json 普通數組
(1) pom.xml 添加依賴
SpringMVC 預設使用 jackson 處理 json 的轉換,是以需要添加 jackson 依賴。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
(2) 開啟自動轉換 json 資料的支援
@EnablewebMvc
注解功能強大,該注解整合了多個功能。此處僅使用其中一部分功能,即 json 資料進行自動類型轉換。
@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc//開啟将json轉換成對象的功能
//以後把@EnableWebMvc當做标配配置上去,不要省略
public class SpringMvcConfig {
}
(3) PostMan 編寫 json 資料
(4) 背景處理請求的方法
@RequestBody
注解将請求中請求體所包含的資料傳遞給方法的形參,此注解一個方法隻能使用一次。(因為資料在請求體中,不在請求參數中,是以不能用@RequestParam注解)
//使用Controller定義bean
@Controller
public class UserController {
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("list common(json)參數傳遞 list="+likes);
return "{'module':'list common for json param'}";
}
}
運作程式後,用 postman 發送 json 資料,得到請求結果:
控制台輸出:
3.2 傳輸 json 對象
要求:json 資料與形參對象屬性名相同。
前兩步與 3.1 相同。
(3) PostMan 編寫 json 資料
(4) 背景處理請求的方法
//使用Controller定義bean
@Controller
public class UserController {
@RequestMapping("/pojoParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){
System.out.println("pojo(json)參數傳遞 user="+user);
return "{'module':'pojo for json param'}";
}
}
運作程式後,用 postman 發送 json 資料,得到請求結果:
控制台輸出:
3.3 傳輸 json 對象數組
要求:json 數組資料與集合泛型屬性名相同。
前兩步與 3.1 相同。
(3) PostMan 編寫 json 資料
(4) 背景處理請求的方法
//使用Controller定義bean
@Controller
public class UserController {
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> list){
System.out.println("list pojo(json)參數傳遞 list="+list);
return "{'module':'list pojo for json param'}";
}
}
運作程式後,用 postman 發送 json 資料,得到請求結果:
控制台輸出:
@RequestBody 與 @RequestParam
差別:
@RequestParam 用于接收 url 位址傳參,表單傳參【application/x-www-formurlencoded】(請求映射參數)
@RequestBody 用于接收 json 資料【application/json】(請求體)
應用:
後期開發中,發送 json 格式資料為主,@RequestBody 應用較廣。
如果發送非 json 格式資料,選用 @RequestParam 接收請求參數。
4. 日期類型參數傳遞
前面處理過簡單資料類型、POJO 資料類型、數組和集合資料類型以及 json 資料類型,接下來要處理一種開發中比較常見的一種資料類型:日期類型。
日期類型比較特殊,因為對于日期的格式有 N 多中輸入方式,比如:
- 2088-08-18
- 2088/08/18
- 08/18/2088
- …
針對這麼多日期格式,SpringMVC 該如何接收?
(3) PostMan 編寫 json 資料
(4) 背景處理請求的方法
//使用Controller定義bean
@Controller
public class UserController {
@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,
@DateTimeFormat(pattern = "yyyy-MM-dd") Date date1,
@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date2) {
System.out.println("參數傳遞 date=" + date);
System.out.println("參數傳遞 date1=" + date1);
System.out.println("參數傳遞 date2=" + date2);
return "{'module':'data param'}";
}
}
運作程式後,用 postman 發送 json 資料,得到請求結果:
控制台輸出:
參數傳遞 date=Sun Feb 12 00:00:00 CST 2023
參數傳遞 date1=Sun Feb 12 00:00:00 CST 2023
參數傳遞 date2=Sun Feb 12 15:59:33 CST 2023
内部實作原理
講解内部原理之前,需要先思考個問題:
前端傳遞字元串,後端使用日期 Date 接收
前端傳遞 json 資料,後端使用對象接收
前端傳遞字元串,後端使用 Integer 接收
背景需要的資料類型有很多種,在資料的傳遞過程中存在很多類型的轉換,誰來做這個類型轉換呢?是SpringMVC。
SpringMVC是如何實作類型轉換的?
答:SpringMVC中提供了很多類型轉換接口和實作類
在架構中,有一些類型轉換接口,其中有 :
(1) Converter 接口:
Converter 接口的實作類:
架構中有提供很多對應 Converter 接口的實作類,用來實作不同資料類型之間的轉換,如:
請求參數年齡資料(String→Integer)
日期格式轉換(String → Date)
(2) HttpMessageConverter 接口
該接口是實作對象與 json 之間的轉換工作
5. 響應 json 資料
SpringMVC 接收到請求和資料後,進行一些了的處理,當然這個處理可以是轉發給 Service,Service 層再調用 Dao 層。不管怎樣,處理完以後,都需要将結果告知給使用者。
比如:根據使用者 ID 查詢使用者資訊、查詢使用者清單、新增使用者等。
對于響應,主要就包含兩部分内容:
- 響應頁面
- 響應資料
- 文本資料
- json資料
之前學 servlet 時主要是響應頁面。在學習異步送出之後,還可以響應資料。
因為異步調用是目前的主流方式,是以我們需要更關注的就是如何傳回 json 資料,對于其他了解即可。
5.1 響應 / 跳轉頁面(了解)
(1) 準備頁面 page.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello springmvc</title>
</head>
<body>
<h1>hello springmvc</h1>
</body>
</html>
(2) 在 Controller 中設定傳回頁面
//使用Controller定義bean
@Controller
public class UserController {
@RequestMapping("/toJumpPage")
//注意
//1.此處不能添加@ResponseBody,如果加了該注入,會直接将page.jsp當字元串傳回前端
//2.方法需要傳回String
public String toJumpPage(){
return "page.jsp";
}
}
在浏覽器位址欄輸入:http://localhost/toJumpPage,得到:
5.2 響應文本資料(了解)
postman 送出請求:
響應請求:
@Controller
public class UserController {
@RequestMapping("/toText")
//這裡的@ResponseBody注解不能省略
//否則會把“response text”當做頁面名稱查找,找不到該頁面就報404錯誤
@ResponseBody
public String toText(){
System.out.println("傳回純文字資料");
return "response text";
}
}
背景響應,發回請求結果:
控制台輸出:
傳回純文字資料
5.3 響應 json 資料
5.3.1 響應 POJO 對象
postman 送出請求:
響應請求:
//使用Controller定義bean
@Controller
public class UserController {
@RequestMapping("/toJsonPOJO")
@ResponseBody
public User pojoToJson(){
System.out.println("傳回json對象資料");
User user = new User();
user.setName("tom");
user.setAge(8);
return user;
}
}
背景響應,發回請求結果:
控制台輸出:
傳回json對象資料
5.3.2 響應 POJO 對象集合
postman 送出請求:
響應請求:
@Controller
public class UserController {
@RequestMapping("/toJsonList")
@ResponseBody
public List<User> toJsonList() {
System.out.println("傳回json對象集合");
User user1 = new User();
user1.setName("tom");
user1.setAge(8);
User user2 = new User();
user2.setName("jerry");
user2.setAge(5);
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
return userList;
}
}
背景響應,發回請求結果:
控制台輸出:
傳回json對象集合
5.3.3 @ResponseBody 注解
- @ResponseBody 注解可以寫在類或方法上
- 寫在類上就是該類的所有方法都有 @ReponseBody 功能
- 當方法上有 @ReponseBody 注解後
- 方法的傳回值為字元串,會将其作為文本内容直接響應給前端。
- 方法的傳回值為對象,會将對象轉換成 json 響應給前端。
相關屬性 pattern:指定日期時間格式字元串