基于 Jackson 的 JSON 工具类实现解析与设计模式应用
一、项目背景与功能概览
在企业级开发中,JSON 序列化/反序列化是高频操作。本方案基于 Jackson 实现了一个双模式兼容(独立使用 + Spring 整合)、安全可靠的 JSON 工具类,主要提供以下能力:
- ✅ 常用 JSON 转换方法
- ✅ 多态类型安全解析
- ✅ 大数值前端兼容处理
- ✅ 统一时间格式处理
- ✅ Spring 环境无缝整合
二、核心类解析
1. JsonUtils.java(核心工具类)
定位:提供静态方法调用的 JSON 工具门面。
public class JsonUtils {private static ObjectMapper objectMapper = new ObjectMapper();static {objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);// 允许空对象objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 忽略未知字段objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 值objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化}/*** 初始化 objectMapper 属性* <p>* 通过这样的方式,使用 Spring 创建的 ObjectMapper Bean** @param objectMapper ObjectMapper 对象*/public static void init(ObjectMapper objectMapper) {JsonUtils.objectMapper = objectMapper;}@SneakyThrowspublic static String toJsonString(Object object) {return objectMapper.writeValueAsString(object);}@SneakyThrowspublic static byte[] toJsonByte(Object object) {return objectMapper.writeValueAsBytes(object);}@SneakyThrowspublic static String toJsonPrettyString(Object object) {return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);}public static <T> T parseObject(String text, Class<T> clazz) {if (StrUtil.isEmpty(text)) {return null;}try {return objectMapper.readValue(text, clazz);} catch (IOException e) {log.error("json parse err,json:{}", text, e);throw new RuntimeException(e);}}public static <T> T parseObject(String text, String path, Class<T> clazz) {if (StrUtil.isEmpty(text)) {return null;}try {JsonNode treeNode = objectMapper.readTree(text);JsonNode pathNode = treeNode.path(path);return objectMapper.readValue(pathNode.toString(), clazz);} catch (IOException e) {log.error("json parse err,json:{}", text, e);throw new RuntimeException(e);}}public static <T> T parseObject(String text, Type type) {if (StrUtil.isEmpty(text)) {return null;}try {return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type));} catch (IOException e) {log.error("json parse err,json:{}", text, e);throw new RuntimeException(e);}}/*** 将字符串解析成指定类型的对象* 使用 {@link #parseObject(String, Class)} 时,在@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) 的场景下,* 如果 text 没有 class 属性,则会报错。此时,使用这个方法,可以解决。** @param text 字符串* @param clazz 类型* @return 对象*/public static <T> T parseObject2(String text, Class<T> clazz) {if (StrUtil.isEmpty(text)) {return null;}return JSONUtil.toBean(text, clazz);}public static <T> T parseObject(byte[] bytes, Class<T> clazz) {if (ArrayUtil.isEmpty(bytes)) {return null;}try {return objectMapper.readValue(bytes, clazz);} catch (IOException e) {log.error("json parse err,json:{}", bytes, e);throw new RuntimeException(e);}}public static <T> T parseObject(String text, TypeReference<T> typeReference) {try {return objectMapper.readValue(text, typeReference);} catch (IOException e) {log.error("json parse err,json:{}", text, e);throw new RuntimeException(e);}}/*** 解析 JSON 字符串成指定类型的对象,如果解析失败,则返回 null** @param text 字符串* @param typeReference 类型引用* @return 指定类型的对象*/public static <T> T parseObjectQuietly(String text, TypeReference<T> typeReference) {try {return objectMapper.readValue(text, typeReference);} catch (IOException e) {return null;}}public static <T> List<T> parseArray(String text, Class<T> clazz) {if (StrUtil.isEmpty(text)) {return new ArrayList<>();}try {return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));} catch (IOException e) {log.error("json parse err,json:{}", text, e);throw new RuntimeException(e);}}public static <T> List<T> parseArray(String text, String path, Class<T> clazz) {if (StrUtil.isEmpty(text)) {return null;}try {JsonNode treeNode = objectMapper.readTree(text);JsonNode pathNode = treeNode.path(path);return objectMapper.readValue(pathNode.toString(), objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));} catch (IOException e) {log.error("json parse err,json:{}", text, e);throw new RuntimeException(e);}}public static JsonNode parseTree(String text) {try {return objectMapper.readTree(text);} catch (IOException e) {log.error("json parse err,json:{}", text, e);throw new RuntimeException(e);}}public static JsonNode parseTree(byte[] text) {try {return objectMapper.readTree(text);} catch (IOException e) {log.error("json parse err,json:{}", text, e);throw new RuntimeException(e);}}public static boolean isJson(String text) {return JSONUtil.isTypeJSON(text);}/*** 判断字符串是否为 JSON 类型的字符串* @param str 字符串*/public static boolean isJsonObject(String str) {return JSONUtil.isTypeJSONObject(str);}}
特性:
- 防御性校验:使用 StrUtil.isEmpty 防御空指针
- 异常统一处理:捕获 IOException 后记录完整日志并抛出运行时异常
- 多解析策略:支持路径解析(parseObject(text, path, clazz))、静默解析(parseObjectQuietly)
2. DyhJacksonAutoConfiguration.java(Spring 集成)
定位:Spring Boot 自动配置类,实现 ObjectMapper 的自定义配置。
@AutoConfiguration
@Slf4j
public class DyhJacksonAutoConfiguration {@Bean@SuppressWarnings("InstantiationOfUtilityClass")public JsonUtils jsonUtils(List<ObjectMapper> objectMappers) {// 1.1 创建 SimpleModule 对象SimpleModule simpleModule = new SimpleModule();simpleModule// 新增 Long 类型序列化规则,数值超过 2^53-1,在 JS 会出现精度丢失问题,因此 Long 自动序列化为字符串类型.addSerializer(Long.class, NumberSerializer.INSTANCE).addSerializer(Long.TYPE, NumberSerializer.INSTANCE).addSerializer(LocalDate.class, LocalDateSerializer.INSTANCE).addDeserializer(LocalDate.class, LocalDateDeserializer.INSTANCE).addSerializer(LocalTime.class, LocalTimeSerializer.INSTANCE).addDeserializer(LocalTime.class, LocalTimeDeserializer.INSTANCE)// 新增 LocalDateTime 序列化、反序列化规则,使用 Long 时间戳.addSerializer(LocalDateTime.class, TimestampLocalDateTimeSerializer.INSTANCE).addDeserializer(LocalDateTime.class, TimestampLocalDateTimeDeserializer.INSTANCE);// 1.2 注册到 objectMapperobjectMappers.forEach(objectMapper -> objectMapper.registerModule(simpleModule));// 2. 设置 objectMapper 到 JsonUtilsJsonUtils.init(CollUtil.getFirst(objectMappers));log.info("[init][初始化 JsonUtils 成功]");return new JsonUtils();}}
关键点:
- 自动收集机制:通过 List 参数获取 Spring 容器中所有 ObjectMapper 实例
- 模块化配置:使用 SimpleModule 统一管理自定义序列化规则
3. 自定义序列化器
(1) NumberSerializer.java
解决的问题:JavaScript 的 Number 类型精度限制(2^53-1)。
/*** Long 序列化规则** 会将超长 long 值转换为 string,解决前端 JavaScript 最大安全整数是 2^53-1 的问题** @author dyh*/
@JacksonStdImpl
public class NumberSerializer extends com.fasterxml.jackson.databind.ser.std.NumberSerializer {private static final long MAX_SAFE_INTEGER = 9007199254740991L;private static final long MIN_SAFE_INTEGER = -9007199254740991L;public static final NumberSerializer INSTANCE = new NumberSerializer(Number.class);public NumberSerializer(Class<? extends Number> rawType) {super(rawType);}@Overridepublic void serialize(Number value, JsonGenerator gen, SerializerProvider serializers) throws IOException {// 超出范围 序列化位字符串if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) {super.serialize(value, gen, serializers);} else {gen.writeString(value.toString());}}
}
(2) TimestampLocalDateTimeSerializer.java
/*** 基于时间戳的 LocalDateTime 序列化器** @author dyh*/
public class TimestampLocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {public static final TimestampLocalDateTimeSerializer INSTANCE = new TimestampLocalDateTimeSerializer();@Overridepublic void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {// 将 LocalDateTime 对象,转换为 Long 时间戳gen.writeNumber(value.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());}}
三、设计模式应用
1. 单例模式 (Singleton)
-
应用场景:自定义序列化器实例共享
-
代码示例:
public class NumberSerializer extends com.fasterxml.jackson.databind.ser.std.NumberSerializer {public static final NumberSerializer INSTANCE = new NumberSerializer(Number.class); }
2. 工厂方法模式 (Factory Method)
- 应用场景:ObjectMapper 的创建与配置
- 体现形式:
- JsonUtils 静态初始化块中创建基础配置的 ObjectMapper
- Spring 通过 @Bean 工厂方法创建并配置 ObjectMapper
3. 模板方法模式 (Template Method)
-
应用场景:JSON 解析的统一异常处理流程
-
代码体现:
public static <T> T parseObject(String text, Class<T> clazz) { try { return objectMapper.readValue(...); } catch (IOException e) { log.error(...); // 统一日志记录 throw new RuntimeException(e); // 统一异常转换 } }
四、使用示例
1. 基础序列化
User user = new User(1L, "yudaoyuanma", LocalDateTime.now());
String json = JsonUtils.toJsonString(user);
// 输出:{"id":"1","name":"yudaoyuanma","createTime":1672502400000}
2. 复杂解析
// 解析嵌套 JSON
String json = "{\"data\":{\"user\":{\"name\":\"test\"}}}";
User user = JsonUtils.parseObject(json, "data.user", User.class); // 静默解析(不抛异常)
TypeReference<ResultDTO<User>> typeRef = new TypeReference<>() {};
ResultDTO<User> result = JsonUtils.parseObjectQuietly(json, typeRef); 相关文章:
基于 Jackson 的 JSON 工具类实现解析与设计模式应用
一、项目背景与功能概览 在企业级开发中,JSON 序列化/反序列化是高频操作。本方案基于 Jackson 实现了一个双模式兼容(独立使用 Spring 整合)、安全可靠的 JSON 工具类,主要提供以下能力: ✅ 常用 JSON 转换方法✅ …...
87.在线程中优雅处理TryCatch返回 C#例子 WPF例子
在C#异步编程中,正确处理异常是确保程序稳定运行的关键。今天,我们通过一个实际的示例,展示如何在异步线程中使用try-catch块处理异常,并通过标志变量控制流程。同时,我们也会展示一个错误的示例,以便更好地…...
Vue + Axios + Mock.js 全链路实操:从封装到数据模拟的深度解析
一、项目架构深度设计 1.1 分层架构模式 采用经典的前端分层架构,实现高度可维护性: src/ ├─ api/ # 接口管理 │ └─ home.js # 模块化接口 ├─ mock/ # 模拟数据 │ ├─ index.js # Mock入口 │ └─ home.js # 首…...
博客文章:深入分析 PyMovie - 基于 Python和 MoviePy 的视频管理工具
这是一个使用 wxPython 构建界面、moviepy 处理视频的自定义 GUI 应用程序。该工具提供了视频播放、元数据提取、格式转换、视频裁剪和截图等功能。通过分析其设计和实现,我们将了解其工作原理、优点和潜在的改进空间。 C:\pythoncode\new\output\pymovieSample.py …...
Go基础一(Maps Functions 可变参数 闭包 递归 Range 指针 字符串和符文 结构体)
Maps 1.创建map make(map[键类型]值类型) 2.设置键值对 name[key]value; 3. name[key]获取键值 3.1 key不存在 则返回 0 4.len()方法 返回 map 上 键值对数量 len(name) 5.delete()方法 从map中删除 键值对 delete(name,key) 6.clear()方法 map中删除所有键值对 clear(name) 7…...
2025年渗透测试面试题总结-某 携程旅游-基础安全工程师(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 携程旅游-基础安全工程师 反序列化原理 核心原理 扩展分析 SQL注入本质 核心原理 扩展分析 SQL注…...
wireshak抓手机包 wifi手机抓包工具
移动端接口测试抓包工具指南 在做手机或移动端APP的接口测试时,获取完整的接口文档是关键。但如果没有文档,我们就需要使用专业的抓包工具来分析网络请求。本文将介绍两种常用的抓包方案:Fiddler和Sniff Master(抓包大师…...
niuhe插件, 在 go 中渲染网页内容
思路 niuhe 插件生成的 go 代码是基于 github.com/ma-guo/niuhe 库进行组织管理的, niuhe 库 是对 go gin 库的一个封装,因此要显示网页, 可通过给 gin.Engine 指定 HTMLRender 来实现。 实现 HTMLRender 我们使用 gitee.com/cnmade/pongo2gin 实现 1. main.go …...
java基础知识面试题总结
Java基础知识面试题 1.重载和重写的区别 重载(Overload): 同一个类中,方法名相同,参数列表不同(个数、类型、顺序)。 class Calculator {// 方法1:两个int相加public int add…...
使用MySQL时出现 Ignoring query to other database 错误
Ignoring query to other database 错误 当在远程连接软件中输入MySQL命令出现该错误 导致错误原因是:登录mysql时账户名没有加上u 如果出现该错误,退出mysql,重新输入正确格式进入即可!...
MySQL介绍及使用
1. 安装、启动、配置 MySQL 1. 安装 MySQL 更新软件包索引 sudo apt update 安装 MySQL 服务器 sudo apt install mysql-server 安装过程中可能会提示你设置 root 用户密码。如果没有提示,可以跳过,后续可以手动设置。 2. 配置 MySQL 运行安全脚本…...
Vue2-实现elementUI的select全选功能
文章目录 使用 Element UI 的全选功能自定义选项来模拟全选 在使用 Element UI 的 el-select组件时,实现“全选”功能,通常有两种方式:一种是使用内置的全选功能,另一种是通过自定义选项来模拟全选。 使用 Element UI 的全选功能…...
java后端开发day34--脑子空空如何无痛想起所有知识点--概念拟人化
1.上半部学习思考 1.1反思–浮躁–二倍速 刚开始算半个小白吧,从最基础的知识点开始学习,到后面学习整个项目的布局和功能。可能是后面慢慢懂得多了,每次打代码搞项目啊什么的,就能明显感觉到自己很浮躁:脑子里已经明…...
fastGPT—前端开发获取api密钥调用机器人对话接口(HTML实现)
官网文档链接:OpenAPI 介绍 | FastGPT 首先按照文档说明创建api密钥 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-sca…...
解决 PDF 难题:批量处理、文档清理与自由拆分合并
软件介绍 在日常办公与学习中,处理 PDF 文件常常让人头疼不已,不过别担心,今天有一款堪称神器的国产老牌 PDF 工具要分享给大家。它就是 PDF 补丁丁,凭借其强大功能,为大家排忧解难。 界面体验 初次打开 PDF 补丁丁&…...
使用pycharm社区版调试DIFY后端python代码
目录 背景 前置条件 DIFY使用的框架 API服务调试配置步骤(基于tag为0.15.3的版本) 1.配置.env文件 2.关闭docker里面的docker-api-1服务 3.使用DOCKER启动本地环境需要用到的中间件,并暴露端口 注意事项一: 注意事项二:…...
量子计算与人工智能的结合:未来科技的双重革命
引言 在过去几十年里,人工智能(AI)和计算能力的提升一直是推动科技进步的重要力量。然而,随着深度学习和大规模数据处理的发展,传统计算架构的算力瓶颈逐渐显现,人工智能的训练和推理效率受到了限制。在此背…...
关于存储的笔记
存储简介 名称适用场景常见运用网络环境备注块存储高性能、低延迟数据库局域网专业文件存储数据共享共享文件夹、非结构化数据局域网通用对象存储大数据、云存储网盘、网络媒体公网(断点续传、去重)海量 存储协议 名称协议块存储FC-SAN或IP-SAN承载的…...
基于机器学习的三国时期诸葛亮北伐失败因素量化分析
一、研究背景与方法论 1.1 历史问题的数据化挑战 三国时期(220-280年)的战争史存在史料分散、数据缺失的特点。本研究通过构建包含军事、经济、地理、政治四大维度的结构化数据库,收录建安十二年(207年)至建兴十二年…...
MySQL 中的 MVCC 版本控制机制原理
1. MVCC(多版本并发控制)概述 MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种数据库事务并发控制机制,主要用于提高数据库的读写性能。它通过维护数据的多个版本,使得读操作无…...
JWT认证服务
JSON Web Token(JWT)是一种用于在网络应用间安全地传递信息的紧凑、自包含的方式。以下是关于 JWT 认证服务器更详细的介绍,包括其意义、作用、工作原理、组成部分、时效性相关内容、搭建条件以及代码案例。 JWT 的意义与作用 意义…...
RAG中对于PDF复杂格式文件的预处理的解决方案:MinerU
RAG中对于PDF复杂格式文件的预处理的解决方案:MinerU 1. 场景 在RAG场景下,我们所遇到的文档格式可不仅仅局限于txt文件,而对于复杂的PDF文件,里面有图片格式的Excel、图片格式的文字、以及公式等等复杂的格式,我们很难用传统的方式去解析预处理成我们可以用的类似于TXT…...
手机中的type-C是如何防水的呢?
防水类型的type-C座子: 电子产品防水等级的区分: 这里的“IP”是国际防护标准等级;简而言之,IPXX中“XX”两位数字分别代表防尘和防水等级,其中防尘等级从0~6,防水等级则从0~8。 第…...
[Redis]Redis学习开篇概述
欢迎来到啾啾的博客🐱。 这是一个致力于构建完善 Java 程序员知识体系的博客📚。 它记录学习点滴,分享工作思考和实用技巧,偶尔也分享一些杂谈💬。 欢迎评论交流,感谢您的阅读😄。 引言 大家好…...
WordPress浮动广告插件+飘动效果客服插件
源码介绍 WordPress浮动广告插件飘动效果客服插件 将源码上传到wordpress的插件根目录下,解压,然后后台启用即可 截图 源码免费获取 WordPress浮动广告插件飘动效果客服插件...
Java基础关键_034_网络编程
目 录 一、概述 二、网络编程三要素 1.IP 地址 2.端口号 3.通信协议 (1)说明 (2)OSI 七层参考模型 (3)TCP/IP 四层参考模型 三、网络编程基础类 1.InetAddress 2.URL (1)…...
Ubuntu交叉编译器工具链安装
声明 本博客所记录的关于正点原子i.MX6ULL开发板的学习笔记,(内容参照正点原子I.MX6U嵌入式linux驱动开发指南,可在正点原子官方获取正点原子Linux开发板 — 正点原子资料下载中心 1.0.0 文档),旨在如实记录我在学校学…...
C# 操作 Redis
一、简介 C# 中通过 StackExchange.Redis 库可以方便地操作 Redis,实现高性能的数据缓存和存储。StackExchange.Redis 提供了强大的 API,允许开发者轻松连接、读取和写入 Redis 数据。通过使用 ConnectionMultiplexer 类,可以建立与 Redis 服…...
基于Python的招聘推荐数据可视化分析系统
【Python】基于Python的招聘推荐数据可视化分析系统(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 🚀🌟 基于Python的招聘推荐数据可视化分析系统!…...
光谱相机在工业中的应用
光谱相机(多光谱、高光谱、超光谱成像技术)在工业领域通过捕捉物质的光谱特征(反射、透射、辐射等),结合化学计量学与人工智能算法,为工业检测、质量控制和工艺优化提供高精度、非接触式的解决方案。以下是…...
