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 序列化時在最后添加內容
(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;
	}
	
}

    • <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);
	}
}
    • <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)Long類型數據傳到前端精度丟失時,可以將Long類型轉成String類型再輸出到前端就不會丟失精度
(2)可以通過擴展SpringMVC的消息轉換器,全局處理這種Long類型數據精度丟失的問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM