前端字段名和后端不一致?解鎖 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://www.pswp.cn/news/898328.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898328.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898328.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python中使用單例模式在整個程序中只創建一個數據庫連接,節省資源

示例代碼&#xff1a; from loguru import logger from pymongo import MongoClient from pymongo.errors import ConnectionFailurefrom llm_engineering.settings import settingsclass MongoDatabaseConnector:_instance: MongoClient | None Nonedef __new__(cls, *args,…

AI小白的第六天:必要的數學知識(一)

在學習的過程中&#xff0c;不管是上代碼還是理論學習&#xff0c;其中都摻雜了一些數學知識。俗話說“磨刀不誤砍柴工”&#xff0c;而我已經“誤了砍柴功”了&#xff0c;現在變成了“亡羊補牢&#xff0c;為時不晚”。 線性代數 線性代數是數學的一個分支&#xff0c;主要…

【Linux】Bash是什么?怎么使用?

李升偉 整理 什么是 Bash&#xff1f; Bash&#xff08;Bourne Again Shell&#xff09;是一種 命令行解釋器&#xff08;Shell&#xff09;&#xff0c;廣泛用于 Unix 和 Linux 操作系統。它是 Bourne Shell&#xff08;sh&#xff09; 的增強版&#xff0c;提供了更多的功能…

Qt Creator入門

1.創建項目 選擇創建項目-Application&#xff08;Qt&#xff09;-Qt Widgets Application-修改名稱即可 默認創建有窗口類&#xff0c;myWidget,基類有三種選擇&#xff1a;QWidget&#xff0c;QMainWindow&#xff0c;QDialog 注意&#xff1a; 名稱和創建路徑不能有中文、…

C語言經典代碼練習題

1.輸入一個4位數&#xff1a;輸出這個輸的個位 十位 百位 千位 #include <stdio.h> int main(int argc, char const *argv[]) {int a;printf("輸入一個&#xff14;位數&#xff1a;");scanf("%d",&a);printf("個位&#xff1a;%d\n"…

cls(**dict(data, id=id))靈活地從一個字典生成實例,同時確保某些關鍵字段(如 id)被正確設置或覆蓋

示例代碼&#xff1a; classmethoddef from_mongo(cls: Type[T], data: dict) -> T:"""Convert "_id" (str object) into "id" (UUID object)."""if not data:raise ValueError("Data is empty.")id data.pop…

MyBatis XMLMapperBuilder 是如何將 SQL 語句解析成可執行的對象? 如何將結果映射規則解析成對應的處理器?

1. XMLMapperBuilder 如何將 SQL 語句解析成可執行對象 (MappedStatement): XMLMapperBuilder 解析 <select>, <insert>, <update>, <delete> 等 SQL 語句元素時&#xff0c;并不僅僅是簡單地讀取 SQL 文本&#xff0c;而是要將 SQL 語句和相關的配置…

咖啡點單小程序畢業設計(JAVA+SpringBoot+微信小程序+完整源碼+論文)

?全網粉絲20W,csdn特邀作者、博客專家、CSDN新星計劃導師、java領域優質創作者,博客之星、掘金/華為云/阿里云/InfoQ等平臺優質作者、專注于Java技術領域和畢業項目實戰? &#x1f345;文末獲取項目下載方式&#x1f345; 一、項目背景介紹&#xff1a; 隨著社會的快速發展和…

003-掌控命令行-CLI11-C++開源庫108杰

首選的現代C風格命令行參數解析器! &#xff08;本課程包含兩段教學視頻。&#xff09; 以文件對象監控程序為實例&#xff0c;五分鐘實現從命令行讀入多個監控目標路徑&#xff1b;區分兩大時機&#xff0c;學習 CLI11 構建與解析參數兩大場景下的異常處理&#xff1b;區分三…

【leetcode hot 100 124】二叉樹中的最大路徑和

解法一&#xff1a;&#xff08;遞歸&#xff09;考慮實現一個簡化的函數 maxGain(node)&#xff0c;該函數計算二叉樹中的一個節點的最大貢獻值&#xff0c;具體而言&#xff0c;就是在以該節點為根節點的子樹中尋找以該節點為起點的一條路徑&#xff0c;使得該路徑上的節點值…

譜分析方法

前言 本文隸屬于專欄《機器學習數學通關指南》&#xff0c;該專欄為筆者原創&#xff0c;引用請注明來源&#xff0c;不足和錯誤之處請在評論區幫忙指出&#xff0c;謝謝&#xff01; 本專欄目錄結構和參考文獻請見《機器學習數學通關指南》 ima 知識庫 知識庫廣場搜索&#…

在圖像/視頻中裁剪出人臉區域

1. 在圖像中裁剪人臉區域 import face_alignment import skimage.io import numpy from argparse import ArgumentParser from skimage import img_as_ubyte from skimage.transform import resize from tqdm import tqdm import os import numpy as np import warnings warni…

【軟考-架構】11.3、設計模式-新

?資料&文章更新? GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目錄 項目中的應用設計模式創建型設計模式結構型設計模式行為型設計模式 &#x1f4af;考試真題題外話 項目中的應用 在實際項目中&#xff0c;我應用過多種設計模式來解決不同…

使用Redis如何實現分布式鎖?(超賣)

分布式鎖概念 在多線程環境下&#xff0c;為了保證數據的線程安全&#xff0c;鎖保證同一時刻&#xff0c;只有一個可以訪問和更新共享數據。在單機系統我們可以使用 synchronized 鎖、Lock 鎖保證線程安全。 synchronized 鎖是 Java 提供的一種內置鎖&#xff0c;在單個 JVM …

Linux的Shell編程

一、什么是Shell 1、為什么要學習Shell Linux運維工程師在進行服務器集群管理時&#xff0c;需要編寫Shell程序來進行服務器管理。 對于JavaEE和Python程序員來說&#xff0c;工作的需要。Boss會要求你編寫一些Shell腳本進行程序或者是服務器的維護&#xff0c;比如編寫一個…

使用React和google gemini api 打造一個google gemini應用

實現一個簡單的聊天應用&#xff0c;用戶可以通過輸入問題或點擊“Surprise me”按鈕獲取隨機問題&#xff0c;并從后端API獲取回答。 import { useState } from "react"; function App() {const [ value, setValue] useState(""); // 存儲用戶輸入的問題…

深入探討TK矩陣系統:創新的TikTok運營工具

TK矩陣的應用場景 TK矩陣系統適用于多個場景&#xff0c;尤其是在以下幾個方面有顯著優勢&#xff1a; 批量賬號管理與內容發布&#xff1a;對于需要管理多個TikTok賬號的內容創作者或營銷人員&#xff0c;TK矩陣提供了高效的賬號管理工具&#xff0c;支持批量發布視頻、評論、…

MTK Android12 應用在最頂端時,禁止拉起其他某個應用(一)

1、需求 近期&#xff0c;客戶要求應用在最頂端時&#xff0c;禁止拉起其他某個應用2、解決方法 diff --git a/frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java b/frameworks/base/services/core/java/com/android/server/wm/ActivityStarte…

論文閱讀筆記:Deep Unsupervised Learning using Nonequilibrium Thermodynamics

1、來源 論文連接1&#xff1a;http://ganguli-gang.stanford.edu/pdf/DeepUnsupDiffusion.pdf 論文連接2(帶appendix)&#xff1a;https://arxiv.org/pdf/1503.03585v7 代碼鏈接&#xff1a;https://github.com/Sohl-Dickstein/Diffusion-Probabilistic-Models 代碼的環境配置…

7種數據結構

7種數據結構 順序表sqlite.hseqlite.c 單鏈表linklist.clinklist.h 雙鏈表doulinklist.cdoulinklist.h 鏈式棧linkstack.clinkstack.h 隊列SeqQueue.cSeqQueue.h 樹tree.c 哈希表hash.c 順序表 sqlite.h #ifndef __SEQLIST_H__ #define __SEQLIST_H__ typedef struct person…