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

前端字段名和后端不一致?解锁 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<InviteCode> inviteCodePage = inviteCodeService.findPaginatedInviteCodeByAdminIdAndSearch(7, pageWithSearch);
    return BaseResult.success(inviteCodePage);
}

结果,服务层抛了个 NullPointerException,接口返回:

{
  "code": 500,
  "msg": "分页查询失败:null",
  "data": null
}

啥?明明传了 pageNumpageSize,怎么炸了?🤔


🔍 第二幕:深入代码,寻找线索

关键代码

服务层:

public Page<InviteCode> findPaginatedInviteCodeByAdminIdAndSearch(Integer adminId, PageWithSearch pageWithSearch) {
    PageRequest pageRequest = PageRequest.of(pageWithSearch.getPage(), pageWithSearch.getPageSize());
    // ... 其他逻辑 ...
}

PageWithSearchBasePage

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;
    }
}

初步分析

  • 前端字段pageNumpageSize
  • 后端字段pagesize
  • 问题:字段名不一致,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 流程图:映射失败过程
前端: pageNum=0, pageSize=10
Jackson 映射到 PageWithSearch
page 未匹配, size 未匹配
getPage()=null, getPageSize()=null
PageRequest.of(null, null)
自动拆箱抛 NullPointerException
返回 500: '分页查询失败:null'

🔧 第四幕:解决“命名冲突”

为什么会这样?

  • Jackson 的默认行为:严格匹配,不做自动转换。
  • 后端代码:未处理字段名不一致,导致 null 值引发下游问题。

解决方案

方案 1:用 @JsonProperty 指定映射

修改 BasePagePageWithSearch

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;
    // ... 其他代码 ...
}
  • 效果
    • 前端用 pageNumpageSizesearchField,后端正确映射。
    • 输入:
      {
        "searchField": "name",
        "pageNum": 0,
        "pageSize": 10
      }
      
      • pageWithSearch.getPage()0
      • pageWithSearch.getPageSize()10
方案 2:全局命名策略

application.yml 中配置:

spring:
  jackson:
    property-naming-strategy: SNAKE_CASE
  • 效果
    • 前端用 page_numpage_size,自动映射到 pagesize
    • 输入:
      {
        "field": "name",
        "page_num": 0,
        "page_size": 10
      }
      
方案 3:服务层防御

即使字段名不一致,也避免异常:

public Page<InviteCode> 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);
    }
}
  • 效果
    • pagesizenull 时,用默认值 0 和 10。
Mermaid 流程图:修复过程
前端: pageNum=0, pageSize=10
方案 1: @JsonProperty
page=0, size=10
PageRequest.of(0, 10)
正常返回数据
方案 3: toPageableWithDefault
page=0, size=10

🌈 第五幕:经验与启发

学到了啥?💡

  1. Jackson 的严格匹配
    • 字段名不一致,后端字段变 null,小心下游逻辑!
  2. 命名约定很重要
    • 前后端要统一字段名,或者用工具桥接差异。
  3. 防御性编程
    • null 是隐患,提前处理是王道。

小建议 🌟

  • 文档化
    • 用 Swagger 或 API 文档明确字段名,减少误解。
  • 日志排查
    log.info("Received: page={}, size={}", pageWithSearch.getPage(), pageWithSearch.getPageSize());
    

🎬 尾声

500 错误的迷雾到揭开字段名不一致的真相,这场 debug 让我对 JSON 映射有了新认识。希望这篇博客能帮你在前后端对接时少踩坑!有问题欢迎留言,咱们一起聊技术!✌️

在这里插入图片描述


文章转载自:
http://blastoderm.ciuzn.cn
http://arco.ciuzn.cn
http://aigrette.ciuzn.cn
http://cariole.ciuzn.cn
http://acknowledgedly.ciuzn.cn
http://axoplasm.ciuzn.cn
http://borescope.ciuzn.cn
http://brink.ciuzn.cn
http://aback.ciuzn.cn
http://cassette.ciuzn.cn
http://antideuterium.ciuzn.cn
http://blacksnake.ciuzn.cn
http://bodysurf.ciuzn.cn
http://behold.ciuzn.cn
http://cantankerous.ciuzn.cn
http://affrontedly.ciuzn.cn
http://chevron.ciuzn.cn
http://catface.ciuzn.cn
http://antrustion.ciuzn.cn
http://acquirability.ciuzn.cn
http://aversion.ciuzn.cn
http://assibilation.ciuzn.cn
http://abrazo.ciuzn.cn
http://accordatura.ciuzn.cn
http://cheapside.ciuzn.cn
http://aftermarket.ciuzn.cn
http://blockboard.ciuzn.cn
http://chemnitz.ciuzn.cn
http://boots.ciuzn.cn
http://catalepsy.ciuzn.cn
http://www.dtcms.com/a/78885.html

相关文章:

  • LeetCode 第19~21题
  • 【Qt】信号signal是单向的
  • YZi Labs 谈对 Plume 的投资:利用区块链创造现实价值的典范项目
  • 【C++】STL库面试常问点
  • Java基礎2小時速成(下篇) - 掌握核心技术「卷」
  • 【嵌入式学习】嘉立创画pcb门电路
  • Android 动态代理详解
  • 麒麟操作系统作为服务器,并且需要在浏览器上调试 MATLAB
  • LangChain组件Tools/Toolkits详解(1)——Tools接口与创建工具概述
  • Certd自动化申请和部署SSL证书并配置https
  • Go 语言常量
  • Nvidia 官方CUDA课程学习笔记
  • 【ESP32】虚拟机Ubuntu20.04下ESP32环境搭建
  • $set 方法废弃
  • 设计模式(创建型)-工厂模式
  • RK3568 Android11 sh366006驱动
  • HW华为流程管理体系精髓提炼华为流程运营体系(124页PPT)(文末有下载方式)
  • OpenHarmony 开源鸿蒙北向开发——3.配置SDK
  • Vue-Lottie动画使用
  • 第6章:Dockerfile最佳实践:多阶段构建与镜像优化
  • C++继承与组合完结
  • 互联网安全协议IPsec
  • html5基于Canvas的经典打砖块游戏开发实践
  • k8s1.30 部署calio网络
  • qt图表背景问题
  • 更改docker network :br-xxx
  • 登山第二十梯:无人机实时自主探索——我是一只小小小鸟
  • 游戏引擎学习第162天
  • Optiplex 3060 MT 电脑型号与尺寸
  • HTML5学习成果(仅HTML部分)