背景
在项目中使用雪花Id作为主键Id使用,前端返回查询数据时在展示时出现精度丢失,如原Id为1797913405167583236
进度丢失后为1797913405167583000
解决方案(前后端)
前端方案
前端解决精度问题很简单,通过字符串接收,即可避免精度丢失问题。
以ts
代码为例:
// 原
type Demo {
id:number;
...
}
// 改后
type Demo {
id : string;
...
}
后端方案
后端以Spring Boot
项目为例,在前后端约定好使用字符串接收Long
类型数据后:
- 在Spring Boot默认使用
Jackson
web的序列化器时,配置Long类型序列化时序列化为String类型。参考代码如下:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.text.SimpleDateFormat;
/**
* @author 十八
* @createDate 2024-05-15 02:41
*/
@Configuration
public class JacksonConfig {
/**
* 创建Jackson对象映射器
*
* @param builder Jackson对象映射器构建器
* @return ObjectMapper
*/
@Bean
public ObjectMapper getJacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = new ObjectMapper()
// Long类型数据序列化为String
SimpleModule longToString = new SimpleModule();
longToString.addSerializer(Long.class, new ToStringSerializer());
longToString.addSerializer(Long.TYPE, new ToStringSerializer());
longToString.addDeserializer(Long.class, new CustomLongDeserializer());
objectMapper.registerModule(longToString);
return objectMapper;
}
}
- 默认情况下,Long类型数据不支持从字符串直接序列化为Long类型,此时需要定义一个Long的反序列化器。参考代码如下:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
/**
* @author 十八
* @description 自定义Long反序列化器
* @createDate 2024-06-01 23:37
*/
public class CustomLongDeserializer extends JsonDeserializer<Long> {
@Override
public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String value = p.getText();
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
return null; // 或者返回一个默认值
}
}
}
此时,前后端的Long类型数据处理就已经完成,方案算不上最优解,但是在前后端约定好的情况下,能避免大部分数据精度丢失问题。