做搜狗手机网站点做建网站
news/
2025/9/22 15:45:35/
文章来源:
做搜狗手机网站点,做建网站,深圳龙华医院网站建设,千阳做网站#x1f680; 前端字段名和后端不一致#xff1f;解锁 JSON 映射的“隐藏规则” #x1f31f;
嘿#xff0c;技术冒险家们#xff01;#x1f44b; 今天我们要聊一个开发中常见的“坑”#xff1a;前端传来的 JSON 参数字段名和后端对象字段名不一致#xff0c;会发生… 前端字段名和后端不一致解锁 JSON 映射的“隐藏规则”
嘿技术冒险家们 今天我们要聊一个开发中常见的“坑”前端传来的 JSON 参数字段名和后端对象字段名不一致会发生什么是默默失败还是直接炸裂 我将以 Spring 的 PageWithSearch 为例带你揭开 Jackson 的神秘面纱还有流程图助阵快跟我一起探索吧 第一幕一场“命名失误”的意外
问题起源
我在开发一个分页查询接口前端传了个 JSON
{searchField: name,searchValue: John,pageNum: 0,pageSize: 10
}后端用 PageWithSearch 接收
PostMapping(/listInviteCodeByPageWithSearch)
public BaseResult listInviteCodeByPageWithSearch(Valid RequestBody PageWithSearch pageWithSearch) {PageInviteCode inviteCodePage inviteCodeService.findPaginatedInviteCodeByAdminIdAndSearch(7, pageWithSearch);return BaseResult.success(inviteCodePage);
}结果服务层抛了个 NullPointerException接口返回
{code: 500,msg: 分页查询失败null,data: null
}啥明明传了 pageNum 和 pageSize怎么炸了 第二幕深入代码寻找线索
关键代码
服务层
public PageInviteCode 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 流程图映射失败过程 #mermaid-svg-4NdoX6Pw4W3Q3TOl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .error-icon{fill:#552222;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .marker.cross{stroke:#333333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .cluster-label text{fill:#333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .cluster-label span{color:#333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .label text,#mermaid-svg-4NdoX6Pw4W3Q3TOl span{fill:#333;color:#333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .node rect,#mermaid-svg-4NdoX6Pw4W3Q3TOl .node circle,#mermaid-svg-4NdoX6Pw4W3Q3TOl .node ellipse,#mermaid-svg-4NdoX6Pw4W3Q3TOl .node polygon,#mermaid-svg-4NdoX6Pw4W3Q3TOl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .node .label{text-align:center;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .node.clickable{cursor:pointer;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .arrowheadPath{fill:#333333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .cluster text{fill:#333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl .cluster span{color:#333;}#mermaid-svg-4NdoX6Pw4W3Q3TOl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-4NdoX6Pw4W3Q3TOl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 前端: pageNum0, pageSize10 Jackson 映射到 PageWithSearch page 未匹配, size 未匹配 getPage()null, getPageSize()null PageRequest.of(null, null) 自动拆箱抛 NullPointerException 返回 500: 分页查询失败null 第四幕解决“命名冲突”
为什么会这样
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() → 0pageWithSearch.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 PageInviteCode 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 流程图修复过程 #mermaid-svg-edI9dgBpEcOcs6SA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-edI9dgBpEcOcs6SA .error-icon{fill:#552222;}#mermaid-svg-edI9dgBpEcOcs6SA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-edI9dgBpEcOcs6SA .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-edI9dgBpEcOcs6SA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-edI9dgBpEcOcs6SA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-edI9dgBpEcOcs6SA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-edI9dgBpEcOcs6SA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-edI9dgBpEcOcs6SA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-edI9dgBpEcOcs6SA .marker.cross{stroke:#333333;}#mermaid-svg-edI9dgBpEcOcs6SA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-edI9dgBpEcOcs6SA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-edI9dgBpEcOcs6SA .cluster-label text{fill:#333;}#mermaid-svg-edI9dgBpEcOcs6SA .cluster-label span{color:#333;}#mermaid-svg-edI9dgBpEcOcs6SA .label text,#mermaid-svg-edI9dgBpEcOcs6SA span{fill:#333;color:#333;}#mermaid-svg-edI9dgBpEcOcs6SA .node rect,#mermaid-svg-edI9dgBpEcOcs6SA .node circle,#mermaid-svg-edI9dgBpEcOcs6SA .node ellipse,#mermaid-svg-edI9dgBpEcOcs6SA .node polygon,#mermaid-svg-edI9dgBpEcOcs6SA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-edI9dgBpEcOcs6SA .node .label{text-align:center;}#mermaid-svg-edI9dgBpEcOcs6SA .node.clickable{cursor:pointer;}#mermaid-svg-edI9dgBpEcOcs6SA .arrowheadPath{fill:#333333;}#mermaid-svg-edI9dgBpEcOcs6SA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-edI9dgBpEcOcs6SA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-edI9dgBpEcOcs6SA .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-edI9dgBpEcOcs6SA .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-edI9dgBpEcOcs6SA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-edI9dgBpEcOcs6SA .cluster text{fill:#333;}#mermaid-svg-edI9dgBpEcOcs6SA .cluster span{color:#333;}#mermaid-svg-edI9dgBpEcOcs6SA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-edI9dgBpEcOcs6SA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 前端: pageNum0, pageSize10 方案 1: JsonProperty page0, size10 PageRequest.of(0, 10) 正常返回数据 方案 3: toPageableWithDefault page0, size10 第五幕经验与启发
学到了啥
Jackson 的严格匹配 字段名不一致后端字段变 null小心下游逻辑 命名约定很重要 前后端要统一字段名或者用工具桥接差异。 防御性编程 null 是隐患提前处理是王道。
小建议
文档化 用 Swagger 或 API 文档明确字段名减少误解。 日志排查log.info(Received: page{}, size{}, pageWithSearch.getPage(), pageWithSearch.getPageSize());尾声
从 500 错误的迷雾到揭开字段名不一致的真相这场 debug 让我对 JSON 映射有了新认识。希望这篇博客能帮你在前后端对接时少踩坑有问题欢迎留言咱们一起聊技术✌️
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/909519.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!