前端字段名和后端不一致?解锁 JSON 映射的“隐藏规则” !!!
🚀 前端字段名和后端不一致?解锁 JSON 映射的“隐藏规则” 🌟
嘿,技术冒险家们!👋 今天我们要聊一个开发中常见的“坑”:前端传来的 JSON 参数字段名和后端对象字段名不一致,会发生什么?是默默失败,还是直接炸裂?💥 我将以 Spring 的 PageWithSearch 为例,带你揭开 Jackson 的神秘面纱,还有流程图助阵,快跟我一起探索吧!💪
🎯 第一幕:一场“命名失误”的意外
问题起源
我在开发一个分页查询接口,前端传了个 JSON:
{ "searchField": "name", "searchValue": "John", "pageNum": 0, "pageSize": 10 }
后端用 PageWithSearch 接收:
@PostMapping("/listInviteCodeByPageWithSearch") public BaseResult listInviteCodeByPageWithSearch( @Valid @RequestBody PageWithSearch pageWithSearch) { Page inviteCodePage = inviteCodeService.findPaginatedInviteCodeByAdminIdAndSearch(7, pageWithSearch); return BaseResult.success(inviteCodePage); }
结果,服务层抛了个 NullPointerException,接口返回:
{ "code": 500, "msg": "分页查询失败:null", "data": null }
啥?明明传了 pageNum 和 pageSize,怎么炸了?🤔
🔍 第二幕:深入代码,寻找线索
关键代码
服务层:
public Page findPaginatedInviteCodeByAdminIdAndSearch(Integer adminId, PageWithSearch pageWithSearch) { PageRequest pageRequest = PageRequest.of(pageWithSearch.getPage(), pageWithSearch.getPageSize()); // ... 其他逻辑 ... }
PageWithSearch 和 BasePage:
public class PageWithSearch extends BasePage { private String field; private String value; public Integer getPageSize() { return this.size; } } public class BasePage { Integer page; Integer size; public Integer getPage() { return page; } public Integer getSize() { return size; } }
初步分析
- 前端字段:pageNum、pageSize。
- 后端字段:page、size。
- 问题:字段名不一致,pageWithSearch.getPage() 和 getPageSize() 返回 null,导致 PageRequest.of 自动拆箱时抛出 NullPointerException。
🐞 第三幕:Jackson 的“严格规则”
真相揭晓
Spring 默认用 Jackson 处理 JSON 到对象的映射,它的规则很简单:
- 字段名必须一致:JSON 字段名与 Java 对象字段名大小写敏感匹配。
- 不一致的结果:未匹配的字段被忽略,对象中对应字段保持默认值(null)。
测试验证
输入:
{ "pageNum": 0, "pageSize": 10 }
- pageWithSearch.getPage() → null(无 page 字段)。
- pageWithSearch.getPageSize() → null(无 size 字段)。
- PageRequest.of(null, null) → 自动拆箱 → NullPointerException。
Mermaid 流程图:映射失败过程
🔧 第四幕:解决“命名冲突”
为什么会这样?
- Jackson 的默认行为:严格匹配,不做自动转换。
- 后端代码:未处理字段名不一致,导致 null 值引发下游问题。
解决方案
方案 1:用 @JsonProperty 指定映射
修改 BasePage 和 PageWithSearch:
public class BasePage { @JsonProperty("pageNum") Integer page; @JsonProperty("pageSize") Integer size; // ... 其他代码 ... } public class PageWithSearch extends BasePage { @JsonProperty("searchField") private String field; @JsonProperty("searchValue") private String value; // ... 其他代码 ... }
- 效果:
- 前端用 pageNum、pageSize、searchField,后端正确映射。
- 输入:
{ "searchField": "name", "pageNum": 0, "pageSize": 10 }
- pageWithSearch.getPage() → 0
- pageWithSearch.getPageSize() → 10
方案 2:全局命名策略
在 application.yml 中配置:
spring: jackson: property-naming-strategy: SNAKE_CASE
- 效果:
- 前端用 page_num、page_size,自动映射到 page、size。
- 输入:
{ "field": "name", "page_num": 0, "page_size": 10 }
方案 3:服务层防御
即使字段名不一致,也避免异常:
public Page findPaginatedInviteCodeByAdminIdAndSearch(Integer adminId, PageWithSearch pageWithSearch) { Pageable pageable = pageWithSearch.toPageableWithDefault(0, 10); // 默认值保护 String field = pageWithSearch.getField(); String value = pageWithSearch.getValue(); if (!StringUtils.isEmpty(field) && !StringUtils.isEmpty(value)) { return inviteCodeRepository.findPaginatedInviteCodeByAdminIdAndFieldAndValue(adminId, field, value, pageable); } else { return inviteCodeRepository.findByAdminId(adminId, pageable); } }
- 效果:
- page 或 size 为 null 时,用默认值 0 和 10。
Mermaid 流程图:修复过程
🌈 第五幕:经验与启发
学到了啥?💡
- Jackson 的严格匹配:
- 字段名不一致,后端字段变 null,小心下游逻辑!
- 命名约定很重要:
- 前后端要统一字段名,或者用工具桥接差异。
- 防御性编程:
- null 是隐患,提前处理是王道。
小建议 🌟
- Jackson 的严格匹配:
- page 或 size 为 null 时,用默认值 0 和 10。
- 效果:
- 效果:
- 效果:
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。