SpringBoot中@RequestBody的偽表單提交場(chǎng)景
@RequestBody是什么?
@RequestBody是 Spring MVC/Spring Boot 中處理 HTTP 請(qǐng)求的核心注解,它的核心作用是:將 HTTP 請(qǐng)求體中的數(shù)據(jù)(通常是 JSON/XML 格式)自動(dòng)解析并綁定到方法的參數(shù)對(duì)象上。
Spring MVC 框架默認(rèn)參數(shù)解析行為:
在默認(rèn)配置下,Spring MVC 的請(qǐng)求參數(shù)解析器(HandlerMethodArgumentResolver)僅會(huì)解析符合 application/x-www-form-urlencoded 媒體類型的請(qǐng)求參數(shù)(如 URL 路徑參數(shù)、查詢字符串參數(shù)、表單提交的鍵值對(duì)參數(shù)),不會(huì)主動(dòng)讀取 HTTP 請(qǐng)求體的 JSON 數(shù)據(jù),也不支持將請(qǐng)求體中的 JSON 格式數(shù)據(jù)自動(dòng)綁定到控制器方法的參數(shù)對(duì)象上。
@RequestBody 注解用于聲明控制器方法的參數(shù)需從 HTTP 請(qǐng)求體中獲取數(shù)據(jù),并觸發(fā) Spring MVC 的消息轉(zhuǎn)換器(HttpMessageConverter)完成以下核心操作:
讀取請(qǐng)求體中的原始字符數(shù)據(jù)(通常為 JSON 格式);
根據(jù)參數(shù)聲明的 Java 類型,將 JSON 數(shù)據(jù)反序列化為對(duì)應(yīng)的 Java 對(duì)象;
將反序列化后的 Java 對(duì)象注入到控制器方法的參數(shù)中,完成參數(shù)綁定。
簡(jiǎn)言之,該注解覆蓋了 Spring MVC 對(duì)參數(shù)來源的默認(rèn)規(guī)則,明確指定參數(shù)數(shù)據(jù)來源為 HTTP 請(qǐng)求體,并自動(dòng)完成 JSON 到 Java 對(duì)象的轉(zhuǎn)換,把字段值一一賦值進(jìn)去。
是否需要加@RequestBody
| 場(chǎng)景 | 是否需要加 @RequestBody | 備注 |
|---|---|---|
| POST/PUT 請(qǐng)求 | ? 必須加 | 參數(shù)是 JSON 格式(放在請(qǐng)求體) |
| GET 請(qǐng)求 | ? 不能加 | GET 請(qǐng)求沒有請(qǐng)求體,參數(shù)只能在 URL 中 |
| 表單提交 | ? 不加 | 用 @RequestParam 或直接綁定對(duì)象即可 |
| 參數(shù)是 XML 格式 | ? 必須加 | 解析請(qǐng)求體中的 XML 數(shù)據(jù) |
場(chǎng)景 1:傳統(tǒng)表單提交(最常見,無需加 @RequestBody)
這是原生 <form> 標(biāo)簽或前端模擬的表單提交,特征是:
請(qǐng)求頭 Content-Type: application/x-www-form-urlencoded;
參數(shù)以 key1=value1&key2=value2 的形式放在請(qǐng)求體。
場(chǎng)景 2:帶文件的表單提交(multipart/form-data,無需加 @RequestBody)
如果表單包含文件上傳,請(qǐng)求頭是 Content-Type: multipart/form-data,同樣不需要加 @RequestBody,需用 @RequestParam/@RequestPart 接收
場(chǎng)景 3:偽表單提交(實(shí)際是 JSON,需要加 @RequestBody)
有些前端會(huì)用表單提交的寫法,但實(shí)際傳的是 JSON 數(shù)據(jù):
請(qǐng)求頭 Content-Type: application/json;
參數(shù)是 JSON 字符串(而非 key=value),放在請(qǐng)求體中。
這種場(chǎng)景本質(zhì)是JSON 請(qǐng)求體提交,只是前端寫法像表單,必須加 @RequestBody
偽表單提交舉例
前端用表單提交的寫法,但實(shí)際傳的是 JSON 數(shù)據(jù),偽表單提交舉例如下
表單提交的代碼:視覺和交互層面,用了 Element UI 的 <el-form> 組件,搭配 <el-form-item>、<el-input>、<el-radio-group> 等表單類組件,呈現(xiàn)出表單填寫的形態(tài),符合前端開發(fā)中表單寫法的認(rèn)知。
<el-form ref="dataForm" :model="dataForm" :rules="dataRule" label-width="100px" style="width:95%;" @keyup.enter.native="dataFormSubmit()">
<el-row>
<el-col :span="24">
<el-form-item label="攝像頭名稱" prop="cameraName">
<el-input v-model="dataForm.cameraName" placeholder="請(qǐng)輸入攝像頭名稱" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="IP地址" prop="macID">
<el-input v-model="dataForm.macID" placeholder="請(qǐng)輸入IP地址(必須唯一)" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="方向" prop="direction">
<el-radio-group v-model="dataForm.direction">
<el-radio :label="1">進(jìn)場(chǎng)</el-radio>
<el-radio :label="2">出場(chǎng)</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="狀態(tài)" prop="state">
<el-radio-group v-model="dataForm.state">
<el-radio :label="1">啟用</el-radio>
<el-radio :label="2">禁用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="排序" prop="seq">
<el-input v-model="dataForm.seq" placeholder="請(qǐng)輸入排序號(hào)" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="備注" prop="remark">
<el-input v-model="dataForm.remark" placeholder="請(qǐng)輸入備注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button type="danger" @click="visible=false">取 消</el-button>
<el-button type="primary" @click="dataFormSubmit()">確 定</el-button>
</span>
表單與 dataForm 對(duì)象做雙向綁定,每個(gè)表單項(xiàng)都直接關(guān)聯(lián) dataForm 的子字段,里面包含了攝像頭的所有信息:
dataForm: {
cameraInfoId: '',
communityId: '',
cameraName: '',
macID: '',
direction: '1',
seq: '1',
state: 1,
remark: ''
}
這是多個(gè)字段組成的復(fù)雜數(shù)據(jù),不是單個(gè)的鍵值對(duì),而是一個(gè)完整的對(duì)象
再看前端的數(shù)據(jù)提交時(shí)把完整對(duì)象傳給后端,點(diǎn)擊確定按鈕觸發(fā)的自定義的 dataFormSubmit() 方法,觸發(fā)異步請(qǐng)求:
dataFormSubmit() {
this.$refs['dataForm'].validate((valid) => {
if (valid) {
const param = {
'cameraInfoId': this.dataForm.cameraInfoId,
'communityId': this.dataForm.communityId,
'cameraName': this.dataForm.cameraName,
'macID': this.dataForm.macID,
'direction': this.dataForm.direction,
'seq': this.dataForm.seq,
'state': this.dataForm.state,
'remark': this.dataForm.remark
}
if (!this.dataForm.cameraInfoId) {
add(param).then(res => {
if (res.code === 200) {
this.visible = false
this.$emit('refreshDataList')
this.$message.success(res.msg)
} else {
this.$message.error(res.msg)
}
})
} else {
edit(param).then(res => {
if (res.code === 200) {
this.visible = false
this.$emit('refreshDataList')
this.$message.success(res.msg)
} else {
this.$message.error(res.msg)
}
})
}
}
})
export function add(data) {
return request({
url: '/sys/camera/add',
method: 'post',
data
})
}
export function edit(data) {
return request({
url: '/sys/camera/edit',
method: 'put',
data
})
}
先校驗(yàn)表單,通過后把 dataForm 的所有字段組裝成param對(duì)象(和dataForm內(nèi)容一致);
判斷是新增 / 編輯:
新增:調(diào)用add(param),對(duì)應(yīng) POST 請(qǐng)求,把param作為data傳給后端;
編輯:調(diào)用edit(param),對(duì)應(yīng) PUT 請(qǐng)求,同樣把param作為data傳給后端
前端向后端發(fā)新增的 HTTP 請(qǐng)求的過程
請(qǐng)求 URL為:/sys/camera/add
Request Body 請(qǐng)求體為:傳輸?shù)氖?JSON 數(shù)據(jù)
{
"cameraInfoId": 0,
"communityId": "19",
"cameraName": "1號(hào)攝像頭",
"macID": "127.0.0.1",
"direction": 2,
"seq": "2",
"state": 1,
"remark": "高清攝像頭"
}
Content-Type 請(qǐng)求頭:Content-Type: application/json
其中 application/json 是 HTTP 標(biāo)準(zhǔn)定義的媒體類型,專門表示請(qǐng)求體里的數(shù)據(jù)是 JSON 格式的字符串
前端的 request 庫(本質(zhì)是 axios)會(huì)把 data 參數(shù)(也就是param對(duì)象)這個(gè) JavaScript 對(duì)象轉(zhuǎn)換成 JSON 字符串,再把這個(gè) JSON 字符串放在 HTTP 請(qǐng)求的請(qǐng)求體(Request Body)里(而不是 URL 里),且自動(dòng)添加 Content-Type: application/json 請(qǐng)求頭。
后端接收到請(qǐng)求后,先讀取 Content-Type 再?zèng)Q定用哪種解析規(guī)則處理請(qǐng)求體,當(dāng)看到請(qǐng)求頭時(shí) Content-Type: application/json,Spring 會(huì)用JSON 解析器把請(qǐng)求體的 JSON 字符串解析成 Java 對(duì)象。
不管是新增(POST)還是編輯(PUT)都要傳遞多個(gè)字段的完整攝像頭對(duì)象,這些數(shù)據(jù)量大且結(jié)構(gòu)復(fù)雜,不可能拼在 URL 里(URL 長(zhǎng)度有限、不安全、格式不支持),前端把完整對(duì)象通過data參數(shù)放在請(qǐng)求體里傳輸,后端讀取請(qǐng)求體里的 JSON,因此必須加@RequestBody。
總結(jié):Spring MVC 中,默認(rèn)情況下參數(shù)綁定是從 URL 或表單(x-www-form-urlencoded)中解析,只有通過 @RequestBody 注解才能讓 Spring 主動(dòng)解析請(qǐng)求體中的 JSON 字符串,并映射到入?yún)⒌?Java 實(shí)體類(若不使用該注解,Spring 無法自動(dòng)完成這個(gè)綁定)。
到此這篇關(guān)于SpringBoot中@RequestBody的偽表單提交場(chǎng)景的文章就介紹到這了,更多相關(guān)SpringBoot @RequestBody表單提交內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 解讀@RequestBody的正確使用方法
- 快速解決SpringMVC @RequestBody 用map接收請(qǐng)求參數(shù)的問題
- 詳解SpringMVC @RequestBody接收J(rèn)son對(duì)象字符串
- @ResponseBody 和 @RequestBody 注解的區(qū)別
- SpringMVC restful 注解之@RequestBody進(jìn)行json與object轉(zhuǎn)換
- springmvc @RequestBody String類型參數(shù)的使用
- 關(guān)于Springboot | @RequestBody 接收到的參數(shù)對(duì)象屬性為空的問題
- Springboot攔截器如何獲取@RequestBody參數(shù)
- 親測(cè)SpringBoot參數(shù)傳遞及@RequestBody注解---踩過的坑及解決
- springMvc注解之@ResponseBody和@RequestBody詳解
相關(guān)文章
java 根據(jù)前端返回的字段名進(jìn)行查詢數(shù)據(jù)
本文介紹了如何在Java中使用SpringDataJPA實(shí)現(xiàn)動(dòng)態(tài)查詢功能,以便根據(jù)前端傳遞的字段名動(dòng)態(tài)構(gòu)建查詢語句,通過創(chuàng)建實(shí)體類、Repository接口、構(gòu)建動(dòng)態(tài)查詢、在Service層和Controller中使用動(dòng)態(tài)查詢,實(shí)現(xiàn)了前后端分離架構(gòu)中的靈活查詢需求2024-11-11
SpringCloud中數(shù)據(jù)認(rèn)證加密的方法總結(jié)
在當(dāng)今分布式系統(tǒng)的日益復(fù)雜和信息傳遞的廣泛網(wǎng)絡(luò)化環(huán)境中,數(shù)據(jù)的加密和認(rèn)證作為保障信息傳遞安全的關(guān)鍵手段,Spring?Cloud,作為一套構(gòu)建微服務(wù)架構(gòu)的強(qiáng)大框架,提供了多種靈活而強(qiáng)大的數(shù)據(jù)加密和認(rèn)證方式,本文給大家總結(jié)了SpringCloud數(shù)據(jù)認(rèn)證加密的方法2024-03-03
java循環(huán)刪除List元素報(bào)錯(cuò)的原因分析與解決
大家在工作中應(yīng)該都會(huì)遇到從List集合中刪除某一個(gè)或多個(gè)元素的業(yè)務(wù)場(chǎng)景,相信大家都會(huì)避開在循環(huán)里面刪除元素,使用其他方式處理,這是為什么呢,下面小編就來和大家詳細(xì)聊聊2023-11-11
Spring Data JPA 簡(jiǎn)單查詢--方法定義規(guī)則(詳解)
下面小編就為大家?guī)硪黄猄pring Data JPA 簡(jiǎn)單查詢--方法定義規(guī)則(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-04-04
java 使用線程做的一個(gè)簡(jiǎn)單的ATM存取款實(shí)例代碼
線程 Thread 類,和 Runable 接口 比較兩者的特點(diǎn)和應(yīng)用領(lǐng)域.可以,直接繼承線程Thread類。該方法編寫簡(jiǎn)單,可以直接操作線程,適用于單重繼承情況,因而不能在繼承其他類,下面我們來看一個(gè)實(shí)例2013-08-08

