logo头像

不忘初心 方得始终

Javascript Number类型长度溢出

引言

项目中遇到一个问题,由于后台数据库表ID使用分布式唯一算法生成的Long类型(19位数字),导致转成json传至前端js使用时报错,因为js的数字类型最大只能表示15位数字长度【JavaScript Number 对象】。

解决方案:使用Spring自定义Json序列化方式,将过长的Long类型转成String类型。

默认序列化配置

默认序列化方式会将Long类型不做转换,直接传递给前端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg ref="utf8charset"/>
<property name="writeAcceptCharset" value="false"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="serializationInclusion">
<value type="com.fasterxml.jackson.annotation.JsonInclude.Include">NON_NULL</value>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>

自定义序列化方式

现在需要将Long类型数字达到一定长度才转为String类型传递给前端。实现方式有两种:

局部配置某个字段序列化

实现抽象接口JsonSerializer自定义序列化类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CustomLongConverter extends JsonSerializer<Long> {

/**
* 超过多少位转换为Long类型
*/
private static final int THRESHOLD_LENGTH = 15;

@Override
public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
if (value.toString().length() > THRESHOLD_LENGTH) {
gen.writeString(value.toString());
} else {
gen.writeNumber(value);
}
}
}

@JsonSerialize(using = CustomLongConverter.class)注解到指定字段上

1
2
@JsonSerialize(using = CustomLongConverter.class)
private Long id;

全局配置序注册自定义的序列化类

自定义Long类型序列化

继承自StdSerializer类的一个自定义序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CustomLongConverter extends StdSerializer<Long> {

/**
* 超过多少位转换为Long类型
*/
private static final int THRESHOLD_LENGTH = 15;

private static final long serialVersionUID = -4532126689403959662L;

CustomLongConverter() {
super(Long.class);
}

@Override
public void serialize(Long value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value.toString().length() >= THRESHOLD_LENGTH) {
gen.writeString(value.toString());
} else {
gen.writeNumber(value);
}
}
}

需要注册到ObjectMapper中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ObjectMapperConverter extends ObjectMapper {

private static final long serialVersionUID = 5383113523976711806L;

public ObjectMapperConverter() {
super();
// 不包含为空的字段
setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 不包含空字符串字段
setSerializationInclusion(JsonInclude.Include.NON_EMPTY);

SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, new CustomLongConverter());
simpleModule.addSerializer(Long.TYPE, new CustomLongConverter());
registerModule(simpleModule);
}
}

xml中配置注册方式

SpringMVC配置中需要指定为自定义序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg ref="utf8charset"/>
<property name="writeAcceptCharset" value="false"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.rainbowhorse.consult.web.util.ObjectMapperConverter"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
微信打赏

赞赏是不耍流氓的鼓励