diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java new file mode 100644 index 00000000..d3457612 --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/JacksonConfig.java @@ -0,0 +1,49 @@ +package com.ruoyi.framework.config; + +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.ruoyi.framework.jackson.BigNumberSerializer; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.TimeZone; + +/** + * jackson 全局配置 + *
+ * 支持 Long/BigInteger 超出 JS 安全整数范围时自动转为字符串, + * 避免前端精度丢失。 + * + * @author Lion Li + */ +@Configuration +public class JacksonConfig { + + @Bean + public Jackson2ObjectMapperBuilderCustomizer customizer() { + return builder -> { + // 全局配置序列化返回 JSON 处理 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + // Long 类型:超出 JS 安全范围时序列化为字符串 + javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE); + // BigInteger 类型:超出 JS 安全范围时序列化为字符串 + javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE); + // BigDecimal 类型:直接序列化为字符串(精度原因) + javaTimeModule.addSerializer(BigDecimal.class, com.fasterxml.jackson.databind.ser.std.ToStringSerializer.instance); + // LocalDateTime 统一格式化 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + builder.modules(javaTimeModule); + builder.timeZone(TimeZone.getDefault()); + }; + } + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java new file mode 100644 index 00000000..ad40c644 --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/jackson/BigNumberSerializer.java @@ -0,0 +1,45 @@ +package com.ruoyi.framework.jackson; + +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 最大最小值 处理 + * 将超出 Number.MAX_SAFE_INTEGER 范围的 Long/BigInteger 序列化为字符串, + * 避免前端 JavaScript 精度丢失。 + * + * @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 extends Number> rawType) { + super(rawType); + } + + @Override + public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { + // 在 JS 安全整数范围内 → 正常序列化为 Number + if (value.longValue() >= MIN_SAFE_INTEGER && value.longValue() <= MAX_SAFE_INTEGER) { + super.serialize(value, gen, provider); + } else { + // 超出范围 → 序列化为字符串,前端不会丢精度 + gen.writeString(value.toString()); + } + } +}