Long类型参数传到前端精度丢失的解决方案
由于公司数据库表的id是利用雪花算法生成的,所以实体类里面定义的数据类型为Long。但是这个数据传到前端时,发生了精度丢失的现象。本文记录了从java后端的角度如何解决这个精度丢失的问题,便于自己后续查阅。
一、问题的描述
前端通过ajax请求后端接口,返回json数据,然后将数据渲染到一个表格中。突然发现表格中id这一列出现了精度丢失的现象,这精度丢失是由前端引起的。
二、问题的解决
(1)提出方案
在后端代码中将Long类型改为String类型即可,但是由于采用的SpringMVC框架,可简单的做到统一处理。在输出到页面的Json转换器里面做统一处理,对象序列化成json时,将Long类型变成String类型就可以了。
(2)查询资料
由于公司里面用的是FastJson的消息转换器,因此我们只需要扩展下FastJsonHttpMessageConverter这个类。
由于我们需要在fastJson在将对象序列化成Json时做处理,因此先了解下FastJson的SerializeFilter接口。该接口有好多子接口,不同类型的子接口的作用是不同的,具体如下:
SerializeFilter是通过编程扩展的方式定制序列化。fastjson支持6种SerializeFilter,用于不同场景的定制序列化。具体如下:
PropertyPreFilter 根据PropertyName判断是否序列化
PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
NameFilter 修改Key,如果需要修改Key,process返回值则可
ValueFilter 修改Value
BeforeFilter 序列化时在最前添加内容
AfterFilter 序列化时在最后添加内容x
1
SerializeFilter是通过编程扩展的方式定制序列化。fastjson支持6种SerializeFilter,用于不同场景的定制序列化。具体如下:2
3
PropertyPreFilter 根据PropertyName判断是否序列化4
PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化5
NameFilter 修改Key,如果需要修改Key,process返回值则可6
ValueFilter 修改Value7
BeforeFilter 序列化时在最前添加内容8
AfterFilter 序列化时在最后添加内容(3)实战代码
- <1>自定义序列化Filter
由于我们需要在对象序列化成json的阶段,把Long类型的Value变成String类型,因此先写一个ValueFilter的实现类。在这实现类里面,我们把数据类型为Long的数据的Value给修改成String类型。具体代码如下:
package com.kangxiinfo.wechat.common.fastjson;
import com.alibaba.fastjson.serializer.ValueFilter;
/**
* Long类型变成String类型——json序列化Filter
* @author ZENG.XIAO.YAN
* @time 2018-11-08 14:50:19
* @version v1.0
*/
public class LongToStringSerializeFilter implements ValueFilter {
@Override
public Object process(Object object, String name, Object value) {
if (value != null) {
// 当value不为null时,如果value是Long类型的就改成String
if (value instanceof Long) {
return value.toString();
}
}
return value;
}
}1
package com.kangxiinfo.wechat.common.fastjson;2
import com.alibaba.fastjson.serializer.ValueFilter;3
4
/**5
* Long类型变成String类型——json序列化Filter6
* @author ZENG.XIAO.YAN7
* @time 2018-11-08 14:50:198
* @version v1.09
*/10
public class LongToStringSerializeFilter implements ValueFilter {11
12
13
public Object process(Object object, String name, Object value) {14
if (value != null) {15
// 当value不为null时,如果value是Long类型的就改成String16
if (value instanceof Long) {17
return value.toString();18
}19
}20
return value;21
}22
23
}- <2>自定义JsonHttpMessageConverter
直接继承FastJsonHttpMessageConverter这个类,然后重写writeInternal这个方法。在writeInternal方法里面进行对象序列成json串时,传入我们上面自定义的序列化Filter。具体代码如下:
package com.kangxiinfo.wechat.common.fastjson;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
public class CustomFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {
public final static Charset UTF8 = Charset.forName("UTF-8");
private Charset charset = UTF8;
private SerializerFeature[] features = new SerializerFeature[0];
/** 自定义的filter */
private LongToStringSerializeFilter longToStringSerializeFilter = new LongToStringSerializeFilter();
public CustomFastJsonHttpMessageConverter() {
super();
}
@Override
protected boolean supports(Class<?> clazz) {
return true;
}
public Charset getCharset() {
return this.charset;
}
public void setCharset(Charset charset) {
this.charset = charset;
}
public SerializerFeature[] getFeatures() {
return features;
}
public void setFeatures(SerializerFeature... features) {
this.features = features;
}
// 重写这个方法
@Override
protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
OutputStream out = outputMessage.getBody();
// 转json时 加入自定义的Filter
String text = JSON.toJSONString(obj, longToStringSerializeFilter, features);
byte[] bytes = text.getBytes(charset);
out.write(bytes);
}
}
1
package com.kangxiinfo.wechat.common.fastjson;2
import java.io.IOException;3
import java.io.OutputStream;4
import java.nio.charset.Charset;5
import org.springframework.http.HttpOutputMessage;6
import org.springframework.http.converter.HttpMessageNotWritableException;7
import com.alibaba.fastjson.JSON;8
import com.alibaba.fastjson.serializer.SerializerFeature;9
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;10
11
public class CustomFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {12
public final static Charset UTF8 = Charset.forName("UTF-8");13
private Charset charset = UTF8;14
private SerializerFeature[] features = new SerializerFeature[0];15
/** 自定义的filter */16
private LongToStringSerializeFilter longToStringSerializeFilter = new LongToStringSerializeFilter();17
18
public CustomFastJsonHttpMessageConverter() {19
super();20
}21
22
23
protected boolean supports(Class<?> clazz) {24
return true;25
}26
27
public Charset getCharset() {28
return this.charset;29
}30
31
public void setCharset(Charset charset) {32
this.charset = charset;33
}34
35
public SerializerFeature[] getFeatures() {36
return features;37
}38
39
public void setFeatures(SerializerFeature... features) {40
this.features = features;41
}42
43
44
// 重写这个方法45
46
protected void writeInternal(Object obj, HttpOutputMessage outputMessage)47
throws IOException, HttpMessageNotWritableException {48
OutputStream out = outputMessage.getBody();49
// 转json时 加入自定义的Filter50
String text = JSON.toJSONString(obj, longToStringSerializeFilter, features);51
byte[] bytes = text.getBytes(charset);52
out.write(bytes);53
}54
}55
- <3>在SpringMVC配置文件中配置使用我们自定义的Json转换器
配置的具体代码如下:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<!-- 注册我们扩展了的fastjson转换器 -->
<bean class="com.kangxiinfo.wechat.common.fastjson.CustomFastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
<value>text/plain;charset=UTF-8</value>
<value>application/x-www-form-urlencoded;charset=UTF-8</value>
</list>
</property>
<property name="features">
<list>
<value>WriteMapNullValue</value>
<value>WriteNullListAsEmpty</value>
<value>WriteNullStringAsEmpty</value>
<value>WriteNullNumberAsZero</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>1
<mvc:annotation-driven>2
<mvc:message-converters register-defaults="false">3
<!-- 注册我们扩展了的fastjson转换器 -->4
<bean class="com.kangxiinfo.wechat.common.fastjson.CustomFastJsonHttpMessageConverter">5
<property name="supportedMediaTypes">6
<list>7
<value>text/html;charset=UTF-8</value>8
<value>application/json;charset=UTF-8</value>9
<value>text/plain;charset=UTF-8</value>10
<value>application/x-www-form-urlencoded;charset=UTF-8</value> 11
</list>12
</property>13
<property name="features">14
<list>15
<value>WriteMapNullValue</value>16
<value>WriteNullListAsEmpty</value>17
<value>WriteNullStringAsEmpty</value>18
<value>WriteNullNumberAsZero</value>19
</list>20
</property>21
</bean>22
</mvc:message-converters>23
</mvc:annotation-driven>三、小结
(1)Long类型数据传到前端精度丢失时,可以将Long类型转成String类型再输出到前端就不会丢失精度(2)可以通过扩展SpringMVC的消息转换器,全局处理这种Long类型数据精度丢失的问题
作者:zeng1994
出处:http://www.cnblogs.com/zeng1994/
本文版权归作者和博客园共有,欢迎转载!但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接!

浙公网安备 33010602011771号