PutMapping
本章紧接
@PostMapping的资源创建模式。在 RESTful 架构中,更新资源分为"全量更新"和"局部更新"两种语义。@PutMapping对应 HTTP PUT 方法,表示全量替换资源。理解@PutMapping,就掌握了 Spring MVC 处理资源全量更新的标准方式,以及幂等性在 API 设计中的重要意义。
定义与作用
@PutMapping 是 Spring 4.3 引入的方法级组合注解,它的职责可以用一句话概括:声明一个方法只处理 HTTP PUT 请求,用于全量更新或替换服务器上的资源。
@PutMapping 的源码定义:
@RequestMapping(method = RequestMethod.PUT)
public @interface PutMapping {
// 继承 @RequestMapping 的所有属性
}
它与 @RequestMapping(method = RequestMethod.PUT) 完全等价。
PUT 请求的语义
在 HTTP 协议中,PUT 方法的语义是全量替换资源,具有以下特征:
- 非安全:会改变服务器状态
- 幂等:多次执行相同 PUT 请求,结果与执行一次相同
- 参数在请求体中:通过请求体传递完整资源数据
- 全量更新:请求体应包含资源的完整表示,缺失字段通常被置为 null 或默认值
核心原理
PUT 全量更新的处理流程
图解:PUT 请求的处理流程与 POST 几乎相同,但语义不同:POST 是"创建",PUT 是"全量替换"。
PUT vs POST 对比
| 对比维度 | POST | PUT |
|---|---|---|
| 语义 | 创建资源 | 全量更新/替换资源 |
| 幂等性 | 非幂等 | 幂等 |
| URL 指向 | 资源集合 | 具体资源 |
| 请求体 | 新资源数据 | 资源的完整新状态 |
| 缺失字段 | 不适用(创建) | 通常被清空或设为默认值 |
| HTTP 状态码 | 201 Created | 200 OK 或 204 No Content |
适用位置与常用属性
@PutMapping 只能标注在方法上,继承 @RequestMapping 的所有属性:
| 属性 | 类型 | 作用 | 示例 |
|---|---|---|---|
value / path | String[] | URL 路径映射 | "/{id}" |
params | String[] | 约束请求参数 | "force=true" |
headers | String[] | 约束请求头 | "X-Api-Version=2" |
consumes | String[] | 约束请求 Content-Type | "application/json" |
produces | String[] | 约束响应 Content-Type | "application/json" |
完整示例
场景
飞翔科技的员工管理系统需要支持更新员工信息。HR 修改员工档案时,系统使用 @PutMapping 全量替换员工数据。
控制器代码
package com.feixiang.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/employees")
public class EmployeeController {
// 容器已注入该 Bean,本教程不展开 Service 实现
@Autowired
private EmployeeService employeeService;
// 全量更新员工信息
@PutMapping("/{id}")
public Employee update(@PathVariable Long id,
@RequestBody Employee employee) {
return employeeService.update(id, employee);
}
}
HTTP 请求示例 1:全量更新员工
curl -X PUT http://localhost:8080/employees/1001 \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"name": "张伟",
"department": "市场部",
"position": "市场总监",
"email": "zhangwei_new@feixiang.com",
"phone": "13900139001"
}'
实际响应(HTTP 200 OK):
{
"id": 1001,
"name": "张伟",
"department": "市场部",
"position": "市场总监",
"email": "zhangwei_new@feixiang.com",
"phone": "13900139001",
"updatedAt": "2024-06-15T11:00:00"
}
分析:
@PutMapping("/{id}")声明此方法只处理 PUT 请求@PathVariable提取 URL 中的id=1001@RequestBody将请求体 JSON 反序列化为Employee- Service 层执行全量替换:员工 1001 的所有字段被更新为新值
- 注意:如果请求体中缺少某些字段(如
createdAt),全量更新可能会将其清空
HTTP 请求示例 2:幂等性验证
# 第一次 PUT
curl -X PUT http://localhost:8080/employees/1001 \
-H "Content-Type: application/json" \
-d '{"name":"张伟","department":"市场部","position":"市场总监"}'
# 第二次 PUT(完全相同的请求)
curl -X PUT http://localhost:8080/employees/1001 \
-H "Content-Type: application/json" \
-d '{"name":"张伟","department":"市场部","position":"市场总监"}'
两次响应完全相同(HTTP 200 OK):
{
"id": 1001,
"name": "张伟",
"department": "市场部",
"position": "市场总监"
}
分析:
- 两次完全相同的 PUT 请求,服务器状态最终一致
- 这是 PUT 的幂等性特征:无论执行多少次,资源状态与执行一次相同
- 幂等性使得 PUT 请求可以安全地重试(网络超时后自动重发不会导致副作用)
易错场景与面试考点
误区一:用 PUT 做局部更新
错误写法:
@PutMapping("/{id}")
public Employee patch(@PathVariable Long id,
@RequestBody Map<String, Object> fields) {
// 只更新传入的字段
return employeeService.partialUpdate(id, fields);
}
纠正:PUT 的语义是全量替换,局部更新应该使用 @PatchMapping(HTTP PATCH):
// 全量更新(正确)
@PutMapping("/{id}")
public Employee update(@PathVariable Long id,
@RequestBody Employee employee) {
return employeeService.update(id, employee);
}
// 局部更新(正确)
@PatchMapping("/{id}")
public Employee partialUpdate(@PathVariable Long id,
@RequestBody Map<String, Object> fields) {
return employeeService.partialUpdate(id, fields);
}
误区二:PUT 请求 URL 指向集合而非具体资源
错误写法:
@PutMapping
public Employee update(@RequestBody Employee employee) {
// URL 是 /employees,没有指定具体资源 ID
return employeeService.update(employee);
}
纠正:PUT 的 URL 应该指向具体资源(含资源标识符),因为 PUT 是替换已有资源:
// 正确:URL 包含资源 ID
@PutMapping("/{id}")
public Employee update(@PathVariable Long id,
@RequestBody Employee employee) {
return employeeService.update(id, employee);
}
面试高频:PUT 与 POST 的区别
标准回答:
- POST 用于创建资源,PUT 用于全量更新资源
- POST 是非幂等的(多次调用创建多个资源),PUT 是幂等的(多次调用结果相同)
- POST 的 URL 通常指向资源集合(
/employees),PUT 的 URL 指向具体资源(/employees/1001) - PUT 请求体应包含资源的完整表示,缺失字段可能被清空
- PUT 可安全重试,POST 重试可能导致重复创建
小结
@PutMapping 是 Spring MVC 处理 HTTP PUT 请求的语义化注解,用于全量更新或替换资源。PUT 具有幂等性,是 RESTful API 设计中资源更新的标准方式。在实际开发中,应注意区分全量更新(PUT)和局部更新(PATCH)的语义差异。
本章与全局的关系:本章讲解了资源全量更新的映射注解。下一章"DeleteMapping"将讲解用于删除资源的 @DeleteMapping,它也是幂等的 HTTP 方法。