FastJSON 默认行为:JSON.toJSONString 忽略 null 字段
完整的 FakeRegistrationController 代码,这让我可以全面分析后端逻辑,特别是为什么空的字段(如 compareDate)不返回给前端。我将详细分析代码的每个接口,尤其是与 list 请求和字段返回相关的部分,并解释原因。
代码结构总览
FakeRegistrationController 是一个 RESTful 控制器,提供了三个接口:
POST /fakeRegistration/registration/save:保存或修改假货登记信息。POST /fakeRegistration/compare/save:保存或修改比对结果。GET /fakeRegistration/list:获取假货登记列表(对应前端的qlist请求)。
我们关心的是 list 接口,因为它直接决定了前端表格接收到的数据内容,特别是为何空的 compareDate 不返回。
详细分析 list 接口
接口定义
@GetMapping("list")
@ApiOperation("假货登记列表")
public BaseResult list(@ApiIgnore @SessionAttribute(Constants.ADMIN_ID) Integer adminId,BasePage page) {Integer vipAdminId = copywritingApiService.getVipAdminId(adminId, 11);Page<FakeRegistration> fakeRegistrationPage = fakeRegistrationService.findByAdminId(vipAdminId, page);List<FakeRegistration> fakeRegistrations = fakeRegistrationPage.getContent();List<FakeRegistrationListDTO> fakeRegistrationListDTOS = new ArrayList<>();for (FakeRegistration fakeRegistration: fakeRegistrations) {FakeRegistrationListDTO fakeRegistrationListDTO = JSON.parseObject(JSON.toJSONString(fakeRegistration), FakeRegistrationListDTO.class);if (null != fakeRegistration.getProductId()) {Product product = productService.findById(fakeRegistration.getProductId()).orElseThrow(() -> new RuntimeException("未找到商品信息"));fakeRegistrationListDTO.setProductName(product.getName());}Admin creator = adminService.findById(fakeRegistration.getCreatorId()).orElseThrow(() -> new RuntimeException("未找到创建人信息"));fakeRegistrationListDTO.setCreatorName(StringUtils.isEmpty(creator.getNickname()) ? creator.getUsername() : creator.getNickname());fakeRegistrationListDTO.setGenuineIdentificationPoints(fakeRegistrationApiService.findIdentification(fakeRegistration.getId(), 1));fakeRegistrationListDTO.setFakeIdentificationPoints(fakeRegistrationApiService.findIdentification(fakeRegistration.getId(), 0));fakeRegistrationListDTOS.add(fakeRegistrationListDTO);}return BaseResult.success(new PageImpl<>(fakeRegistrationListDTOS, PageRequest.of(fakeRegistrationPage.getNumber(), fakeRegistrationPage.getSize()), fakeRegistrationPage.getTotalElements()));
}
数据流分析
-
数据查询:
fakeRegistrationService.findByAdminId(vipAdminId, page)返回一个Page<FakeRegistration>,其中FakeRegistration是数据库实体类,包含所有字段(如id,createdDate,compareDate,comparisonStatus等)。fakeRegistrations是分页内容的List<FakeRegistration>。
-
数据转换:
- 每个
FakeRegistration被转换为FakeRegistrationListDTO:FakeRegistrationListDTO fakeRegistrationListDTO = JSON.parseObject(JSON.toJSONString(fakeRegistration), FakeRegistrationListDTO.class); - 这里使用了 FastJSON(
com.alibaba.fastjson.JSON)进行序列化和反序列化:JSON.toJSONString(fakeRegistration)将FakeRegistration转为 JSON 字符串。JSON.parseObject(..., FakeRegistrationListDTO.class)将 JSON 字符串转为FakeRegistrationListDTO对象。
- 然后手动补充了:
productName:从ProductService获取。creatorName:从AdminService获取。genuineIdentificationPoints和fakeIdentificationPoints:从FakeRegistrationApiService获取。
- 每个
-
返回结果:
- 返回一个
PageImpl<FakeRegistrationListDTO>,最终被序列化为 JSON 响应。
- 返回一个
为什么空的字段(如 compareDate)不返回?
-
FastJSON 的默认行为:
- FastJSON 在序列化时,默认忽略
null值字段,除非显式配置SerializerFeature.WriteMapNullValue。 - 如果
FakeRegistration的compareDate是null,JSON.toJSONString(fakeRegistration)生成的 JSON 字符串不会包含"compareDate"。 - 示例:
FakeRegistration fr = new FakeRegistration(); fr.setId(34); fr.setComparisonStatus(1); fr.setCompareDate(null); // 为空 String json = JSON.toJSONString(fr); // 输出: {"id":34,"comparisonStatus":1} - 反序列化到
FakeRegistrationListDTO时,由于 JSON 中没有compareDate,fakeRegistrationListDTO的compareDate字段不会被赋值,最终返回的 JSON 也不会包含它。
- FastJSON 在序列化时,默认忽略
-
业务逻辑:
- 从其他接口看,
compareDate只有在compare/save接口保存比对结果时才会设置:fakeRegistrationOrigin.setCompareDate(new Date()); - 在
registration/save接口中,新建记录时没有设置compareDate,它保持为null。 - 因此,未完成比对的记录(
comparisonStatus = 0或1)在数据库中compareDate就是NULL,序列化后被忽略。
- 从其他接口看,
-
DTO 定义的影响:
- 如果
FakeRegistrationListDTO中定义了compareDate:public class FakeRegistrationListDTO {private Integer id;private Date compareDate; // 假设是这样// 其他字段 } - 当
JSON.parseObject处理没有compareDate的 JSON 时,fakeRegistrationListDTO.compareDate会是null,但后续的序列化(返回给前端时)仍由 FastJSON 处理,又会被忽略。
- 如果
其他接口的补充分析
1. registration/save
@PostMapping("registration/save")
public BaseResult save(@RequestBody FakeRegistration fakeRegistration, ...) {if(null != fakeRegistration.getId()) {FakeRegistration fakeRegistrationOrigin = fakeRegistrationService.findById(fakeRegistration.getId()).orElseThrow(...);fakeRegistration = SqlUtil.mergeObject(fakeRegistration, fakeRegistrationOrigin);if(null != fakeRegistration.getCompareResult() && fakeRegistration.getCompareResult() == 1) {fakeRegistrationOrigin.setComparisonStatus(3);} else if(null != fakeRegistration.getCompareResult() && fakeRegistration.getCompareResult() == 0) {fakeRegistrationOrigin.setComparisonStatus(2);}} else {fakeRegistration.setAdminId(vipAdminId);fakeRegistration.setCreatorId(adminId);}fakeRegistration = fakeRegistrationService.save(fakeRegistration);...
}
- 关键点:
- 新建记录时(
fakeRegistration.getId() == null),只设置了adminId和creatorId,没有初始化compareDate,它默认为null。 - 修改记录时,如果提供了
compareResult,会更新comparisonStatus,但不会设置compareDate。 - 因此,
compareDate在这个接口中始终不会被赋值。
- 新建记录时(
2. compare/save
@PostMapping("compare/save")
public BaseResult compareSave(@RequestBody FakeRegistrationSaveDTO fakeRegistration, ...) {FakeRegistration fakeRegistrationOrigin = fakeRegistrationService.findById(fakeRegistration.getId()).orElseThrow(...);fakeRegistrationOrigin.setCompareResult(fakeRegistration.getCompareResult());fakeRegistrationOrigin.setCompareDate(new Date());fakeRegistrationService.save(fakeRegistrationOrigin);...
}
- 关键点:
- 这里显式设置了
compareDate = new Date(),表示比对完成的时间。 - 只有通过这个接口保存比对结果时,
compareDate才会被赋值。 - 这解释了前端数据中,只有
comparisonStatus = 2或更高状态的记录有compareDate。
- 这里显式设置了
综合结论:为什么空的字段不返回?
-
数据来源:
compareDate在数据库中默认为NULL,除非通过compare/save接口保存比对结果时才会被赋值。- 未完成比对的记录(
comparisonStatus = 0或1)没有compareDate值。
-
FastJSON 序列化:
list接口中,JSON.toJSONString(fakeRegistration)将FakeRegistration转为 JSON 时,默认忽略null字段。- 如果
compareDate是null,它不会出现在 JSON 字符串中。 - 反序列化到
FakeRegistrationListDTO后,compareDate仍未被赋值,最终返回的 JSON 也不包含这个字段。
-
业务逻辑:
- 设计上,
compareDate只有在比对完成时才有意义,未完成时保持null并被忽略是合理的。
- 设计上,
-
最终返回:
- Spring Boot 的
@RestController使用 Jackson(或其他配置)将PageImpl<FakeRegistrationListDTO>序列化为 JSON,同样忽略null字段,进一步确保空的compareDate不出现在响应中。
- Spring Boot 的
前端数据的验证
你的前端数据:
id: 34,33,32(comparisonStatus = 0或1):没有compareDate,因为未调用compare/save。id: 31,30,28(comparisonStatus = 2):有compareDate,因为通过compare/save设置了值。
改进建议
如果希望空的 compareDate 也返回(例如 "compareDate": null):
-
修改 FastJSON 配置:
FakeRegistrationListDTO fakeRegistrationListDTO = JSON.parseObject(JSON.toJSONString(fakeRegistration, SerializerFeature.WriteMapNullValue),FakeRegistrationListDTO.class );- 添加
WriteMapNullValue,确保null字段被包含。
- 添加
-
调整 DTO:
- 在
FakeRegistrationListDTO中显式处理:fakeRegistrationListDTO.setCompareDate(fakeRegistration.getCompareDate() != null ? fakeRegistration.getCompareDate() : null);
- 在
-
全局配置:
- 在 Spring Boot 中配置 Jackson:
@Bean public ObjectMapper objectMapper() {ObjectMapper mapper = new ObjectMapper();mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);return mapper; }
- 在 Spring Boot 中配置 Jackson:
总结
空的 compareDate 不返回给前端是因为:
- 业务逻辑:未完成比对时,数据库中
compareDate为NULL。 - FastJSON 默认行为:
JSON.toJSONString忽略null字段。 - 设计选择:后端选择不返回无意义的空字段。
这种行为是合理的,但如果前端需要一致性,可以通过上述方式调整后端返回。

相关文章:
FastJSON 默认行为:JSON.toJSONString 忽略 null 字段
完整的 FakeRegistrationController 代码,这让我可以全面分析后端逻辑,特别是为什么空的字段(如 compareDate)不返回给前端。我将详细分析代码的每个接口,尤其是与 list 请求和字段返回相关的部分,并解释原…...
数据结构:基数排序(c++实现)
个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 基数排序的定义和基本原理基本原理具体步骤 基数排序的优缺点:代码实现总结 基数排序的定义和基本原理 基数排序(Radix Sort)是一…...
DOM 事件 HTML 标签属性速查手册
以下是一份 DOM 事件 & HTML 标签属性速查手册,涵盖常用场景和示例,助你快速查阅和使用: 一、DOM 事件速查表 1. 鼠标事件 事件名触发时机适用元素示例代码click元素被点击任意可见元素button.addEventListener(click, () > { ... …...
PhotoShop学习01
了解Photoshop 这里省略了Photoshop的软件安装,请自行查找资源下载。 1.打开图片 下图为启动photoshop后出现的界面,我们可以通过创建新文件或打开已有文件来启用photoshop的工作界面。 可以通过左边的按钮进行新文件的创建或打开已有文件。 也可以点…...
mongodb【实用教程】
MongoDB 是一个开源的文档型数据库管理系统 下载安装 Windows 系统 https://blog.csdn.net/weixin_41192489/article/details/126777309 GUI工具 【推荐】MongoDB Compass https://www.mongodb.com/zh-cn/docs/compass/current/ Robo 3T https://blog.csdn.net/weixin_4119248…...
C语言机试编程题
编写版本:vc2022 1.求最大/小值 #include<stdio.h> int main(){int a[50],n;int max, min;printf("请输入您要输入几个数");scanf_s("%d", &n);printf("请输入您要比较的%d个数\n",n);for (int i 0; i<n; i) {scanf_…...
threeJs+vue 轻松切换几何体贴图
嗨,我是小路。今天主要和大家分享的主题是“threeJsvue 轻松切换几何体贴图”。 想象一下,手头上正好有个在线3D家具商店,用户不仅可以看到产品的静态图片,还能实时更换沙发的颜色或材质,获得真实的购物体验。…...
Android ObjectBox数据库使用与集成指南
ObjectBox其核心特点ObjectBox与 SQLite 和 Realm 的对比Android集成ObjectBox创建ObjectBox实体对象创建ObjectBox操作管理类OBManager在Application初始化ObjectBox插入或更新数据查询数据统计数据分页数据查询删除数据总结今天分享一套Android另一个数据库ObjectBox。Object…...
【HarmonyOS Next】地图使用详解(一)
背景 这系列文章主要讲解鸿蒙地图的使用,当前可以免费使用,并提供了丰富的SDK给开发者去自定义控件开发。目前可以实现个性化显示地图、位置搜索和路径规划等功能,轻松完成地图构建工作。需要注意的是,现在测试只能使用实体手机去…...
seacmsv9注入管理员账号密码+orderby+limi
1:mysql默认存储引擎innoDB携带的表 1,mysql.innodb_table_stats 2,mysql.innodb_index_stats SELECT table_name FROM mysql.innodb_table_stats WHERE database_name DATABASE(); 2: 关键字做处理 HEX编码:0x696E666F726D6174696F6E5F7…...
C#与AI的交互(以DeepSeek为例)
C#与ai的交互 与AI的交互使用的Http请求的方式,通过发送请求,服务器响应ai生成的文本 下面是完整的代码,我这里使用的是Ollama本地部署的deepseek,在联网调用api时,则url会有不同 public class OllamaRequester {[Se…...
面试八股文--数据库基础知识总结(2) MySQL
本文介绍关于MySQL的相关面试知识 一、关系型数据库 1、定义 关系型数据库(Relational Database)是一种基于关系模型的数据库管理系统(DBMS),它将数据存储在表格(表)中,并通过表格…...
Failed to start The PHP FastCGI Process Manager.
报错如下: Job for php-fpm.service failed because the control process exited with error code. See "systemctl status php-fpm.service" and "journalctl -xe" for details. 2月 25 21:49:00 nginx systemd[1]: Starting The PHP FastC…...
软件供应链安全工具链研究系列——RASP自适应威胁免疫平台(上篇)
1.1 基本能力 RASP是一种安全防护技术,运行在程序执行期间,使程序能够自我监控和识别有害的输入和行为。也就是说一个程序如果注入或者引入了RASP技术,那么RASP就和这个程序融为一体,使应用程序具备了自我防护的能力,…...
Spring Boot集成MyBatis访问MySQL:从项目搭建到基础数据库查询(基础入门)
Spring Boot集成MyBatis访问MySQL 一、引言 在当今企业级应用开发中,Spring Boot、MyBatis与MySQL的组合凭借其高效性和灵活性,成为构建数据驱动型应用的首选方案。本文将带你从零开始搭建项目,掌握Spring Boot集成MyBatis的基础入门内容。…...
一周学会Flask3 Python Web开发-Jinja2模板继承和include标签使用
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 不管是开发网站还是后台管理系统,我们页面里多多少少有公共的模块。比如博客网站,就有公共的头部&…...
【2025.2.25更新】wordpress免费AI插件,文章内容、图片自动生成、视频自动生成、网站AI客服、批量采集文章,内置deepseek联网满血版
wordpress免费AI插件,文章内容、文章图片、长尾关键词、视频自动生成、网站AI客服、批量采集文章,插件已接入腾讯云大模型知识引擎xDeepSeek,基于腾讯云大模型知识引擎xDeepSeek可联网满血版,插件可实现文章生成、长尾关键词生成、…...
待解决 leetcode71 简化路径 栈的应用
用多种ifelse很不好很复杂容易丢情况 class Solution { public:string simplifyPath(string path) {stack<char> st;string result;int n path.size();while(n > 1 && (path[n-1] / || path[n-1] .)){if(n > 2 && path[n-2] . && pat…...
数据安全_笔记系列09_人工智能(AI)与机器学习(ML)在数据安全中的深度应用
数据安全_笔记系列09_人工智能(AI)与机器学习(ML)在数据安全中的深度应用 人工智能与机器学习技术通过自动化、智能化的数据分析,显著提升了数据分类、威胁检测的精度与效率,尤其在处理非结构化数据、复杂…...
RocketMQ 可观测性最佳实践
RocketMQ 概述 Apache RocketMQ 是一个开源的分布式消息传递和流处理平台,由阿里巴巴团队最初开发并捐赠给 Apache 软件基金会。它主要用于处理大规模消息的发送和接收,支持高吞吐量、可扩展性强且具有高可用性的消息服务。 RocketMQ 的优势有以下几点…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...
基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...
