Spring MVC 請求參數(shù)處理全解析
2.4 請求
訪問不同的路徑,就是發(fā)送不同的請求。在發(fā)送請求時,可能會帶一些參數(shù),所以學(xué)習(xí) Spring 的請求,主要是學(xué)習(xí)如何傳遞參數(shù)到后端以及后端如何接收.傳遞參數(shù),咱們主要是使用瀏覽器和 Postman 來模擬
后端開發(fā)人員無需過度關(guān)注如何傳遞參數(shù),了解即可,實際開發(fā)中以 Postman 測試為主.比如餐廳的廚師,不關(guān)注用戶是在店里下單,還是外賣平臺下單,或者小程序下單,只需要知道如何接收訂單,根據(jù)訂單做出對應(yīng)的菜肴就可以了.
2.4.1 傳遞單個參數(shù)
接收單個參數(shù),在 Spring MVC 中直接用方法中的參數(shù)就可以,比如以下代碼:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/param")
public class ParamController {
@RequestMapping("m1")
public String method1(String name){
return "接收到參數(shù)name:"+ name;
}
}咱們使用瀏覽器發(fā)送請求并傳參http://127.0.0.1:8080/param/m1?name=spring

可以看到,后端程序正確拿到了name參數(shù)的值
Spring MVC會根據(jù)方法的參數(shù)名,找到對應(yīng)的參數(shù),賦值給方法

如果參數(shù)不?致,是獲取不到參數(shù)的.
比如請求URL:http://127.0.0.1:8080/param/m1?name1=spring 響應(yīng)結(jié)果

那Postman中測試的結(jié)果

注意事項 :
使用基本類型來接收參數(shù)時,參數(shù)必須傳(除boolean類型),否則會報500錯誤
類型不匹配時,會報400錯誤.
特殊情況:
1.不傳參數(shù):報了一個500的狀態(tài)碼,我們看后端日志

通過Fiddler觀察請求和響應(yīng),HTTP響應(yīng)狀態(tài)碼為500


?般看日志堆棧信息的首行,報錯信息顯示: int類型的參數(shù)'age',雖然為可選的,但由于被聲明為基本類型而不能轉(zhuǎn)換為空值.考慮將其聲明為對應(yīng)基本類型的包裝類型.
按照錯誤信息解決錯誤即可 最開始學(xué)習(xí)時,會遇到各種各樣的問題,我們要養(yǎng)成看錯誤?志的習(xí)慣,根據(jù)錯誤?志來解決問題
2.傳遞參數(shù)類型不匹配:狀態(tài)碼400

通過Fiddler觀察請求和響應(yīng), HTTP響應(yīng)狀態(tài)碼為400

注意:對于包裝類型,如果不傳對應(yīng)參數(shù),Spring接收到的數(shù)據(jù)則為null 所以企業(yè)開發(fā)中,對于參數(shù)可能為空的數(shù)據(jù),建議使?包裝類型
我們還可以用format進行代碼的格式化
@RequestMapping("/r4")
public String r3(String name, Integer age){
return String.format("接受到參數(shù):姓名[%s], age[%d]", name, age);
}作用是接收前端傳遞的name和age兩個參數(shù),并將接收到的參數(shù)拼接成字符串返回給前端。
Spring MVC 識別接口的核心是「請求路徑 + 請求方式(可選)」,而非方法名。
- Spring MVC 的映射核心:Spring MVC 會將
@RequestMapping的路徑、請求方式、請求參數(shù)、請求頭等信息組合成一個唯一的請求映射標識,只要這個標識不重復(fù),即使方法名相同,也能被正確識別和調(diào)用。 - Java 方法的重載規(guī)則:上述示例中同名的
r3方法,參數(shù)列表不同(如(String, Integer)和(String)),這本身符合 Java 的方法重載規(guī)則(方法名相同,參數(shù)列表不同),因此編譯器也不會報錯。
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/param")
public class ParamController {
// 路徑1:/param/r4,方法名r3
@RequestMapping("/r4")
public String r3(String name, Integer age) {
return String.format("接受到參數(shù):姓名[%s], age[%d]", name, age);
}
// 路徑2:/param/r5,方法名同樣是r3(同名)
@RequestMapping("/r5")
public String r3(String address) {
return "接收到參數(shù):地址[" + address + "]";
}
// 甚至可以路徑相同,但請求方式不同(如GET/POST),方法名也能相同
@RequestMapping(value = "/r6", method = RequestMethod.GET)
public String r3(String email) {
return "GET請求:郵箱[" + email + "]";
}
@RequestMapping(value = "/r6", method = RequestMethod.POST)
public String r3(String phone) {
return "POST請求:手機號[" + phone + "]";
}
}2.4.2 傳遞多個參數(shù)
如何接收多個參數(shù)呢? 和接收單個參數(shù)?樣,直接使用?法的參數(shù)接收即可.使用多個形參
@RequestMapping("/m2")
public Object method2(String name, String password) {
return "接收到參數(shù)name:" + name + ", password:" + password;
}使用瀏覽器發(fā)送請求并傳參:http://127.0.0.1:8080/param/m2?name=zhangsan&password=123456

當(dāng)有多個參數(shù)時,前后端進?參數(shù)匹配時,是以參數(shù)的名稱進?匹配的,因此參數(shù)的位置是不影響后端獲取參數(shù)的結(jié)果.
比如訪問:http://127.0.0.1:8080/param/m2?password=123456&name=zhangsan 同樣可以拿到正 確的結(jié)果
可以看到,后端程序正確拿到了name和password參數(shù)的值


底層的邏輯是,先用這個特殊符號&進行分割,然后再從你的方法中看用到了啥,然后找到并且使用,所以這個順序是可以不一樣的但是名字必須是一樣的
詳細解釋:
一、先明確:參數(shù)傳遞的 “載體” 與分割符&的作用
當(dāng)前端通過URL 參數(shù)(如/param/r4?name=張三&age=20)或表單提交傳遞參數(shù)時,參數(shù)的格式是key=value的鍵值對,多個參數(shù)之間用&分隔,&的核心作用就是分割不同的鍵值對參數(shù),這是 HTTP 協(xié)議規(guī)定的參數(shù)傳遞格式,和 Spring MVC 無關(guān),但卻是 Spring 處理參數(shù)的前提。
舉個例子:name=張三&age=20 被&分割后,會得到兩個獨立的鍵值對:
name=張三(鍵:name,值:張三)age=20(鍵:age,值:20)
二、Spring MVC 處理參數(shù)的核心步驟
Spring MVC 接收到分割后的鍵值對后,會按照以下邏輯匹配方法參數(shù),這也是參數(shù)名必須一致、順序可以任意的根本原因:
步驟 1:解析請求參數(shù),生成 “參數(shù)鍵值對映射表”
Spring 會先把所有請求參數(shù)(不管是 URL 里的、表單里的)解析成一個 **Map<String, String>結(jié)構(gòu)的映射表 **(鍵是參數(shù)名,值是參數(shù)值)。比如上面的例子,映射表就是:
{
"name": "張三",
"age": "20"
}
步驟 2:根據(jù)方法的參數(shù)名,從映射表中 “按名取值”
Spring MVC 會獲取后端方法的參數(shù)名(如r3(String name, Integer age)中的name和age),然后根據(jù)參數(shù)名去映射表中查找對應(yīng)的值,找到后再進行類型轉(zhuǎn)換(比如把字符串"20"轉(zhuǎn)成Integer類型),最后把值傳遞給方法參數(shù)。
三、為什么 “順序可以不一樣,名字必須一樣”?
1. 順序可以不一樣:因為參數(shù)是 “鍵值對”,不是 “位置依賴”
HTTP 參數(shù)是鍵值對結(jié)構(gòu),核心是key(參數(shù)名),而非參數(shù)在 URL 中的順序。比如:
/param/r4?name=張三&age=20/param/r4?age=20&name=張三
這兩個請求的參數(shù)順序不同,但解析后的映射表完全一樣,Spring MVC 按名取值的結(jié)果也完全一樣,所以方法接收的參數(shù)值不會受影響。
2. 名字必須一樣:因為 Spring 是 “按名匹配”,不是 “按位置匹配”
如果前端傳遞的參數(shù)名和方法參數(shù)名不一致,Spring MVC 在映射表中找不到對應(yīng)的鍵,參數(shù)值就會變成null(除非用@RequestParam指定別名)。比如:前端請求:/param/r4?username=張三&age=20(參數(shù)名是username,不是name)后端方法:public String r3(String name, Integer age)此時name參數(shù)會是null,因為映射表中只有username,沒有name這個鍵。
四、補充:如果想讓參數(shù)名不一致怎么辦?用@RequestParam指定別名
如果前端傳遞的參數(shù)名和后端方法參數(shù)名不一樣,可以通過@RequestParam注解顯式指定參數(shù)名的映射關(guān)系,這是實際開發(fā)中很常用的技巧:
@RequestMapping("/r4")
public String r3(
@RequestParam("username") String name, // 前端傳username,后端用name接收
Integer age
) {
return String.format("接受到參數(shù):姓名[%s], age[%d]", name, age);
}
此時前端請求/param/r4?username=張三&age=20,就能正確接收到name=張三了。
2.4.3 傳遞對象
如果參數(shù)比較多時,方法聲明就需要有很多形參.并且后續(xù)每次新增?個參數(shù),也需要修改方法聲明. 我們不妨把這些參數(shù)封裝為?個對象. Spring MVC也可以自動實現(xiàn)對象參數(shù)的賦值,比如Person對象
如果參數(shù)比較多時,方法聲明就需要有很多形參.并且后續(xù)每次新增?個參數(shù),也需要修改方法聲明. 我們不妨把這些參數(shù)封裝為?個對象.
Spring MVC也可以?動實現(xiàn)對象參數(shù)的賦值,比如Person對象
public class Person {
private int id;
private String name;
private String password;
public int getId() {
return id;
}
public void setId(int 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;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}傳遞對象代碼實現(xiàn):
@RequestMapping("/m3")
public Object method3(Person p){
return p.toString();
}使用瀏覽器發(fā)送請求并傳參:http://127.0.0.1:8080/param/m3?id=5&name=zhangsan&password=123456

Spring 會根據(jù)參數(shù)名稱自動綁定到對象的各個屬性上,如果某個屬性未傳遞,則賦值為null(基本類型則 賦值為默認初識值,比如int類型的屬性,會被賦值為0)
2.4.4 后端參數(shù)重命名(后端參數(shù)映射)
某些特殊的情況下,前端傳遞的參數(shù) key 和我們后端接收的 key 可以不一致,比如前端傳遞了一個 time 給后端,而后端是使用 createtime 字段來接收的,這樣就會出現(xiàn)參數(shù)接收不到的情況,如果出現(xiàn)這種情況,我們就可以使用 @RequestParam 來重命名前后端的參數(shù)值。
具體示例如下,后端實現(xiàn)代碼:
@RequestMapping("/r6")
public String r5(@RequestParam("sa") String name){
return "接受到參數(shù): " + name;
}可以看到,Spring 可以正確的把瀏覽器傳遞的參數(shù) time 綁定到了后端參數(shù)name 參數(shù)上此時,如果瀏覽器使用 name 進行參數(shù)傳遞呢?訪問 URL:

fildder的使用查看

可以得出結(jié)論:
- 使用
@RequestParam進行參數(shù)重命名時,請求參數(shù)只能和@RequestParam聲明的名稱一致,才能進行參數(shù)綁定和賦值. - 使用
@RequestParam進行參數(shù)重命名時,參數(shù)就變成了必傳參數(shù).
非必傳參數(shù)設(shè)置如果我們的實際業(yè)務(wù)前端的參數(shù)是一個非必傳的參數(shù),針對上述問題,如何解決呢?先來了解下參數(shù)必傳的原因,我們查看@RequestParam注解的實現(xiàn)細節(jié)就可以發(fā)現(xiàn)端倪,注解實現(xiàn)如下:
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}可以看到required的默認值為 true, 表示含義就是:該注解修飾的參數(shù)默認為必傳既然如此,我們可以通過設(shè)置@RequestParam中的 required=false 來避免不傳遞時報錯,具體實現(xiàn)如下:
@RequestMapping("/m4")
public Object method4(@RequestParam(value = "time", required = false) String createtime) {
return "接收到參數(shù)createtime:" + createtime;
}
可以看到,添加 required=false 之后,time 前面也加了 key, 變成了 value = "time"注解屬性賦值時,沒有指明 key 的話,默認為 value 屬性.如果需要有多個屬性進行賦值時,需要寫上 key
2.4.5 傳遞數(shù)組
Spring MVC可以?動綁定數(shù)組參數(shù)的賦值
后端實現(xiàn)代碼:
@RequestMapping("/m5")
public String method5(String[] arrayParam) {
return "返回的數(shù)組:" + Arrays.toString(arrayParam);
}使用瀏覽器發(fā)送請求并傳參:數(shù)組參數(shù):請求參數(shù)名與形參數(shù)組名稱相同且請求參數(shù)為多個,后端定義數(shù)組類型形參即可接收參數(shù)
http://127.0.0.1:8080/param/m5?arrayParam=zhangsan&arrayParam=lisi&arrayParam=wangwu或者使用或者使用 http://127.0.0.1:8080/param/m5?arrayParam=zhangsan,lisi,wangwu瀏覽器響應(yīng)結(jié)果:

可以看到后端對數(shù)組參數(shù)進行了正確的接收和響應(yīng).
或者使?Postman來發(fā)送請求

2.4.6 傳遞集合
2.4.6 傳遞集合集合參數(shù):和數(shù)組類似,同一個請求參數(shù)名有多個,且需要使用 @RequestParam 綁定參數(shù)關(guān)系默認情況下,請求中參數(shù)名相同的多個值,是封裝到數(shù)組。如果要封裝到集合,要使用@RequestParam 綁定參數(shù)關(guān)系請求方式和數(shù)組類似:
瀏覽器傳參:
方式一: http://127.0.0.1:8080/param/m6?listParam=zhangsan&listParam=lisi&listParam=wangwu
方式二::http://127.0.0.1:8080/param/m6?listParam=zhangsan%2clisi%2cwangwu
%2c 是逗號的轉(zhuǎn)義編碼,解碼后的 url 為: http://127.0.0.1:8080/param/m6listParam=zhangsan,lisi,wangwu
后端接收代碼:
@RequestMapping ("/m6")
public String method6 (@RequestParam List<String> listParam){
return "size:"+listParam.size() + ",listParam:"+listParam;
}
2.4.7 傳遞 JSON 數(shù)據(jù)
JSON 概念
JSON: JavaScript Object Notation【JavaScript 對象表示法】JSON 是一種輕量級的數(shù)據(jù)交互格式。它基于 ECMAScript (歐洲計算機協(xié)會制定的 js 規(guī)范) 的一個子集,采用完全獨立于編程語言的文本格式來存儲和表示數(shù)據(jù)。-- 百度百科簡單來說: JSON 就是一種數(shù)據(jù)格式,有自己的格式和語法,使用文本表示一個對象或數(shù)組的信息,因此JSON 本質(zhì)是字符串。主要負責(zé)在不同的語言中數(shù)據(jù)傳遞和交換.
類似于:?國際通用語言 - 英語?中國 56 個民族不同地區(qū)的通用語言 - 普通話有自己的語法,其他語言也認識.
JSON 與 Javascript 的關(guān)系
沒有關(guān)系,只是語法相似,js 開發(fā)者能更快的上手而已,但是他的語法本身比較簡單,所以也很好學(xué)
JSON 語法
JSON 是一個字符串,其格式非常類似于 JavaScript 對象字面量的格式
我們先來看一段 JSON 數(shù)據(jù)
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
},
{
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
"powers": ["Million tonne punch", "Damage resistance", "Superhuman reflexes"]
},
{
"name": "Eternal Flame",
"age": 1000000,
"secretIdentity": "Unknown",
"powers": ["Immortality", "Heat Immunity", "Inferno", "Teleportation", "Interdimensional travel"]
}
]
}- 小隊基礎(chǔ)信息
"squadName": "Super hero squad":小隊名稱(超級英雄小隊)"homeTown": "Metro City":家鄉(xiāng)(大都會城)"formed": 2016:成立年份(2016 年)"secretBase": "Super tower":秘密基地(超級塔樓)"active": true:是否活躍(是)
- 成員列表(
"members"是數(shù)組)數(shù)組里包含 3 個英雄對象,每個對象描述一個英雄的信息: - 第一個英雄(Molecule Man)
"name": "Molecule Man":姓名"age": 29:年齡"secretIdentity": "Dan Jukes":秘密身份"powers": [...]:超能力(抗輻射、變小、輻射爆炸)
- 第二個英雄(Madame Uppercut)
"name": "Madame Uppercut":姓名"age": 39:年齡"secretIdentity": "Jane Wilson":秘密身份"powers": [...]:超能力(百萬噸拳、抗傷害、超人反應(yīng))
- 第三個英雄(Eternal Flame)
"name": "Eternal Flame":姓名"age": 1000000:年齡(100 萬歲)"secretIdentity": "Unknown":秘密身份(未知)"powers": [...]:超能力(永生、耐熱、地獄火、 teleportation、跨維度旅行)
可以壓縮表示
{"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":[{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":["Radiation resistance","Turning tiny","Radiation blast"]},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":["Million tonne punch","Damage resistance","Superhuman reflexes"]},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":["Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"]}]}JSON 的語法:
- 數(shù)據(jù)在 鍵值對 (Key/Value) 中
- 數(shù)據(jù)由逗號
,分隔 - 對象用
{}表示 - 數(shù)組用
[]表示 - 值可以為對象,也可以為數(shù)組,數(shù)組中可以包含多個對象

JSON 的兩種結(jié)構(gòu)
- 對象:大括號
{}保存的對象是一個無序的 鍵值對 集合。一個對象以左括號{開始,右括號}結(jié)束。每個 "鍵" 后跟一個冒號:,鍵值對使用逗號,分隔 - 數(shù)組:中括號
[]保存的數(shù)組是值(value)的有序集合。一個數(shù)組以左中括號[開始,右中括號]結(jié)束,值之間使用逗號,分隔。
可 以使?在線JSON格式化?具來進?校驗和書寫:在線JSON校驗格式化?具(BeJSON)
JSON 字符串和 Java 對象互轉(zhuǎn)
JSON 本質(zhì)上是一個字符串,通過文本來存儲和描述數(shù)據(jù)
Spring MVC 框架也集成了 JSON 的轉(zhuǎn)換工具,我們可以直接使用,來完成 JSON 字符串和 Java 對象的互轉(zhuǎn)本質(zhì)上是 jackson-databind 提供的功能,Spring MVC 框架中已經(jīng)把該工具包引入了進來,咱們直接使用即可,如果脫離 Spring MVC 使用,需要引入相關(guān)依賴
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.5</version>
</dependency>JSON 的轉(zhuǎn)換工具包有很多,jackson-databind 只是其中的一種.

public class JSONUtils {
private static ObjectMapper objectMapper = new ObjectMapper();
public static void main(String[] args) throws JsonProcessingException {
Person person = new Person();
person.setId(5);
person.setName("zhangsan");
person.setPassword("123456");
//對象轉(zhuǎn)為JSON字符串
String jsonStr = objectMapper.writeValueAsString(person);
System.out.println("JSON字符串為:"+jsonStr);
//JSON字符串轉(zhuǎn)為對象
Person p = objectMapper.readValue(jsonStr,Person.class);
System.out.println("轉(zhuǎn)換的對象 id:"+p.getId()+",name:"+p.getName()+",password:"+p.getPassword());
}
}使用 ObjectMapper 對象提供的兩個方法,可以完成對象和 JSON 字符串的互轉(zhuǎn)
- writeValueAsString: 把對象轉(zhuǎn)為 JSON 字符串
- readValue: 把字符串轉(zhuǎn)為對象
JSON 優(yōu)點
- 簡單易用:語法簡單,易于理解和編寫,可以快速地進行數(shù)據(jù)交換
- 跨平臺支持: JSON 可以被多種編程語言解析和生成,可以在不同的平臺和語言之間進行數(shù)據(jù)交換和傳輸
- 輕量級:相較于 XML 格式,JSON 數(shù)據(jù)格式更加輕量級,傳輸數(shù)據(jù)時占用帶寬較小,可以提高數(shù)據(jù)傳輸速度
- 易于擴展: JSON 的數(shù)據(jù)結(jié)構(gòu)靈活,支持嵌套對象和數(shù)組等復(fù)雜的數(shù)據(jù)結(jié)構(gòu),便于擴展和使用
- 安全性: JSON 數(shù)據(jù)格式是一種純文本格式,不包含可執(zhí)行代碼,不會執(zhí)行惡意代碼,因此具有較高的安全性
基于以上特點,JSON 在 Web 應(yīng)用程序中被廣泛使用,如前后端數(shù)據(jù)交互、API 接口數(shù)據(jù)傳輸?shù)?
| 維度 / 格式 | Protobuf | JSON | XML |
|---|---|---|---|
| 輕量級(評分) | 1(最優(yōu)) | 2(中等) | 3(最差) |
| 可讀性(評分) | 3(最差) | 2(中等) | 1(最優(yōu)) |
| 典型適用場景 | 高性能 / 低空間要求的數(shù)據(jù)交互 | 通用數(shù)據(jù)交互(兼顧輕量與可讀) | 配置文件(可讀性優(yōu)先) |
傳遞 JSON 對象
接收 JSON 對象,需要使用 @RequestBody 注解
RequestBody: 請求正文,意思是這個注解作用在請求正文的數(shù)據(jù)綁定,請求參數(shù)必須在寫在請求正文中
后端實現(xiàn):
@RequestMapping(value = "/m7")
public Object method7(@RequestBody Person person) {
return person.toString();
}
使用 Postman 來發(fā)送 json 請求參數(shù):


可以看到,后端正確接收了 通過Fiddler觀察?下請求參數(shù)


嘗試去除掉 @RequestBody 試試
@RequestMapping(value = "/m7")
public Object method7(Person person) {
return person.toString();
}請求響應(yīng)結(jié)果如下

后端未能成功給Person對象賦值.
2.4.8 獲取 URL 中參數(shù) @PathVariable
path variable: 路徑變量和字面表達的意思一樣,這個注解主要作用在請求 URL 路徑上的數(shù)據(jù)綁定默認傳遞參數(shù)寫在 URL 上,SpringMVC 就可以獲取到
后端實現(xiàn)代碼:
@RequestMapping("/m8/{id}/{name}")
public String method8(@PathVariable Integer id, @PathVariable("name") String userName){
return "解析參數(shù)id:"+id+",name:"+userName;
}
使用瀏覽器發(fā)送請求: http://127.0.0.1:8080/param/m8/5/zhangsan或者使用 Postman 發(fā)送請求
@RequestMapping("/m8/{id}/{name}")- 這是 URL 路徑的占位符寫法:
{id}和{name}是路徑中的動態(tài)參數(shù)(占位符),表示訪問/m8/xxx/xxx時,xxx會被解析為對應(yīng)的參數(shù)值。
- 這是 URL 路徑的占位符寫法:
- 示例請求 URL:
http://127.0.0.1:8080/m8/100/spring(此時id=100,name=spring)。 public String method8(@PathVariable Integer id, @PathVariable("name") String userName)@PathVariable:Spring MVC 的注解,用于綁定 URL 路徑中的占位符參數(shù)到方法參數(shù)。- 第一個參數(shù)
@PathVariable Integer id:路徑中{id}的參數(shù)值會直接綁定到id(因為參數(shù)名和占位符名稱一致)。 - 第二個參數(shù)
@PathVariable("name") String userName:路徑中{name}的參數(shù)值,通過("name")指定占位符名稱,綁定到方法參數(shù)userName(參數(shù)名和占位符名稱不一致時,必須顯式指定)。
- 第一個參數(shù)
return "解析參數(shù)id:"+id+",name:"+userName;- 將接收到的
id和userName拼接成字符串返回,作為響應(yīng)結(jié)果。
URL 傳參方式的驗證思路說明:
那我們看他是不是用了url進行傳參,就是把你給查詢字符串(?后面的東西刪除)

看看頁面還正常使用么,如果可以就是使用了

2.4.9 上傳文件 @RequestPart
后端代碼實現(xiàn):
@RequestMapping("/m9")
public String getfile(@RequestPart("file") MultipartFile file) throws IOException {
//獲取文件名稱
String fileName = file.getOriginalFilename();
//文件上傳到指定路徑
file.transferTo(new File("D:/temp/" + file.getOriginalFilename()));
return "接收到文件名稱為: "+fileName;
}使用 Postman 發(fā)送請求:
postman form-data
- 含義:多部分表單數(shù)據(jù)(對應(yīng) HTTP 的
multipart/form-data格式)。 - 用途:
- 同時傳文件和普通參數(shù)(比如上傳文件 + 傳字符串參數(shù));
- 支持復(fù)雜數(shù)據(jù)結(jié)構(gòu)(鍵值對、文件)。
- 典型場景:文件上傳接口(比如你之前的
@RequestPart接口)。
使用 Postman 發(fā)送請求:

2.4.10 獲取 Cookie/Session
回顧 CookieHTTP 協(xié)議
自身是屬于 "無狀態(tài)" 協(xié)議."無狀態(tài)" 的含義指的是:
默認情況下 HTTP 協(xié)議的客戶端和服務(wù)器之間的這次通信,和下次通信之間沒有直接的聯(lián)系.
但是實際開發(fā)中,我們很多時候是需要知道請求之間的關(guān)聯(lián)關(guān)系的.
例如登陸網(wǎng)站成功后,第二次訪問的時候服務(wù)器就能知道該請求是否是已經(jīng)登陸過了.

上述圖中的 “令牌” 通常就存儲在 Cookie 字段中.比如去醫(yī)院掛號
- 看病之前先掛號。掛號時候需要提供身份證號,同時得到了一張 "就診卡", 這個就診卡就相當(dāng)于患者的 "令牌".
- 后續(xù)去各個科室進行檢查,診斷,開藥等操作,都不必再出示身份證了,只要憑就診卡即可識別出當(dāng)前患者的身份.
- 看完病了之后,不想要就診卡了,就可以注銷這個卡。此時患者的身份和就診卡的關(guān)聯(lián)就銷毀了.(類似于網(wǎng)站的注銷操作)
- 又來看病,可以辦一張新的就診卡,此時就得到了一個新的 "令牌"
此時在服務(wù)器這邊就需要記錄 "令牌" 信息,以及令牌對應(yīng)的用戶信息,這個就是 Session 機制所做的工作.
理解 Session
我們先來了解一下什么是會話.會話:對話的意思

在計算機領(lǐng)域,會話是一個客戶與服務(wù)器之間的不中斷的請求響應(yīng)。對客戶的每個請求,服務(wù)器能夠識別出請求來自于同一個客戶。當(dāng)一個未知的客戶向 Web 應(yīng)用程序發(fā)送第一個請求時就開始了一個會話。當(dāng)客戶明確結(jié)束會話或服務(wù)器在一個時限內(nèi)沒有接受到客戶的任何請求時,會話就結(jié)束了.
比如我們打客服
電話每次打客服電話,是一個會話。
掛斷電話,會話就結(jié)束了下次再打客服電話,又是一個新的會話.
如果我們長時間不說話,沒有新的請求,會話也會結(jié)束.
服務(wù)器同一時刻收到的請求是很多的。服務(wù)器需要清楚的區(qū)分每個請求是屬于哪個用戶,也就是屬于哪個會話,就需要在服務(wù)器這邊記錄每個會話以及與用戶的信息的對應(yīng)關(guān)系.
Session 是服務(wù)器為了保存用戶信息而創(chuàng)建的一個特殊的對象.

Session的本質(zhì)就是?個"哈希表",存儲了?些鍵值對結(jié)構(gòu).Key就是SessionID,Value就是??信息(? ?信息可以根據(jù)需求靈活設(shè)計).

SessionId 是由服務(wù)器生成的一個 "唯一性字符串", 從 Session 機制的角度來看,這個唯一性字符串稱為 "SessionId". 但是站在整個登錄流程中看待,也可以把這個唯一性字符串稱為 "token".上述例子中的令牌 ID, 就可以看做是 SessionId, 只不過令牌除了 ID 之外,還會帶一些其他信息,比如時間,簽名等.

- 當(dāng)用戶登陸的時候,服務(wù)器在 Session 中新增一個新記錄,并把 sessionId 返回給客戶端.(通過 HTTP 響應(yīng)中的 Set-Cookie 字段返回).
- 客戶端后續(xù)再給服務(wù)器發(fā)送請求的時候,需要在請求中帶上 sessionId.(通過 HTTP 請求中的 Cookie 字段帶上).
- 服務(wù)器收到請求之后,根據(jù)請求中的 sessionId 在 Session 信息中獲取到對應(yīng)的用戶信息,再進行后續(xù)操作。找不到則重新創(chuàng)建 Session, 并把 SessionID 返回

Session 默認是保存在內(nèi)存中的.如果重啟服務(wù)器則Session數(shù)據(jù)就會丟失
Cookie 和 Session 的區(qū)別
- Cookie 是客戶端保存用戶信息的一種機制. Session 是服務(wù)端保存用戶信息的一種機制.
- Cookie 和 Session 之間主要是通過 SessionId 關(guān)聯(lián)起來的,SessionId 是 Cookie 和 Session 之間的橋梁
- Cookie 和 Session 經(jīng)常會在一起配合使用。但是不是必須配合.
- 完全可以用 Cookie 來保存一些數(shù)據(jù)在客戶端。這些數(shù)據(jù)不一定是用戶身份信息,也不一定是 SessionId
- Session 中的 sessionId 也不需要非得通過 Cookie/Set-Cookie 傳遞,比如通過 URL 傳遞.
獲取Cookie
傳統(tǒng)獲取Cookie
@RequestMapping("/getCookie")
public String getCookie (HttpServletRequest request ,HttpServletresponse){
Cookie[] cookies = request.getCookies();
StringBuilder stringBuilder = new StringBuilder();
if(cookies != null){
for ( Cookie cookie :cookies) {
stringBuilder.append("這個cookie 的名字是").append(cookie.getName()).append(cookie.getValue()).append("/n");
}
}else {
stringBuilder.append("這個cookies 里面沒有任何值 ");
}
return stringBuilder.toString();
}F12開發(fā)者工具也很好用

補充說明
Spring MVC 是基于 Servlet API 構(gòu)建的原始 Web 框架,也是在 Servlet 的基礎(chǔ)上實現(xiàn)的
HttpServletRequest , HttpServletResponse 是 Servlet 提供的兩個類,是 Spring MVC 方法的內(nèi)置對象,需要時直接在方法中添加聲明即可.
HttpServletRequest 對象代表客戶端的請求,當(dāng)客戶端通過 HTTP 協(xié)議訪問服務(wù)器時,HTTP 請求頭中的所有信息都封裝在這個對象中,通過這個對象提供的方法,可以獲得客戶端請求的所有信息.
HttpServletResponse 對象代表服務(wù)器的響應(yīng).HTTP 響應(yīng)的信息都在這個對象中,比如向客戶端發(fā)送的數(shù)據(jù),響應(yīng)頭,狀態(tài)碼等。通過這個對象提供的方法,可以獲得服務(wù)器響應(yīng)的所有內(nèi)容
Spring MVC 在這兩個對象的基礎(chǔ)上進行了封裝,給我們提供更加簡單的使用方法.
使用注解的傳遞單個Cookie
//使用注解傳遞的值
@RequestMapping("/getTwoRequest")
public String getCookie(@CookieValue("name") String cookie){
return " 這個值是 " + cookie;
}
獲取 Session
Session 存儲和獲取
Session 是服務(wù)器端的機制,我們需要先存儲,才能再獲取Session 也是基于 HttpServletRequest 來存儲和獲取的
Session 存儲
@RequestMapping("/setSess")
public String setsess(HttpServletRequest request) {
// 獲取Session對象
HttpSession session = request.getSession();
if (session != null) {
session.setAttribute("username", "java");
}
return "session 存儲成功";
}
獲取 Session 有兩種方式
HttpSession getSession(boolean create); HttpSession getSession();
HttpSession getSession(boolean create):參數(shù)如果為true,則當(dāng)不存在會話時新建會話;參數(shù)如果為false,則當(dāng)不存在會話時返回nullHttpSession getSession():和getSession(true)含義一樣,默認值為true。void setAttribute(String name, Object value):使用指定的名稱綁定一個對象到該 session 會話
Session 讀取
讀取 Session 可以使用 HttpServletRequest
@RequestMapping("/getSess")
public String sess(HttpServletRequest request) {
// 如果 session 不存在,不會自動創(chuàng)建
HttpSession session = request.getSession(false);
String username = null;
if (session != null && session.getAttribute("username") != null) {
username = (String) session.getAttribute("username");
}
return "username: " + username;
}
Object getAttribute(String name):返回在該 session 會話中具有指定名稱的對象,如果沒有指定名稱的對象,則返回null。
運行
先設(shè)置 Session: http://127.0.0.1:8080/param/setSess
先設(shè)置Session:http://127.0.0.1:8080/param/setSess
通過Fiddler觀察Http請求和響應(yīng)

可以看到,Http響應(yīng)中,通過Set-Cookie告知客?端,把SessionID存儲在Cookie中 通過瀏覽器,可以觀察到運?結(jié)果:

可以看到,Http請求時,把SessionId通過Cookie傳遞到了服務(wù)器.
通過SpringMVC內(nèi)置對象HttpSession來獲
@RequestMapping("/getSess2")
public String sess2(@SessionAttribute(value = "username",required = false)
String username) {
return "username: "+username;
}
運行結(jié)果(getSess2)
地址:http://127.0.0.1:8080/param/getSess2頁面顯示:username: java
簡潔獲取 Session (2)
通過 Spring MVC 內(nèi)置對象 HttpSession 來獲取
代碼 2
@RequestMapping("/getSess3")
public String sess3(HttpSession session) {
String username = (String)session.getAttribute("username");
return "username: "+username;
}
補充說明
HttpSession session = request.getSession();Session 不存在的話,會自動進行創(chuàng)建
運行結(jié)果(getSess3)
地址:http://127.0.0.1:8080/param/getSess3頁面顯示:username: java
2.4.11 獲取 Header
傳統(tǒng)獲取 header
獲取 Header 也是從 HttpServletRequest 中獲取
@RequestMapping("/param10")
public String param10(HttpServletRequest request, HttpServletResponse response)
{
String userAgent = request.getHeader("User-Agent");
return name + ":" + userAgent;
}
- 使用 HttpServletRequest 提供的 getHeader 方法來獲取,參數(shù)對應(yīng) HTTP 請求報頭的 "Key"
運行結(jié)果:

補充說明
通過 Fiddler 觀察,獲取的 User-Agent 是否正確

簡潔獲取 Header
@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String userAgent) {
return "userAgent: " + userAgent;
}
@RequestHeader注解的參數(shù)值為 HTTP 請求報頭中的 "Key"
運行結(jié)果
地址:http://127.0.0.1:8080/param/getHeader2

到此這篇關(guān)于Spring MVC 請求參數(shù)處理全解析的文章就介紹到這了,更多相關(guān)Spring MVC請求參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 在Spring MVC中處理請求參數(shù)的方法總結(jié)
- SpringMvc請求處理參數(shù)?和?響應(yīng)數(shù)據(jù)處理的示例詳解
- SpringMVC中Controller層獲取前端請求參數(shù)的方式匯總
- SpringMVC獲取請求參數(shù)的方法詳解
- SpringMVC打印請求參數(shù)和響應(yīng)數(shù)據(jù)最優(yōu)方案
- springMVC獲取請求參數(shù)的幾種方式匯總
- springmvc接口接收參數(shù)與請求參數(shù)格式的整理
- 詳解在Spring MVC或Spring Boot中使用Filter打印請求參數(shù)問題
相關(guān)文章
springboot不同環(huán)境使用不同配置文件打包方式
這篇文章主要介紹了springboot不同環(huán)境使用不同配置文件打包方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
基于bufferedreader的read()與readline()讀取出錯原因及解決
這篇文章主要介紹了bufferedreader的read()與readline()讀取出錯原因及解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
Spring?MVC和springboot靜態(tài)資源處理問題
這篇文章主要介紹了Spring?MVC和springboot靜態(tài)資源處理問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
elasticsearch 8.2.3 安裝及springboot簡單使用
這篇文章主要介紹了elasticsearch 8.2.3 安裝及springboot簡單使用,本文通過示例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06
關(guān)于SpringBoot mysql數(shù)據(jù)庫時區(qū)問題
在后端開發(fā)過程中經(jīng)常會遇到幾個時區(qū)設(shè)置問題,今天分幾種情況給大家介紹SpringBoot mysql數(shù)據(jù)庫時區(qū)問題,感興趣的朋友跟隨小編一起看看吧2021-06-06
通過Spring Boot + Mybatis + Redis快速搭建現(xiàn)代化Web項目
本篇文章介紹了如何通過Spring Boot、Mybatis以及Redis快速搭建一個現(xiàn)代化的Web項目,并且同時介紹了如何在Spring Boot下優(yōu)雅地書寫單元測試來保證我們的代碼質(zhì)量。具體內(nèi)容詳情大家通過本文學(xué)習(xí)下吧2017-12-12
SpringBoot整合ElasticSearch的示例代碼
本篇文章主要介紹了SpringBoot整合ElasticSearch的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09
jackson 如何將實體轉(zhuǎn)json json字符串轉(zhuǎn)實體
這篇文章主要介紹了jackson 實現(xiàn)將實體轉(zhuǎn)json json字符串轉(zhuǎn)實體,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10

