在最近做“原材料入库管理”模块时,我遇到了一个常见的坑:在 GET 请求里用 @RequestBody 接收 JSON 条件参数。这里记录一下踩坑→分析→解决的过程,供大家参考。
背景:想用 GET + @RequestBody 做条件查询
起初我写的 Controller:
/**
* 查询原材料入库记录列表(支持分页)
*/
@ApiOperation("查询原材料入库记录列表")
@PreAuthorize("@ss.hasPermi('datamanager:rawMaterialReceipt:list')")
@GetMapping("/list")
public TableDataInfo list(DtsFactoryRawMaterialReceiptQuery query) {
startPage();
List<DtsFactoryRawMaterialReceiptVO> list = receiptService.selectList(query);
return getDataTable(list);
}
前端打算用 JSON body 把查询条件传过来。
结果运行时参数接受不到:
原因分析:HTTP GET 与 @RequestBody 不兼容
- HTTP 语义:GET 用于“获取资源”,标准里没有定义 GET 请求 body 的语义。
- 框架行为:Spring MVC 遵循这个惯例,默认不会解析 GET 请求的 body,
@RequestBody接收不到值。
所以在 GET 接口里直接用 @RequestBody 是无效的。
两种可行的改法
方案 A:保持 GET,用 QueryParam 传参
去掉 @RequestBody,Spring 会自动把 URL 查询参数绑定到 DTO:
@GetMapping("/list")
public TableDataInfo list(DtsFactoryRawMaterialReceiptQuery query) {
startPage();
List<DtsFactoryRawMaterialReceiptVO> list = receiptService.selectList(query);
return getDataTable(list);
}
前端调用示例:
GET /datamanager/factoryRawMaterialReceipt/list?factoryId=1&supplierId=2&inStockStartTime=2025-09-01%2000:00:00
这种方式适合条件比较少、可以用查询字符串表达的场景。
方案 B:改成 POST,用 JSON body 传参(我最终采用的方案)
如果条件很多或需要嵌套 JSON,改成 POST 接口:
/**
* 条件分页查询原材料入库记录列表(支持分页)
*/
@ApiOperation("条件分页查询原材料入库记录列表")
@PreAuthorize("@ss.hasPermi('datamanager:rawMaterialReceipt:list')")
@PostMapping("/list")
public TableDataInfo list(@RequestBody DtsFactoryRawMaterialReceiptQuery query) {
startPage();
List<DtsFactoryRawMaterialReceiptVO> list = receiptService.selectList(query);
return getDataTable(list);
}
前端调用示例:
POST /datamanager/factoryRawMaterialReceipt/list
Content-Type: application/json
{
"pageNum":2,
"pageSize":10,
"inStockStartTime": "2025-09-01 00:00:00",
"inStockEndTime": "2025-09-30 23:59:59"
}
Spring 会把 JSON 自动反序列化到 query 对象。
一个新问题
此时又有了一个新问题,分页失效了,怎么插都是第一页,就是因为使用了post,将分页的两个参数也放在了请求体的JSON里,而StartPage规定这两个参数是在url里作为request parameter读取的。所以这里就需要手动从query对象里取出这两个值手动设置分页查询:
/**
* 条件分页查询原材料入库记录列表(支持分页)
*/
@ApiOperation("条件分页查询原材料入库记录列表")
@PreAuthorize("@ss.hasPermi('datamanager:rawMaterialReceipt:list')")
@PostMapping("/list")
public TableDataInfo list(@RequestBody DtsFactoryRawMaterialReceiptQuery query) {
// 手动启动分页
PageHelper.startPage(query.getPageNum(), query.getPageSize());
List<DtsFactoryRawMaterialReceiptVO> list = receiptService.selectList(query);
return getDataTable(list);
}
注:query:
@Data
public class DtsFactoryRawMaterialReceiptQuery {
private Integer pageNum;
private Integer pageSize;
private Long factoryId;
private Long supplierId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime inStockStartTime; // 入库开始时间
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime inStockEndTime; // 入库结束时间
}
有一个新问题
前端某个页面初始化时要调用两次这个接口(条件不同),但是前端又做了全局的post防抖(1S内不能连续请求两次post)。
这里暂时在前端用白名单的方式处理,但不优雅。。。所以之后我还是先按get方法写吧…
简单总结一下:
🔎 问题根源
- 接口语义不对
- 条件查询本质是“读取数据”,按 HTTP/REST 语义应该用 GET;
- 用 POST 只是因为要传 JSON,但违背了原本的语义,导致和前端全局策略冲突。
- 前端防抖策略过粗
- 前端把所有 POST 一刀切防抖,缺乏按“接口 + 参数”维度的精细化控制;
- 导致即便是两个不同条件的查询也被拦掉。
- 幂等性不是这个问题的解法
- 幂等性能保证“相同请求多次执行结果一致”,不能替代防抖、也不能合并不同条件的请求。
✅ 最佳实践
| 场景 | HTTP 方法 | 后端处理 | 前端处理 |
|---|---|---|---|
| 条件查询/分页 | GET(推荐) | DTO 接收 QueryParam;天然幂等 | 可按需防抖(输入搜索时),不一刀切 |
| 写操作(新增、下单、扣款) | POST/PUT/DELETE | 必须做幂等性(防重复提交) | 可以防抖以减少用户误触 |
| 复杂查询条件 JSON | POST /search(仅为传参方便) | 标注清楚语义仍是查询 | 精细化防抖(按 URL+参数 key) |