由于公司数据库表的id是利用雪花算法生成的,所以实体类里面定义的数据类型为Long。但是这个数据传到前端时,发生了精度丢失的现象。本文记录了从java后端的角度如何解决这个精度丢失的问题,便于自己后续查阅。

一、问题的描述

    前端通过ajax请求后端接口,返回json数据,然后将数据渲染到一个表格中。突然发现表格中id这一列出现了精度丢失的现象,这精度丢失是由前端引起的。

二、问题的解决

(1)提出方案
    在后端代码中将Long类型改为String类型即可,但是由于采用的SpringMVC框架,可简单的做到统一处理。在输出到页面的Json转换器里面做统一处理,对象序列化成json时,将Long类型变成String类型就可以了。
(2)查询资料
    由于公司里面用的是FastJson的消息转换器,因此我们只需要扩展下FastJsonHttpMessageConverter这个类。
    由于我们需要在fastJson在将对象序列化成Json时做处理,因此先了解下FastJson的SerializeFilter接口。该接口有好多子接口,不同类型的子接口的作用是不同的,具体如下:
  1. SerializeFilter是通过编程扩展的方式定制序列化。fastjson支持6SerializeFilter,用于不同场景的定制序列化。具体如下:
  2. PropertyPreFilter 根据PropertyName判断是否序列化
  3. PropertyFilter 根据PropertyNamePropertyValue来判断是否序列化
  4. NameFilter 修改Key,如果需要修改Key,process返回值则可
  5. ValueFilter 修改Value
  6. BeforeFilter 序列化时在最前添加内容
  7. AfterFilter 序列化时在最后添加内容
  1. x
 
1
  1. SerializeFilter是通过编程扩展的方式定制序列化。fastjson支持6SerializeFilter,用于不同场景的定制序列化。具体如下:
2
  1.  
3
  1. PropertyPreFilter 根据PropertyName判断是否序列化
4
  1. PropertyFilter 根据PropertyNamePropertyValue来判断是否序列化
5
  1. NameFilter 修改Key,如果需要修改Key,process返回值则可
6
  1. ValueFilter 修改Value
7
  1. BeforeFilter 序列化时在最前添加内容
8
  1. AfterFilter 序列化时在最后添加内容
(3)实战代码
    • <1>自定义序列化Filter
    由于我们需要在对象序列化成json的阶段,把Long类型的Value变成String类型,因此先写一个ValueFilter的实现类。在这实现类里面,我们把数据类型为Long的数据的Value给修改成String类型。具体代码如下:
  1. package com.kangxiinfo.wechat.common.fastjson;
  2. import com.alibaba.fastjson.serializer.ValueFilter;
  3. /**
  4. * Long类型变成String类型——json序列化Filter
  5. * @author ZENG.XIAO.YAN
  6. * @time 2018-11-08 14:50:19
  7. * @version v1.0
  8. */
  9. public class LongToStringSerializeFilter implements ValueFilter {
  10. @Override
  11. public Object process(Object object, String name, Object value) {
  12. if (value != null) {
  13. // 当value不为null时,如果value是Long类型的就改成String
  14. if (value instanceof Long) {
  15. return value.toString();
  16. }
  17. }
  18. return value;
  19. }
  20. }
 
1
  1. package com.kangxiinfo.wechat.common.fastjson;
2
  1. import com.alibaba.fastjson.serializer.ValueFilter;
3
  1.  
4
  1. /**
5
  1. * Long类型变成String类型——json序列化Filter
6
  1. * @author ZENG.XIAO.YAN
7
  1. * @time   2018-11-08 14:50:19
8
  1. * @version v1.0
9
  1. */
10
  1. public class LongToStringSerializeFilter implements ValueFilter {
11
  1.  
12
  1. @Override
13
  1. public Object process(Object object, String name, Object value) {
14
  1. if (value != null) {
15
  1. // 当value不为null时,如果value是Long类型的就改成String
16
  1. if (value instanceof Long) {
17
  1. return value.toString();
18
  1. }
19
  1. }
20
  1. return value;
21
  1. }
22
23
  1. }

    • <2>自定义JsonHttpMessageConverter
    直接继承FastJsonHttpMessageConverter这个类,然后重写writeInternal这个方法。在writeInternal方法里面进行对象序列成json串时,传入我们上面自定义的序列化Filter。具体代码如下:
  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. public class CustomFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {
  11. public final static Charset UTF8 = Charset.forName("UTF-8");
  12. private Charset charset = UTF8;
  13. private SerializerFeature[] features = new SerializerFeature[0];
  14. /** 自定义的filter */
  15. private LongToStringSerializeFilter longToStringSerializeFilter = new LongToStringSerializeFilter();
  16. public CustomFastJsonHttpMessageConverter() {
  17. super();
  18. }
  19. @Override
  20. protected boolean supports(Class<?> clazz) {
  21. return true;
  22. }
  23. public Charset getCharset() {
  24. return this.charset;
  25. }
  26. public void setCharset(Charset charset) {
  27. this.charset = charset;
  28. }
  29. public SerializerFeature[] getFeatures() {
  30. return features;
  31. }
  32. public void setFeatures(SerializerFeature... features) {
  33. this.features = features;
  34. }
  35. // 重写这个方法
  36. @Override
  37. protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
  38. throws IOException, HttpMessageNotWritableException {
  39. OutputStream out = outputMessage.getBody();
  40. // 转json时 加入自定义的Filter
  41. String text = JSON.toJSONString(obj, longToStringSerializeFilter, features);
  42. byte[] bytes = text.getBytes(charset);
  43. out.write(bytes);
  44. }
  45. }
 
1
  1. package com.kangxiinfo.wechat.common.fastjson;
2
  1. import java.io.IOException;
3
  1. import java.io.OutputStream;
4
  1. import java.nio.charset.Charset;
5
  1. import org.springframework.http.HttpOutputMessage;
6
  1. import org.springframework.http.converter.HttpMessageNotWritableException;
7
  1. import com.alibaba.fastjson.JSON;
8
  1. import com.alibaba.fastjson.serializer.SerializerFeature;
9
  1. import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
10
  1.  
11
  1. public class CustomFastJsonHttpMessageConverter extends FastJsonHttpMessageConverter {
12
  1. public final static Charset UTF8 = Charset.forName("UTF-8");
13
  1. private Charset charset = UTF8;
14
  1. private SerializerFeature[] features = new SerializerFeature[0];
15
  1. /** 自定义的filter */
16
  1. private LongToStringSerializeFilter longToStringSerializeFilter = new LongToStringSerializeFilter();
17
  1.  
18
  1. public CustomFastJsonHttpMessageConverter() {
19
  1. super();
20
  1. }
21
  1.  
22
  1. @Override
23
  1. protected boolean supports(Class<?> clazz) {
24
  1. return true;
25
  1. }
26
  1.  
27
  1. public Charset getCharset() {
28
  1. return this.charset;
29
  1. }
30
  1.  
31
  1. public void setCharset(Charset charset) {
32
  1. this.charset = charset;
33
  1. }
34
  1.  
35
  1. public SerializerFeature[] getFeatures() {
36
  1. return features;
37
  1. }
38
  1.  
39
  1. public void setFeatures(SerializerFeature... features) {
40
  1. this.features = features;
41
  1. }
42
  1.  
43
44
  1. // 重写这个方法
45
  1. @Override
46
  1. protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
47
  1. throws IOException, HttpMessageNotWritableException {
48
  1. OutputStream out = outputMessage.getBody();
49
  1. // 转json时 加入自定义的Filter
50
  1. String text = JSON.toJSONString(obj, longToStringSerializeFilter, features);
51
  1. byte[] bytes = text.getBytes(charset);
52
  1. out.write(bytes);
53
  1. }
54
  1. }
55
  1.  
    • <3>在SpringMVC配置文件中配置使用我们自定义的Json转换器
    配置的具体代码如下:
  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
  1.     <mvc:annotation-driven>
2
  1.        <mvc:message-converters register-defaults="false">
3
  1.       <!-- 注册我们扩展了的fastjson转换器 -->
4
  1.            <bean class="com.kangxiinfo.wechat.common.fastjson.CustomFastJsonHttpMessageConverter">
5
  1.                <property name="supportedMediaTypes">
6
  1.                    <list>
7
  1.                        <value>text/html;charset=UTF-8</value>
8
  1.                        <value>application/json;charset=UTF-8</value>
9
  1.                        <value>text/plain;charset=UTF-8</value>
10
  1.                        <value>application/x-www-form-urlencoded;charset=UTF-8</value>                        
11
  1.                    </list>
12
  1.                </property>
13
  1.                <property name="features">
14
  1.                    <list>
15
  1.                        <value>WriteMapNullValue</value>
16
  1.                        <value>WriteNullListAsEmpty</value>
17
  1.                        <value>WriteNullStringAsEmpty</value>
18
  1.                        <value>WriteNullNumberAsZero</value>
19
  1.                    </list>
20
  1.                </property>
21
  1.            </bean>
22
  1.        </mvc:message-converters>
23
  1.    </mvc:annotation-driven>

三、小结

(1)Long类型数据传到前端精度丢失时,可以将Long类型转成String类型再输出到前端就不会丢失精度
(2)可以通过扩展SpringMVC的消息转换器,全局处理这种Long类型数据精度丢失的问题

Long类型参数传到前端精度丢失的解决方案的更多相关文章

  1. 后端Long类型传到前端精度丢失的正确解决方式

    原因:前端js对Long类型支持的精度不够,导致后端使用的Long传到前端丢失精度,比如现在分布式id生成算法"雪花算法"在使用中就会出现问题. 解决方式: 1.后端的Long类型 ...

  2. 计算价格, java中浮点数精度丢失的解决方案

    计算价格, java中浮点数精度丢失的解决方案

  3. Spring MVC自定义消息转换器(可解决Long类型数据传入前端精度丢失的问题)

    1.前言 对于Long 类型的数据,如果我们在Controller层通过@ResponseBody将返回数据自动转换成json时,不做任何处理,而直接传给前端的话,在Long长度大于17位时会出现精度 ...

  4. Long类型数据前端精度丢失

    问题描述 后端把Long类型的数据传给前端,前端可能会出现精度丢失的情况.例如:201511200001725439这样一个Long类型的整数,传给前端后会变成201511200001725440 相 ...

  5. .Net Core 配置之long类型 前端精度丢失和时间格式设置

    在很多项目中,都采用的前后端分离的方式进行开发,经常遇到后台的long精度的数据到前端丢失不准确,显示效果为long类型(19位)的后几位为000,此时需要对long的字段进行设置,改变默认的返回类型 ...

  6. springboot中关于Long类型返回前端精度丢失问题处理

    使用了HuTool这个雪花算法后,会出现丢失精度的问题 hutool算法使用地址 对于一些大的业务表,自增主键这里 接口层得注意下是否会产生大数值 设计接口的时候采用String类型. 在项目中,我们 ...

  7. javascript(js)小数精度丢失的解决方案

    原因:js按照2进制来处理小数的加减乘除,在arg1的基础上 将arg2的精度进行扩展或逆扩展匹配,所以会出现如下情况. javascript(js)的小数点加减乘除问题,是一个js的bug如0.3* ...

  8. 后端传Long类型至前端js会出现精度丢失问题

    今天开发遇到个问题,Java后端的Long类型数据,传到前端会出现精度丢失,如:164379764419858435,前端会变成164379764419858430.在浏览器中做测试可知,这就是一个精 ...

  9. 后端传给前端Long类型数据,导致精度丢失

    1.前几天遇到了一个问题,后端向前端传递一个Long类型的数据,前端拿到的值不对. 2.当Long类型的数据大于17位时候,就会出现精度丢失的情况. 3.解决办法 我们采用的解决方案是将后端的Long ...

随机推荐

  1. Android udp json+数组 --->bytes发送数据

    Android  json支持五种数据类型 String / int(float)/bool / null  / object 今天说 object  : json = new JSONObject( ...

  2. CSS回顾(常见问题解决)

    一.margin的塌陷解决: BFC (block format context)块级格式化上下文格式 display:inline-block float:left / right overflow ...

  3. Docker Data Center系列(三)- DTR安装指南

    本系列文章演示如何搭建一个mini的云平台和DevOps实践环境. 基于这套实践环境,可以部署微服务架构的应用栈,演练提升DevOps实践能力. 1 系统要求 1.1 硬件和软件要求 成为UCP管理的 ...

  4. Mac上一条命令搭建web服务器

    实际测试工作中偶尔会需要搭建Web服务器环境,由于Mac OS X自带了Apache和PHP环境,只需要简单的启动就可以. 开启Apache 开启Web服务器的方法有两种(默认启动端口号是80): 打 ...

  5. 网站流量统计PV&UV

    统计网站pv和uv PV是网站分析的一个术语,用以衡量网站用户访问的网页的数量. 对于广告主,PV值可预期它可以带来多少广告收入.一般来说,PV与来访者的数量成正比,但是PV并不直接决定页面的真实来访 ...

  6. ssh-keygen的学习总结

    ssh-keygen介绍   维基百科上关于ssh-keygen的介绍如下:     ssh-keygen is a standard component of the Secure Shell (S ...

  7. C#-构造函数中base

    base 是调用基类的有参数构造函数  因为在子类不能直接继承父类的构造函数   实例 using System; using System.Collections.Generic; using Sy ...

  8. web前端(7)—— 了解CSS样式,引入css样式的方式

    CSS 在前面大概的介绍了css,从本片博文开始,会详细的介绍它,在最开始介绍web前端时,打开百度首页,当时我提出了一个问题,为什么百度首页的输入框可以放在正中间,就是由于有css的控制,我们可以打 ...

  9. Java线程相关的热门面试题

    ---恢复内容开始--- 下面是Java线程相关的热门面试题,你可以用它来好好准备面试. 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序 ...

  10. 联想x3650m5服务器安装windows2008R2系统

    服务器型号:联想x3650 M5 2U服务器 硬盘:一块300G硬盘 阵列:raid0 系统:windowsserver2008R2系统 安装开始时间:20180930晚上9点 客户手里有window ...