@requestbody是什么?
@requestbody是 spring mvc/spring boot 中处理 http 请求的核心注解,它的核心作用是:将 http 请求体中的数据(通常是 json/xml 格式)自动解析并绑定到方法的参数对象上。
spring mvc 框架默认参数解析行为:
在默认配置下,spring mvc 的请求参数解析器(handlermethodargumentresolver)仅会解析符合 application/x-www-form-urlencoded 媒体类型的请求参数(如 url 路径参数、查询字符串参数、表单提交的键值对参数),不会主动读取 http 请求体的 json 数据,也不支持将请求体中的 json 格式数据自动绑定到控制器方法的参数对象上。
@requestbody 注解用于声明控制器方法的参数需从 http 请求体中获取数据,并触发 spring mvc 的消息转换器(httpmessageconverter)完成以下核心操作:
读取请求体中的原始字符数据(通常为 json 格式);
根据参数声明的 java 类型,将 json 数据反序列化为对应的 java 对象;
将反序列化后的 java 对象注入到控制器方法的参数中,完成参数绑定。
简言之,该注解覆盖了 spring mvc 对参数来源的默认规则,明确指定参数数据来源为 http 请求体,并自动完成 json 到 java 对象的转换,把字段值一一赋值进去。
是否需要加@requestbody
| 场景 | 是否需要加 @requestbody | 备注 |
|---|---|---|
| post/put 请求 | ✅ 必须加 | 参数是 json 格式(放在请求体) |
| get 请求 | ❌ 不能加 | get 请求没有请求体,参数只能在 url 中 |
| 表单提交 | ❌ 不加 | 用 @requestparam 或直接绑定对象即可 |
| 参数是 xml 格式 | ✅ 必须加 | 解析请求体中的 xml 数据 |
场景 1:传统表单提交(最常见,无需加 @requestbody)
这是原生 <form> 标签或前端模拟的表单提交,特征是:
请求头 content-type: application/x-www-form-urlencoded;
参数以 key1=value1&key2=value2 的形式放在请求体。
场景 2:带文件的表单提交(multipart/form-data,无需加 @requestbody)
如果表单包含文件上传,请求头是 content-type: multipart/form-data,同样不需要加 @requestbody,需用 @requestparam/@requestpart 接收
场景 3:伪表单提交(实际是 json,需要加 @requestbody)
有些前端会用表单提交的写法,但实际传的是 json 数据:
请求头 content-type: application/json;
参数是 json 字符串(而非 key=value),放在请求体中。
这种场景本质是json 请求体提交,只是前端写法像表单,必须加 @requestbody
伪表单提交举例
前端用表单提交的写法,但实际传的是 json 数据,伪表单提交举例如下
表单提交的代码:视觉和交互层面,用了 element ui 的 <el-form> 组件,搭配 <el-form-item>、<el-input>、<el-radio-group> 等表单类组件,呈现出表单填写的形态,符合前端开发中表单写法的认知。
<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="请输入摄像头名称" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="ip地址" prop="macid">
<el-input v-model="dataform.macid" placeholder="请输入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">进场</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="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="请输入排序号" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="dataform.remark" placeholder="请输入备注" />
</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 对象做双向绑定,每个表单项都直接关联 dataform 的子字段,里面包含了摄像头的所有信息:
dataform: {
camerainfoid: '',
communityid: '',
cameraname: '',
macid: '',
direction: '1',
seq: '1',
state: 1,
remark: ''
}
这是多个字段组成的复杂数据,不是单个的键值对,而是一个完整的对象
再看前端的数据提交时把完整对象传给后端,点击确定按钮触发的自定义的 dataformsubmit() 方法,触发异步请求:
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
})
}
先校验表单,通过后把 dataform 的所有字段组装成param对象(和dataform内容一致);
判断是新增 / 编辑:
新增:调用add(param),对应 post 请求,把param作为data传给后端;
编辑:调用edit(param),对应 put 请求,同样把param作为data传给后端
前端向后端发新增的 http 请求的过程
请求 url为:/sys/camera/add
request body 请求体为:传输的是 json 数据
{
"camerainfoid": 0,
"communityid": "19",
"cameraname": "1号摄像头",
"macid": "127.0.0.1",
"direction": 2,
"seq": "2",
"state": 1,
"remark": "高清摄像头"
}
content-type 请求头:content-type: application/json
其中 application/json 是 http 标准定义的媒体类型,专门表示请求体里的数据是 json 格式的字符串
前端的 request 库(本质是 axios)会把 data 参数(也就是param对象)这个 javascript 对象转换成 json 字符串,再把这个 json 字符串放在 http 请求的请求体(request body)里(而不是 url 里),且自动添加 content-type: application/json 请求头。
后端接收到请求后,先读取 content-type 再决定用哪种解析规则处理请求体,当看到请求头时 content-type: application/json,spring 会用json 解析器把请求体的 json 字符串解析成 java 对象。
不管是新增(post)还是编辑(put)都要传递多个字段的完整摄像头对象,这些数据量大且结构复杂,不可能拼在 url 里(url 长度有限、不安全、格式不支持),前端把完整对象通过data参数放在请求体里传输,后端读取请求体里的 json,因此必须加@requestbody。
总结:spring mvc 中,默认情况下参数绑定是从 url 或表单(x-www-form-urlencoded)中解析,只有通过 @requestbody 注解才能让 spring 主动解析请求体中的 json 字符串,并映射到入参的 java 实体类(若不使用该注解,spring 无法自动完成这个绑定)。
到此这篇关于springboot中@requestbody的伪表单提交场景的文章就介绍到这了,更多相关springboot @requestbody表单提交内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论