zoukankan      html  css  js  c++  java
  • 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 修改Value
    7
    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序列化Filter
    6
     * @author ZENG.XIAO.YAN
    7
     * @time   2018-11-08 14:50:19
    8
     * @version  v1.0
    9
     */
    10
    public class LongToStringSerializeFilter implements ValueFilter {
    11
    12
        @Override
    13
        public Object process(Object object, String name, Object value) {
    14
            if (value != null) {
    15
                // 当value不为null时,如果value是Long类型的就改成String
    16
                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
        @Override
    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
        @Override
    46
        protected void writeInternal(Object obj, HttpOutputMessage outputMessage)
    47
                throws IOException, HttpMessageNotWritableException {
    48
            OutputStream out = outputMessage.getBody();
    49
            // 转json时 加入自定义的Filter
    50
            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类型数据精度丢失的问题
  • 相关阅读:
    Java 7的javax.net.ssl.SSLHandshakeException
    Oracle数据泵导出数据库
    ORA-00054: 资源正忙 --锁表的解决方法
    Linux学习私人笔记-Shell基础
    Linux学习私人笔记-目录和文件的基本命令
    Linux学习私人笔记-文件基本命令
    Linux学习私人笔记-账号管理
    Linux学习私人笔记-Vim
    form提交表单时本地下载
    SQL Servel 中分页解决
  • 原文地址:https://www.cnblogs.com/zeng1994/p/7ea79563e5be10eb132f18dc1961944d.html
Copyright © 2011-2022 走看看