当前位置: 首页 > news >正文

诡异的Spring @RequestBody驼峰命名字段映射失败为null问题记录

问题

一个非常常规的Spring Controller,代码如下:

import lombok.RequiredArgsConstructor;@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/config")
public class ConfigController {private final ConfigService configService;@ApiOperation("新增配置")@PostMapping("")public R<ConfigVo> createConfig( /*@Valid*/ @RequestBody ConfigDto dto) {return R.success(configService.createConfig(dto));}
}

DTO定义如下:

import io.swagger.annotations.ApiModel;
import lombok.*;@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("配置")
public class ConfigDto {@NotBlankprivate String appId;private String json;private String mark;
}

Postman模拟一次POST请求:

{"mark": "verifyUserByIdAndName","json": "{}","appId": "a_15c140390de54948af88ad9b39d1fd2f"
}

代码逻辑不对劲,然后通过断点调试,发现appId字段为null:
在这里插入图片描述
WTF???有毒吧。

现象就是驼峰命名的字段解析不出来,映射不上。

@Valid

咨询DeepSeek,一大堆废话。提取到关键词@Valid。

给这个Controller加个@Valid注解,也就是上面的代码片段里被注释的/*@Valid*/,Postman请求报错:
在这里插入图片描述
这个报错是框架类的封装然后返回的。说明Spring(Jackson)确实没有从Postman的request里解析映射出appId字段。

框架类代码片段:

private static final MediaType MEDIA_TYPE = new MediaType("application", "json", StandardCharsets.UTF_8);/*** JSR303 表单参数校验失败* 在Controller层使用@Valid注解*/
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResponseEntity<R<?>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e,HttpServletRequest request) {this.logWarn(e, request, "不合法的参数异常");InvalidField invalidField = getInvalidField(e.getBindingResult());R<InvalidField> invalidFieldR = new R<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "不合法的参数异常", invalidField);return createResponseEntity(HttpStatus.BAD_REQUEST, invalidFieldR);
}private void logWarn(Exception e, HttpServletRequest request, String... msg) {String template = "[Web][有Warn被抛出] >> Warn类=[%s], URI=[%s], 消息=[%s], Warn=[%s]";log.warn(String.format(template, e.getClass().getName(), request.getRequestURI(),ArrayUtil.isEmpty(msg) ? e.getMessage() : ArrayUtil.join(msg, ","), ExceptionUtil.stacktraceToString(e)));
}private InvalidField getInvalidField(BindingResult bindingResult) {if (bindingResult == null) {return null;}FieldError fieldError = bindingResult.getFieldError();if (fieldError == null) {return null;}return InvalidField.builder().fieldName(fieldError.getField()).message(fieldError.getDefaultMessage()).build();
}protected static ResponseEntity<R<?>> createResponseEntity(HttpStatus httpStatus, R<?> body) {return ResponseEntity.status(httpStatus.value()).contentType(MEDIA_TYPE).body(body);
}@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public static class InvalidField {private String fieldName;private String message;
}

断点调试截图:
在这里插入图片描述

workaround

继续询问DeepSeek,又是一大堆废话,提取到关键词@JsonProperty。

一开始并没有关注这个,因为这个注解的使用场景是字段命名不匹配。

试试吧,增加@JsonProperty("appId"),也就是

public class ConfigDto {@NotBlank@JsonProperty("appId")private String appId;
}

能解析到appId字段。


但是!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


这两个地方的命名,明明是一模一样的啊。

分析

为啥呢?

Lombok

不是Lombok的问题,其他字段都没有问题,再说appId是一个非常常规的驼峰命名,又不是isSuccesscAppId这种不规范命名。

编译后的代码如下,没有问题
在这里插入图片描述

调试

在DTO里的字段加断点调试,
在这里插入图片描述
在Controller层加断点调试说明@JsonProperty生效:
在这里插入图片描述

为啥呢??

一个比较相似的blog,不过他这篇里的命名不太规范。

参考

http://www.lryc.cn/news/523127.html

相关文章:

  • YOLOv10改进,YOLOv10检测头融合RFAConv卷积,添加小目标检测层(四头检测)+CA注意机制,全网首发
  • 周末总结(2024/01/18)
  • LLM - 大模型 ScallingLaws 的迁移学习与混合训练(PLM) 教程(3)
  • 【软件开发过程管理规范】需求管理,需求分析,设计开发管理,测试管理(Word)
  • 计算机网络 (49)网络安全问题概述
  • RPA编程实践:Electron实践开始
  • ORB-SLAM2源码学习:MapPoint.cc④: 新增地图点总结
  • 2025西湖论剑-babytrace
  • 绘图专用,26个常见流程图符号及其解释
  • 【个人学习记录】软件开发生命周期(SDLC)是什么?
  • 自学SpringBoot笔记
  • 03JavaWeb——Ajax-Vue-Element(项目实战)
  • [leetcode](找到vector中的特定元素并删除)无重复字符的最长子串
  • Mockito+PowerMock+Junit单元测试
  • Ncat: bind to :::7777: Address already in use报错问题解决
  • Docker 搭建mysql 连接超时问题,xxl-job启动mysql连接报错,禁用dns
  • 在线图片像素颜色拾取工具
  • Qt之登录界面(splash)
  • NotebookLM:Google 最新 AI 笔记助理解析与实战应用
  • 软路由系统iStoreOS 一键安装 docker compose
  • vue3本地文件下载
  • 纯代码实现给WordPress添加文章复制功能
  • Redis 中 TTL 的基本知识与禁用缓存键的实现策略(Java)
  • 【PyQt】图像处理系统
  • Ruby语言的循环实现
  • javaEE安全开发 SQL预编译 Filter过滤器 Listener 监听器 访问控制
  • 一体机cell服务器更换内存步骤
  • Hadoop•用Web UI查看Hadoop状态词频统计
  • rhel7.9利用有网络环境打包ansible
  • vim文本编辑器三种模式的转换关系