FastJSON 默认行为:JSON.toJSONString 忽略 null 字段

完整的 FakeRegistrationController 代码,这让我可以全面分析后端逻辑,特别是为什么空的字段(如 compareDate)不返回给前端。我将详细分析代码的每个接口,尤其是与 list 请求和字段返回相关的部分,并解释原因。


代码结构总览

FakeRegistrationController 是一个 RESTful 控制器,提供了三个接口:

  1. POST /fakeRegistration/registration/save:保存或修改假货登记信息。
  2. POST /fakeRegistration/compare/save:保存或修改比对结果。
  3. 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()));
}
数据流分析
  1. 数据查询

    • fakeRegistrationService.findByAdminId(vipAdminId, page) 返回一个 Page<FakeRegistration>,其中 FakeRegistration 是数据库实体类,包含所有字段(如 id, createdDate, compareDate, comparisonStatus 等)。
    • fakeRegistrations 是分页内容的 List<FakeRegistration>
  2. 数据转换

    • 每个 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 获取。
      • genuineIdentificationPointsfakeIdentificationPoints:从 FakeRegistrationApiService 获取。
  3. 返回结果

    • 返回一个 PageImpl<FakeRegistrationListDTO>,最终被序列化为 JSON 响应。
为什么空的字段(如 compareDate)不返回?
  • FastJSON 的默认行为

    • FastJSON 在序列化时,默认忽略 null 值字段,除非显式配置 SerializerFeature.WriteMapNullValue
    • 如果 FakeRegistrationcompareDatenullJSON.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 中没有 compareDatefakeRegistrationListDTOcompareDate 字段不会被赋值,最终返回的 JSON 也不会包含它。
  • 业务逻辑

    • 从其他接口看,compareDate 只有在 compare/save 接口保存比对结果时才会设置:
      fakeRegistrationOrigin.setCompareDate(new Date());
      
    • registration/save 接口中,新建记录时没有设置 compareDate,它保持为 null
    • 因此,未完成比对的记录(comparisonStatus = 01)在数据库中 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),只设置了 adminIdcreatorId,没有初始化 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

综合结论:为什么空的字段不返回?

  1. 数据来源

    • compareDate 在数据库中默认为 NULL,除非通过 compare/save 接口保存比对结果时才会被赋值。
    • 未完成比对的记录(comparisonStatus = 01)没有 compareDate 值。
  2. FastJSON 序列化

    • list 接口中,JSON.toJSONString(fakeRegistration)FakeRegistration 转为 JSON 时,默认忽略 null 字段。
    • 如果 compareDatenull,它不会出现在 JSON 字符串中。
    • 反序列化到 FakeRegistrationListDTO 后,compareDate 仍未被赋值,最终返回的 JSON 也不包含这个字段。
  3. 业务逻辑

    • 设计上,compareDate 只有在比对完成时才有意义,未完成时保持 null 并被忽略是合理的。
  4. 最终返回

    • Spring Boot 的 @RestController 使用 Jackson(或其他配置)将 PageImpl<FakeRegistrationListDTO> 序列化为 JSON,同样忽略 null 字段,进一步确保空的 compareDate 不出现在响应中。

前端数据的验证

你的前端数据:

  • id: 34, 33, 32comparisonStatus = 01):没有 compareDate,因为未调用 compare/save
  • id: 31, 30, 28comparisonStatus = 2):有 compareDate,因为通过 compare/save 设置了值。

改进建议

如果希望空的 compareDate 也返回(例如 "compareDate": null):

  1. 修改 FastJSON 配置

    FakeRegistrationListDTO fakeRegistrationListDTO = JSON.parseObject(JSON.toJSONString(fakeRegistration, SerializerFeature.WriteMapNullValue),FakeRegistrationListDTO.class
    );
    
    • 添加 WriteMapNullValue,确保 null 字段被包含。
  2. 调整 DTO

    • FakeRegistrationListDTO 中显式处理:
      fakeRegistrationListDTO.setCompareDate(fakeRegistration.getCompareDate() != null ? fakeRegistration.getCompareDate() : null);
      
  3. 全局配置

    • 在 Spring Boot 中配置 Jackson:
      @Bean
      public ObjectMapper objectMapper() {ObjectMapper mapper = new ObjectMapper();mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);return mapper;
      }
      

总结

空的 compareDate 不返回给前端是因为:

  • 业务逻辑:未完成比对时,数据库中 compareDateNULL
  • FastJSON 默认行为JSON.toJSONString 忽略 null 字段。
  • 设计选择:后端选择不返回无意义的空字段。

这种行为是合理的,但如果前端需要一致性,可以通过上述方式调整后端返回。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/896403.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型基础概念之神经网络宽度

在大模型中,神经网络宽度是提升模型容量的核心手段之一,与深度、数据规模共同构成性能的三大支柱。合理增加宽度可显著增强模型表达能力,但需结合正则化、硬件优化和结构设计进行平衡。未来趋势可能包括动态宽度调整、稀疏化宽度设计(如MoE)以及更高效宽度-深度复合缩放策…

在Linux环境下利用MTCNN进行人脸检测(基于ncnn架构)

概述 本文将详细介绍如何在Linux环境下部署MTCNN模型进行人脸检测&#xff0c;并使用NCNN框架进行推理。 1. CMake的安装与配置 下载CMake源码 前往CMake官网下载&#xff0c;找到适合您系统的最新版本tar.gz文件链接&#xff0c;或者直接通过wget下载&#xff1a;CMake官方…

算法day1 dfs搜索2题

一 火星人 拿到这种类似于排序的&#xff0c;这个就好比如我们之前学习dfs基础的时候里面的指数型枚举 指数型枚举数据与数据之间没有任何枚举&#xff0c;就比如选这个数字与不选组合型枚举数据与数据之间有联系&#xff0c;下一个数字不可以给上一个数字排列型枚举数据与数…

CC攻击防御策略全解析:技术实现与代码示例

CC攻击&#xff08;Challenge Collapsar&#xff09;是一种以消耗服务器资源为目标的分布式拒绝服务攻击&#xff08;DDoS&#xff09;&#xff0c;其特点在于攻击流量伪装成合法请求&#xff0c;难以通过传统防火墙完全防御。本文将从技术实现角度详细解析CC攻击的防御策略&am…

(九)axios的使用

1、axios 的基本使用 1.1、简介 在 Web 开发的演进历程中&#xff0c;数据请求方式的变革至关重要。回溯早期&#xff0c;旧浏览器在向服务器请求数据时&#xff0c;存在严重弊端。由于返回的是整个页面数据&#xff0c;每次请求都会导致页面强制刷新&#xff0c;这不仅极大地…

【MySQL篇】数据库基础

目录 1&#xff0c;什么是数据库&#xff1f; 2&#xff0c;主流数据库 3&#xff0c;MySQL介绍 1&#xff0c;MySQL架构 2&#xff0c;SQL分类 3&#xff0c;MySQL存储引擎 1&#xff0c;什么是数据库&#xff1f; 数据库&#xff08;Database&#xff0c;简称DB&#xf…

网络安全事件研判

&#x1f345; 点击文末小卡片 &#xff0c;免费获取网络安全全套资料&#xff0c;资料在手&#xff0c;涨薪更快 研判&#xff08;入侵检测&#xff09; 研判我理解为人工层面对入侵检测事件进行再分析&#xff0c;即借助已有的设备告警根据经验判断是否为真实action 研判工作…

python整理文件下

我们使用 os.path.join() 函数拼接出文件要移动的目标地址。 并使用 os.path.exists() 函数配合 not 关键字找到未创建的文件夹。 这节课&#xff0c;我们会先创建文件夹&#xff0c;然后再移动文件到目标文件夹。如果文件夹不存在&#xff0c;我们需要先创建文件夹&#xff…

hackmyvm-buster

题目地址 信息收集 主机发现 ┌──(root㉿kali)-[/home/kali] └─# arp-scan -I eth1 192.168.56.0/24 Interface: eth1, type: EN10MB, MAC: 00:0c:29:34:da:f5, IPv4: 192.168.56.103 WARNING: Cannot open MAC/Vendor file ieee-oui.txt: Permission denied WARNING: C…

FS800DTU联动OneNET平台数据可视化View

目录 1 前言 2 环境搭建 2.1 硬件准备 2.2 软件环境 2.3 硬件连接 3 注册OneNET云平台并建立物模型 3.1 参数获取 3.2 连接OneNET 3.3上报数据 4 数据可视化View 4.1 用户信息获取 4.2 启用数据可视化View 4.3 创建项目 4.4 编辑项目 4.5 新增数据源 4.6 数据过滤器配置 4.6 项…

Dockerfile 中的 COPY 语句:作用与使用详解

在 Docker 的构建过程中&#xff0c;Dockerfile 是一个核心文件&#xff0c;它定义了镜像的构建步骤和内容。其中&#xff0c;COPY 语句是一个非常重要的指令&#xff0c;用于将文件或目录从构建上下文&#xff08;通常是 Dockerfile 所在的目录及其子目录&#xff09;复制到容…

大白话Vuex 核心概念(state、mutations、actions)的使用案例与原理

大白话Vuex 核心概念&#xff08;state、mutations、actions&#xff09;的使用案例与原理 Vuex是Vue.js应用程序中专门用来管理状态的工具&#xff0c;就好像是一个大管家&#xff0c;帮你把项目里一些重要的数据和操作管理得井井有条。下面用大白话结合案例来介绍Vuex核心概…

机器学习介绍与数据集

一、机器学习介绍与定义 1.1 机器学习定义 机器学习&#xff08;Machine Learning&#xff09;是让计算机从数据中自动学习规律&#xff0c;并依据这些规律对未来数据进行预测的技术。它涵盖聚类、分类、决策树、贝叶斯、神经网络、深度学习&#xff08;Deep Learning&#xf…

大模型训练——pycharm连接实验室服务器

一、引言 我们在运行或者复现大佬论文代码的时候&#xff0c;笔记本的算力不够&#xff0c;需要使用实验室的服务器进行运行。可以直接在服务器的终端上执行&#xff0c;但是这样的话代码调试就不方便。而我们可以使用 pycharm 连接到服务器&#xff0c;既方便了代码调试&…

【Linux】进程优先级 | 进程调度(三)

目录 前言&#xff1a; 一、进程优先级&#xff1a; 1.通过nice值修改优先级&#xff1a; 二、进程切换&#xff1a; 三、上下文数据 四、Linux真实调度算法&#xff1a; 五、bitmap位图&#xff1a; 六、命令总结&#xff1a; 总结&#xff1a; 前言&#xff1a; 我…

【redis】数据类型之hyperloglog

Redis的HyperLogLog&#xff08;HLL&#xff09;是一种高效的概率数据结构&#xff0c;也是一种基于字符串的数据结构&#xff0c;用于估计大数据集的唯一元素数量&#xff08;基数统计&#xff09;。它通过极低的内存占用&#xff08;约 12KB&#xff09;实现接近线性的时间复…

【C语言】第八期——指针、二维数组与字符串

目录 1 初始指针 2 获取变量的地址 3 定义指针变量、取地址、取值 3.1 定义指针变量 3.2 取地址、取值 4 对指针变量进行读写操作 5 指针变量作为函数参数 6 数组与指针 6.1 指针元素指向数组 6.2 指针加减运算&#xff08;了解&#xff09; 6.2.1 指针加减具体数字…

SpringBoot——生成Excel文件

在Springboot以及其他的一些项目中&#xff0c;或许我们可能需要将数据查询出来进行生成Excel文件进行数据的展示&#xff0c;或者用于进行邮箱发送进行附件添加 依赖引入 此处demo使用maven依赖进行使用 <dependency><groupId>org.apache.poi</groupId>&…

mac 下 java 调用 gurobi 不能加载 jar

在 mac 电脑中的 java 始终不能加载 gurobi 的 jar 包&#xff0c;java 的开发软件 eclipse&#xff0c;idea 总是显示找不到 gurobi 的 jar 包&#xff0c;但是 jar 包明明就在那里。 摸索了三个小时&#xff0c;最后发现原因竟然是&#xff1a; jar 包太新&#xff0c;替换…

服务端配置TCP探活,超出探活时间后的行为?

server端启动 &#xff08;完整源码在最后&#xff09; 配置探活 setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPIDLE, &(int){5}, sizeof(int)); // 空闲60秒后探测setsockopt(client_fd, IPPROTO_TCP, TCP_KEEPINTVL, &(int){10}, sizeof(int)); // 探测间隔10秒…