问题的场景是
当前端调用后端接口时,如果后台返回的ID值比较大(例如雪花算法生成的ID),在JavaScript中处理的时候会出现精度丢失的问题。为解决这个问题,可以将ID转化为字符串类型,也可以通过前端框架或组件库进行处理。
解决这个问题,有以下几种思路:
- 将后端返回的 ID 值转化为字符串类型。这是一个简单而且可行的方案,如果业务允许使用字符串类型的 ID。可以通过接口或者中间件等方式,将后端返回的长整型 ID 值转化为字符串类型,这样前端就可以安全处理这个 ID 了。
- 通过前端框架处理。可以使用一些前端框架,如 Vue、React 等,来处理这个问题。这些框架中通常会提供 BigNumber(高精度数)这样的类库,支持对于大整数的精确处理。
- 把 ID 值分段传输。可以将 ID 分为高低位表示,通过两个数字来传输 ID 值。这种方案需要后端和前端协同设计,不易于实现,但可以解决此问题。
- 通过前端组件库处理。一些优秀的前端组件库中,也可能会集成处理 Big Integer 类型的组件,例如 element-ui 中就有 support-big-number 组件用于处理超大数据的问题。
总之,解决此问题的方法有很多,具体选择哪一种方案要根据业务需求和当前技术栈来确定。
如果真的需要让后端解决,在不修改实体类数据类型的基础上,我们可以使用消息转换器来实现。
消息转换器是 Spring Framework 中常用的特性之一,用于实现请求和响应的自动转换。Spring Boot 默认使用了 Jackson 模块作为消息转换器,即通过使用 Jackson 库将请求和响应中的 JSON 数据自动转换为实体类对象,或将实体类对象转换为 JSON 数据。在这个场景下,我们可以自定义一个消息转换器,使用其将后端返回的 ID 值转化为字符串类型,然后再响应给前端。
自定义消息转换器代码示例
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(BigInteger.class, ToStringSerializer.instance)
.addSerializer(Long.class, ToStringSerializer.instance)
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
这段代码是一个 Spring MVC 的消息转换器配置。Spring MVC 中的消息转换器用于将不同的呈现形式(如 JSON、XML 等)的数据转换为 Java 对象和将 Java 对象转换为不同的呈现形式。在代码中,由于我们需要使用 JSON 数据格式进行数据交互,所以需要配置一个 JSON 数据转换器。
具体实现方式如下:
1、扩展 Spring MVC 的消息转换器。
2、创建一个 MappingJackson2HttpMessageConverter 对象。
3、设置 ObjectMapper 对象,使用 JacksonObjectMapper 实例作为对象转换器,即使用 Jackson 序列化库将 Java 对象转换为 JSON。
4、将该转换器对象追加到 Spring MVC 框架的消息转换器接口 List<HttpMessageConverter<?>> converters 集合的开头位置。
需要注意的是,这段代码中继承自 WebMvcConfigurationSupport 类,而不是继承自 WebMvcConfigurerAdapter 类。因为在 Spring Framework 5.0 版本之后,WebMvcConfigurerAdapter 已经被标记为过时,建议开发者继承 WebMvcConfigurationSupport 类来进行 Spring MVC 的配置。
代码示例
public class WebMvcConfig extends WebMvcConfigurationSupport {
/**
* @Description: 消息转换
* @Author: Mr.Lin
* @Date: 2023/6/4
*/
@Override
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
//创建消息转换器对象
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
//设置对象转换器,底层使用Jackson 将Java对象转为json
messageConverter.setObjectMapper(new JacksonObjectMapper());
//将上面的消息转换器对象追加到mvc框架的转换器集合中
converters.add(0,messageConverter);
}
}