feat(jackson): 添加大数字序列化处理避免前端精度丢失

- 新增大数字序列化器 BigNumberSerializer 处理超出 JS 安全整数范围的 Long/BigInteger
- 配置 Jackson 全局设置将超长数字自动转换为字符串格式
- 添加 BigDecimal 直接序列化为字符串确保精度完整
- 统一 LocalDateTime 时间格式化为 yyyy-MM-dd HH:mm:ss 格式
This commit is contained in:
2026-06-08 13:19:19 +08:00
parent 0b02122015
commit 7899b31c08
2 changed files with 94 additions and 0 deletions

View File

@@ -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 全局配置
* <p>
* 支持 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());
};
}
}

View File

@@ -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());
}
}
}