Spring MVC 参数接收容易踩的 6 个隐形坑

平时写 CRUD 接口,大部分人对参数接收的认知停留在:@RequestParam 接普通参数、@RequestBody 接 JSON。
但线上很多 400、参数为空、类型转换异常、接收不到数据的问题,都不是写错注解导致的,是对 Spring MVC 参数绑定规则细节不了解。
记录近期项目迭代遇到的几个隐蔽问题,全部可稳定复现,针对性规避即可。


  1. @RequestParam 接收空字符串自动转 null
    前端传参为空字符串 “”,后端用String 参数接收,大部分场景会直接变成 null。
    坑点:业务中如果需要区分「未传参」和「传空字符串」,这个默认行为会直接打乱校验逻辑。
    解决方式:
  2. 全局关闭字符串自动trim(不推荐,影响范围大)
  3. 业务层手动判空,区分 null 和空字符串:
    // null 代表未传参,“” 代表主动传空
    if (name == null) {
    // 未携带该参数
    } else if (“”.equals(name)) {
    // 主动传空字符串
    }

  1. @RequestBody 无法接收 form-data 数据
    新手最容易混淆的传参方式:
    前端 form-data 表单提交,后端用 @RequestBody 接收,直接报 400 错误。
    根因:
    @RequestBody 只能解析 application/json、application/xml 这类请求体数据,依赖 MappingJackson2HttpMessageConverter。
    而 form-data / x-www-form-urlencoded 属于表单请求,走的是参数绑定流程,不走 JSON 解析器。
    正确对应关系:
  • JSON 格式 → @RequestBody
  • 表单/URL 参数 → 实体类参数、@RequestParam
    如果接口需要同时兼容 JSON 和表单,不要用 @RequestBody,直接用实体类接收参数即可。

  1. 实体类参数首字母大写导致接收不到值
    非常隐蔽的字段绑定问题,很多人排查半小时找不到原因。
    实体类字段定义:
    public class UserDTO {
    // 首字母大写
    private String UserName;

    // getter/setter
    public String getUserName() { return UserName; }
    public void setUserName(String userName) { UserName = userName; }
    }
    前端传参userName: “test”,后端始终接收不到。
    根因:Spring 参数绑定遵循 Java 驼峰规范,通过 setter 方法反射赋值。
    字段 UserName、setter setUserName,Spring 解析对应的参数名为 u serName,和前端传入的 userName 不匹配,直接绑定失败。
    规范:实体类字段必须小驼峰命名,绝对不能首字母大写。


  1. 基本类型参数不传参直接报错 400
    接口使用基本类型接收参数,不赋默认值,前端不传参直接 400。
    @GetMapping(“/page”)
    public void page(@RequestParam int pageNum, @RequestParam int pageSize) {
    // 分页逻辑
    }
    问题:基本类型 int 不能为 null,Spring 检测到参数缺失,直接抛出参数缺失异常。
    很多人习惯用包装类,但不知道根本区别:
    // 推荐写法
    @GetMapping(“/page”)
    public void page(
    @RequestParam(required = false, defaultValue = “1”) Integer pageNum,
    @RequestParam(required = false, defaultValue = “10”) Integer pageSize
    ) {
    // 兜底赋值
    pageNum = pageNum == null ? 1 : pageNum;
    }
    核心原则:所有对外接口参数,数值类型统一用包装类,设置非必传+默认值,避免空参报错。
  2. @RequestParam 接收数组参数的格式坑

前端传数组参数,两种格式后端接收效果完全不同。
后端代码:
@GetMapping(“/ids”)
public void getIds(@RequestParam List ids) {
System.out.println(ids);
}
支持格式:/ids?ids=1&ids=2&ids=3
不支持格式:/ids?ids=1,2,3
第二种写法会被当成单个字符串,不会自动分割成数组,导致集合长度为1,数据异常。
解决方案:
如果前端只能传逗号分隔字符串,后端手动分割:
@GetMapping(“/ids”)
public void getIds(@RequestParam String ids) {
List idList = Arrays.stream(ids.split(“,”))
.map(Long::valueOf)
.collect(Collectors.toList());
}


  1. 时间参数无格式化注解报错
    非 JSON 传参场景下,时间字符串无法自动转换 Date 对象。
    错误写法:
    @GetMapping(“/time”)
    public void time(@RequestParam Date createTime) {
    }
    前端传 2025-09-01 12:00:00,直接类型转换异常。
    根因:Spring 默认只能解析 yyyy/MM/dd 格式,不支持横杠+时分秒格式。
    正确写法:
    @GetMapping(“/time”)
    public void time(@RequestParam @DateTimeFormat(pattern = “yyyy-MM-dd HH:mm:ss”) Date createTime) {
    }
    补充:@RequestBody 接收 JSON 时间参数,用 @JsonFormat,不要混用两个注解。

收尾
Spring MVC 参数绑定的大部分问题,都不是代码写错了,是默认机制不熟悉。
这类问题本地测试很难全覆盖,基本都是上线后才暴露。把这些细节固化成编码习惯,能规避 80% 的接口参数异常。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值