From 302e085a18f329651d0ec3c027b159d7796b8e85 Mon Sep 17 00:00:00 2001 From: cuijiawang Date: Tue, 12 Aug 2025 17:21:44 +0800 Subject: [PATCH] common-json --- agileboot-common/pom.xml | 1 + agileboot-common/wol-common-box/pom.xml | 7 +- agileboot-common/wol-common-json/pom.xml | 32 ++++ .../common/json/config/JacksonConfig.java | 50 ++++++ .../json/handler/BigNumberSerializer.java | 42 +++++ .../json/handler/CustomDateDeserializer.java | 31 ++++ .../common/json/utils/JsonUtils.java | 170 ++++++++++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + agileboot-common/wol-common-web/pom.xml | 4 + 9 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 agileboot-common/wol-common-json/pom.xml create mode 100644 agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/config/JacksonConfig.java create mode 100644 agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/handler/BigNumberSerializer.java create mode 100644 agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/handler/CustomDateDeserializer.java create mode 100644 agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/utils/JsonUtils.java create mode 100644 agileboot-common/wol-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/agileboot-common/pom.xml b/agileboot-common/pom.xml index 100a7a6..bfe5c6c 100644 --- a/agileboot-common/pom.xml +++ b/agileboot-common/pom.xml @@ -15,6 +15,7 @@ wol-common-doc wol-common-mybatis wol-common-redis + wol-common-json pom diff --git a/agileboot-common/wol-common-box/pom.xml b/agileboot-common/wol-common-box/pom.xml index 20d448b..9b7da86 100644 --- a/agileboot-common/wol-common-box/pom.xml +++ b/agileboot-common/wol-common-box/pom.xml @@ -37,9 +37,14 @@ wol-common-redis ${revision} + + com.agileboot + wol-common-json + ${revision} + - \ No newline at end of file + diff --git a/agileboot-common/wol-common-json/pom.xml b/agileboot-common/wol-common-json/pom.xml new file mode 100644 index 0000000..cb37182 --- /dev/null +++ b/agileboot-common/wol-common-json/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + + com.agileboot + agileboot-common + 1.0.0 + + + wol-common-json + + + + com.agileboot + wol-common-core + + + + + com.fasterxml.jackson.core + jackson-databind + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + diff --git a/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/config/JacksonConfig.java b/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/config/JacksonConfig.java new file mode 100644 index 0000000..b39d502 --- /dev/null +++ b/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/config/JacksonConfig.java @@ -0,0 +1,50 @@ +package com.agileboot.common.json.config; + +import com.agileboot.common.json.handler.BigNumberSerializer; +import com.agileboot.common.json.handler.CustomDateDeserializer; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.TimeZone; + +/** + * jackson 配置 + * + * @author Lion Li + */ +@Slf4j +@AutoConfiguration(before = JacksonAutoConfiguration.class) +public class JacksonConfig { + + @Bean + public Jackson2ObjectMapperBuilderCustomizer customizer() { + return builder -> { + // 全局配置序列化返回 JSON 处理 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + javaTimeModule.addDeserializer(Date.class, new CustomDateDeserializer()); + builder.modules(javaTimeModule); + builder.timeZone(TimeZone.getDefault()); + log.info("初始化 jackson 配置"); + }; + } + +} diff --git a/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/handler/BigNumberSerializer.java b/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/handler/BigNumberSerializer.java new file mode 100644 index 0000000..eda1ee4 --- /dev/null +++ b/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/handler/BigNumberSerializer.java @@ -0,0 +1,42 @@ +package com.agileboot.common.json.handler; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; +import com.fasterxml.jackson.databind.ser.std.NumberSerializer; + +import java.io.IOException; + +/** + * 超出 JS 最大最小值 处理 + * + * @author Lion Li + */ +@JacksonStdImpl +public class BigNumberSerializer extends NumberSerializer { + + /** + * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来 + */ + private static final long MAX_SAFE_INTEGER = 9007199254740991L; + private static final long MIN_SAFE_INTEGER = -9007199254740991L; + + /** + * 提供实例 + */ + public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); + + public BigNumberSerializer(Class rawType) { + super(rawType); + } + + @Override + public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { + // 超出范围 序列化位字符串 + if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { + super.serialize(value, gen, provider); + } else { + gen.writeString(value.toString()); + } + } +} diff --git a/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/handler/CustomDateDeserializer.java b/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/handler/CustomDateDeserializer.java new file mode 100644 index 0000000..319c034 --- /dev/null +++ b/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/handler/CustomDateDeserializer.java @@ -0,0 +1,31 @@ +package com.agileboot.common.json.handler; + +import cn.hutool.core.date.DateUtil; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; +import java.util.Date; + +/** + * 自定义 Date 类型反序列化处理器(支持多种格式) + * + * @author AprilWind + */ +public class CustomDateDeserializer extends JsonDeserializer { + + /** + * 反序列化逻辑:将字符串转换为 Date 对象 + * + * @param p JSON 解析器,用于获取字符串值 + * @param ctxt 上下文环境(可用于获取更多配置) + * @return 转换后的 Date 对象,若为空字符串返回 null + * @throws IOException 当字符串格式非法或转换失败时抛出 + */ + @Override + public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + return DateUtil.parse(p.getText()); + } + +} diff --git a/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/utils/JsonUtils.java b/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/utils/JsonUtils.java new file mode 100644 index 0000000..3d87da5 --- /dev/null +++ b/agileboot-common/wol-common-json/src/main/java/com/agileboot/common/json/utils/JsonUtils.java @@ -0,0 +1,170 @@ +package com.agileboot.common.json.utils; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.extra.spring.SpringUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 工具类 + * + * @author 芋道源码 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JsonUtils { + + private static final ObjectMapper OBJECT_MAPPER = SpringUtil.getBean(ObjectMapper.class); + + public static ObjectMapper getObjectMapper() { + return OBJECT_MAPPER; + } + + /** + * 将对象转换为JSON格式的字符串 + * + * @param object 要转换的对象 + * @return JSON格式的字符串,如果对象为null,则返回null + * @throws RuntimeException 如果转换过程中发生JSON处理异常,则抛出运行时异常 + */ + public static String toJsonString(Object object) { + if (ObjectUtil.isNull(object)) { + return null; + } + try { + return OBJECT_MAPPER.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为指定类型的对象 + * + * @param text JSON格式的字符串 + * @param clazz 要转换的目标对象类型 + * @param 目标对象的泛型类型 + * @return 转换后的对象,如果字符串为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static T parseObject(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将字节数组转换为指定类型的对象 + * + * @param bytes 字节数组 + * @param clazz 要转换的目标对象类型 + * @param 目标对象的泛型类型 + * @return 转换后的对象,如果字节数组为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static T parseObject(byte[] bytes, Class clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(bytes, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为指定类型的对象,支持复杂类型 + * + * @param text JSON格式的字符串 + * @param typeReference 指定类型的TypeReference对象 + * @param 目标对象的泛型类型 + * @return 转换后的对象,如果字符串为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static T parseObject(String text, TypeReference typeReference) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为Dict对象 + * + * @param text JSON格式的字符串 + * @return 转换后的Dict对象,如果字符串为空或者不是JSON格式则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static Dict parseMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class)); + } catch (MismatchedInputException e) { + // 类型不匹配说明不是json + return null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为Dict对象的列表 + * + * @param text JSON格式的字符串 + * @return 转换后的Dict对象的列表,如果字符串为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static List parseArrayMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为指定类型对象的列表 + * + * @param text JSON格式的字符串 + * @param clazz 要转换的目标对象类型 + * @param 目标对象的泛型类型 + * @return 转换后的对象的列表,如果字符串为空则返回空列表 + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static List parseArray(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/agileboot-common/wol-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/agileboot-common/wol-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..9a60449 --- /dev/null +++ b/agileboot-common/wol-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.agileboot.common.json.config.JacksonConfig diff --git a/agileboot-common/wol-common-web/pom.xml b/agileboot-common/wol-common-web/pom.xml index c174a61..42836d1 100644 --- a/agileboot-common/wol-common-web/pom.xml +++ b/agileboot-common/wol-common-web/pom.xml @@ -13,6 +13,10 @@ com.agileboot wol-common-core + + com.agileboot + wol-common-json + org.springframework.boot spring-boot-starter-web