feat(jackson): 添加大数字序列化处理避免前端精度丢失
- 新增大数字序列化器 BigNumberSerializer 处理超出 JS 安全整数范围的 Long/BigInteger - 配置 Jackson 全局设置将超长数字自动转换为字符串格式 - 添加 BigDecimal 直接序列化为字符串确保精度完整 - 统一 LocalDateTime 时间格式化为 yyyy-MM-dd HH:mm:ss 格式
This commit is contained in:
@@ -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());
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user