diff --git a/yami-shop-common/src/main/java/com/yami/shop/common/util/Json.java b/yami-shop-common/src/main/java/com/yami/shop/common/util/Json.java new file mode 100644 index 0000000..087e6e9 --- /dev/null +++ b/yami-shop-common/src/main/java/com/yami/shop/common/util/Json.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved. + * + * https://www.mall4j.com/ + * + * 未经允许,不可做商业用途! + * + * 版权所有,侵权必究! + */ + +package com.yami.shop.common.util; + +// 导入Jackson相关的注解和类,用于配置JSON序列化和反序列化过程中的一些行为,比如包含哪些属性、如何处理未知属性等 +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.json.JsonWriteFeature; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +// 导入Lombok的日志记录相关注解,用于简化日志记录代码,自动生成名为log的日志记录对象 +import lombok.extern.slf4j.Slf4j; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Json工具类,主要基于Jackson库提供了一系列便捷的JSON处理方法, + * 包括将Java对象转换为JSON字符串、将JSON字符串反序列化为Java对象(单个对象、对象数组、JSON节点等多种形式), + * 同时在类初始化时对Jackson的ObjectMapper进行了一些常用的配置,以满足特定的JSON处理需求,例如处理空值、未知属性、日期格式等情况。 + * + * @author lanhai + */ +@Slf4j +public class Json { + + // 创建一个静态的ObjectMapper实例,ObjectMapper是Jackson库中用于进行JSON序列化和反序列化的核心类,后续所有的JSON操作都基于它来实现 + private static ObjectMapper objectMapper = new ObjectMapper(); + + // 静态代码块,用于对ObjectMapper实例进行一系列的配置,这些配置会影响JSON序列化和反序列化的行为。 + static { + // 设置序列化时的包含规则,这里配置为JsonInclude.Include.NON_EMPTY,表示如果属性值为空(比如null、空字符串、空集合等)则不输出该属性到JSON字符串中,减少不必要的JSON数据量。 + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + // 配置在序列化时,对于空的Java对象(没有任何属性值的对象)转JSON的时候不抛出错误,而是正常返回一个空的JSON对象(如 {}),增强程序的健壮性,避免因空对象序列化失败导致整个操作中断。 + objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); + // 禁用将日期类型属性序列化为时间戳的功能,这样在处理日期类型数据时可以按照更符合业务需求的日期格式(比如特定的字符串格式)进行序列化,而不是默认的时间戳形式。 + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + // 禁用在反序列化时遇到未知属性(即JSON字符串中的属性在对应的Java类中不存在定义)抛出异常的功能,这样即使JSON数据有额外的属性,也能尽量解析出已知的属性值,避免因未知属性导致整个反序列化失败。 + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + // 取消对非ASCII字符的转码操作,使得JSON字符串中可以直接包含如中文等非ASCII字符,而不需要进行转义编码,方便查看和处理,更符合实际业务场景中对中文等字符的使用需求。 + objectMapper.configure(JsonWriteFeature.ESCAPE_NON_ASCII.mappedFeature(), false); + + } + + /** + * 将给定的Java对象转换为JSON字符串的方法。 + * 通过调用ObjectMapper的writeValueAsString方法来实现转换,如果在转换过程中出现JSON处理异常(如对象的属性类型不支持序列化等情况), + * 则会记录错误日志,并返回null,由调用者根据实际情况进行后续处理。 + * + * @param object 要转换为JSON字符串的Java对象,可以是任意符合Jackson序列化规则的对象,如POJO、集合、基本数据类型包装类等。 + * @return String 返回转换后的JSON字符串,如果转换过程出现异常则返回null。 + */ + public static String toJsonString(Object object) { + try { + return objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + // 记录对象转JSON时出现的错误日志,方便后续排查问题,这里记录了异常的详细信息(通过传入e作为参数) + log.error("对象转json错误:", e); + } + return null; + } + + /** + * 将给定的JSON字符串反序列化为指定类型的Java对象的方法。 + * 通过调用ObjectMapper的readValue方法,按照传入的目标类类型(clazz)信息将JSON字符串解析为对应的Java对象, + * 如果在反序列化过程中出现异常(如JSON格式不符合要求、属性类型不匹配等情况),则会记录错误日志,并返回null, + * 由调用者根据实际情况进行后续处理。 + * + * @param json 要反序列化的JSON字符串,需要符合对应Java类的结构和Jackson的解析规则。 + * @param clazz 目标Java类的类型,用于告诉ObjectMapper将JSON字符串解析成什么类型的对象,必须是具体的类类型,不能是接口或抽象类等无法实例化的类型。 + * @return 返回反序列化后的Java对象,类型与传入的clazz参数指定的类型一致,如果反序列化过程出现异常则返回null。 + */ + public static T parseObject(String json, Class clazz) { + T result = null; + try { + result = objectMapper.readValue(json, clazz); + } catch (Exception e) { + // 记录JSON转对象时出现的错误日志,方便后续排查问题,这里记录了异常的详细信息(通过传入e作为参数) + log.error("对象转json错误:", e); + } + return result; + } + + /** + * 获取配置好的ObjectMapper实例的方法,外部代码可以通过获取该实例来进行更复杂、自定义的JSON序列化和反序列化操作, + * 利用已有的配置来满足一些特殊的JSON处理需求,比如使用不同的JSON格式、自定义序列化器和反序列化器等情况。 + * + * @return ObjectMapper 返回配置好的ObjectMapper实例,供外部调用进行JSON相关操作。 + */ + public static ObjectMapper getObjectMapper() { + return objectMapper; + } + + /** + * 将给定的JSON字符串反序列化为指定类型的Java对象数组,并将其转换为对应的List集合的方法。 + * 先通过ObjectMapper的readValue方法将JSON字符串按照传入的对象数组类型(clazz)解析为对象数组, + * 如果解析成功,则将对象数组转换为List集合返回;如果解析过程出现异常或者解析结果为null,则返回一个空的List集合, + * 保证方法的返回结果具有一定的稳定性,方便调用者进行后续操作而不用担心空指针等问题。 + * 此方法相较于使用TypeReference来处理数组反序列化,在特定情况下(如文档中提到的,最多可快10倍)性能更好。 + * + * @param json 要反序列化的JSON字符串,其结构需要符合对应Java对象数组的格式要求,即包含多个符合指定类型的JSON对象表示。 + * @param clazz 目标Java对象数组的类型,用于告诉ObjectMapper将JSON字符串解析成什么类型的对象数组,必须是具体的类数组类型,如MyClass[].class。 + * @return 返回反序列化后的Java对象列表,类型与传入的clazz参数指定的对象数组中的元素类型一致,如果反序列化出现异常则返回空的List集合。 + */ + public static List parseArray(String json, Class clazz) { + T[] result = null; + try { + result = objectMapper.readValue(json, clazz); + } catch (Exception e) { + // 记录JSON转换时出现的错误日志,方便后续排查问题,这里记录了异常的详细信息(通过传入e作为参数) + log.error("Json转换错误:", e); + } + if (result == null) { + return Collections.emptyList(); + } + return Arrays.asList(result); + } + + /** + * 将给定的JSON字符串转换为JsonNode对象的方法,JsonNode类似于JSON数据的树形结构表示,可以方便地对JSON数据进行灵活的遍历、查询和操作, + * 相当于将JSON字符串解析为一个通用的、可以灵活处理的JSON节点对象(类似Map结构,可以按节点层次获取属性值等)。 + * 如果在转换过程中出现异常,则会记录错误日志,并返回null,由调用者根据实际情况进行后续处理。 + * + * @param jsonStr 要转换为JsonNode对象的JSON字符串,格式需符合JSON语法规范。 + * @return JsonNode 返回解析后的JsonNode对象,如果转换过程出现异常则返回null,通过该对象可以进一步操作JSON数据的各个节点和属性。 + */ + public static JsonNode parseJson(String jsonStr) { + JsonNode jsonNode = null; + try { + jsonNode = objectMapper.readTree(jsonStr); + } catch (Exception e) { + // 记录JSON转换时出现的错误日志,方便后续排查问题,这里记录了异常的详细信息(通过传入e作为参数) + log.error("Json转换错误:", e); + } + return jsonNode; + } +} \ No newline at end of file