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