亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

springboot?Long?精度丟失問題解決

 更新時間:2022年07月06日 09:12:21   作者:smileluck  
這篇文章主要為大家介紹了解決springboot?Long?精度丟失問題的方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

最近在開發(fā)中,碰到一個問題,關(guān)于數(shù)據(jù)庫Long類型查詢后,返回給前端后,精度丟失。

297874820157145088 => 297874820157145100

后端源碼地址

前端源碼地址

數(shù)據(jù)庫數(shù)據(jù)如下:

id字典碼字典名稱備注
297874820157145088enableFlag啟用狀態(tài)0未啟用,1啟用

查詢語句如下:

SELECT id AS id, dict_code AS dictCode, dict_name AS dictName, remark AS remark, create_time AS createTime, create_by AS createBy, update_time AS updateTime, update_by AS updateBy, del_flag AS delFlag FROM sys_dict WHERE (del_flag=0) LIMIT 10 OFFSET 0

查詢結(jié)果:(正確,此時并未出現(xiàn)精度丟失)

id字典碼字典名稱備注
297874820157145088enableFlag啟用狀態(tài)0未啟用,1啟用

再來看一下Springboot準(zhǔn)備返回時的數(shù)據(jù)顯示:

這里可以看到返回類型是Long類型且精度并未丟失。

可以看到這時前端顯示出來的,就出現(xiàn)問題了。是不是網(wǎng)絡(luò)傳輸?shù)倪^程有問題呢?我們換PostMan試一下。

可以看見這里的id是正確的,那么應(yīng)該時JavaScript導(dǎo)致的精度丟失了。

大致看了一下網(wǎng)上的思路,因?yàn)镴avaScript 的整數(shù)類型范圍有限,精度為17位 ,當(dāng)接口返回的Long類型過長時,javaScript會進(jìn)行截斷,所以解決辦法就是把Long類型轉(zhuǎn)換成String類型返回,這樣就不會由精度丟失的問題了。

解決方法

基于注解@JsonSerialize(不推薦)

最直接的方式就是在需要轉(zhuǎn)換的Long類型字段使用注解標(biāo)記。

@JsonSerialize
private Long id;

這樣子好處是可以對單個的字段進(jìn)行精細(xì)管理,但是需要每個字段都添加轉(zhuǎn)換,很不方便,工作量大。

基于jackson全局配置(不推薦)

spring:
	jackson:
		generator:
			write-numbers-as-strings: true

這個方法會將全局所有的數(shù)字類型包括int/long等都轉(zhuǎn)換為string類型返回,不推薦使用。

使用JsonComponent 序列化配置

@JsonComponent
public class JsonConfig {
    /**
     * 添加Long轉(zhuǎn)json精度丟失的配置
     */
    @Bean
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        SimpleModule module = new SimpleModule();
        module.addSerializer(Long.class, ToStringSerializer.instance);
        module.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(module);
        return objectMapper;
    }
}

為什么這樣寫能生效呢?我們可以看一下 WebMvcConfigurationSupport 類。

WebMvcConfigurationSupport 分析

//初始化
static {
   // etc...
    jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
}
// 添加默認(rèn)的httpMesssage轉(zhuǎn)換器
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
    //etc
    if (jackson2Present) {
        builder = Jackson2ObjectMapperBuilder.json();
        if (this.applicationContext != null) {
            builder.applicationContext(this.applicationContext);
        }
        messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    }
}       

這里可以看出來Springboot提供的默認(rèn)mvc配置內(nèi)容:

  • 初始化并查找是否有 ObjectMapper 類
  • 如果沒有發(fā)現(xiàn) ObjectMapper Bean對象,就會提供給一個默認(rèn)的 MappingJackson2HttpMessageConverter 對象。
  • 如果發(fā)現(xiàn) ObjectMapper Bean對象,就會將這個綁定到默認(rèn)的轉(zhuǎn)換器上。

WebMvcConfigurer/WebMvcConfigurationSupport

這里雖然將這兩個類放一起,是因?yàn)槎寄芑谒麄內(nèi)ブ貙?configureMessageConverters方法,來實(shí)現(xiàn)對轉(zhuǎn)換器的添加。

@Configuration
public class WebConfig implements WebMvcConfigurer {
    /**
     * 添加Long轉(zhuǎn)json精度丟失的配置
     *
     * @Return: void
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(jackson2HttpMessageConverter);
    }
}

這里需要注意的是,該方法可能存在失效的情況,但是如果我們改成這樣,就能有效。

converters.add(0,jackson2HttpMessageConverter);

這是為什么呢?讓我們探究一下。

分析

先看一下都有什么轉(zhuǎn)換器。

可以看到在我們添加轉(zhuǎn)換器前,就已經(jīng)有了2個 Mappingjackson2HttpMessageConverter 了。我們說過springboot 自帶了 HttpMessageConverter 。

那么這時出現(xiàn)多個,會不會相互之間有影響?

// AbstractMessageConverterMethodProcessor.class
if (selectedMediaType != null) {
    selectedMediaType = selectedMediaType.removeQualityValue();
    for (HttpMessageConverter<?> converter : this.messageConverters) {
        GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
                                                        (GenericHttpMessageConverter<?>) converter : null);
        if (genericConverter != null ?
            ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
            converter.canWrite(valueType, selectedMediaType)) {
            body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
                                               (Class<? extends HttpMessageConverter<?>>) converter.getClass(),
                                               inputMessage, outputMessage);
            if (body != null) {
                Object theBody = body;
                LogFormatUtils.traceDebug(logger, traceOn ->
                                          "Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
                addContentDispositionHeader(inputMessage, outputMessage);
                if (genericConverter != null) {
                    genericConverter.write(body, targetType, selectedMediaType, outputMessage);
                }
                else {
                    ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
                }
            }
            else {
                if (logger.isDebugEnabled()) {
                    logger.debug("Nothing to write: null body");
                }
            }
            return;
        }
    }
}
// AbstractMessageConverterMethodArgumentResolver.class
for (HttpMessageConverter<?> converter : this.messageConverters) {
    Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
    GenericHttpMessageConverter<?> genericConverter =
        (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
    if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
        (targetClass != null && converter.canRead(targetClass, contentType))) {
        if (message.hasBody()) {
            HttpInputMessage msgToUse =
                getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
            body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
                    ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
            body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
        }
        else {
            body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
        }
        break;
    }
}

這里可以看到,會遍歷messageConverters轉(zhuǎn)換器列表,但是問題在于,如果有一個 HttpMessageConverter 類響應(yīng)了讀寫信息,那么就會進(jìn)行返回,這樣導(dǎo)致了后面的轉(zhuǎn)換器不生效。

解決方法

那么針對這種有幾種解決方法

  • 提升自定義的消息處理轉(zhuǎn)換器優(yōu)先級;
converters.add(0,jackson2HttpMessageConverter);
  • 移除列表里的springboot 默認(rèn)的轉(zhuǎn)換器;
converters.removeIf(converter -> converter instanceof MappingJackson2HttpMessageConverter);
  • 使用@EnableWebMvc 注解。慎用,會清空sprinb自帶的默認(rèn)轉(zhuǎn)換器導(dǎo)致某些功能失效。此時的converters轉(zhuǎn)換列表為空。
@EnableWebMvc
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(jackson2HttpMessageConverter);
    }
}

以上就是springboot Long 精度丟失問題解決的詳細(xì)內(nèi)容,更多關(guān)于springboot Long 精度丟失的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java如何比較兩個任意文件是否相同

    Java如何比較兩個任意文件是否相同

    這篇文章主要為大家詳細(xì)介紹了Java如何實(shí)現(xiàn)比較兩個任意文件是否相同,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-04-04
  • Java解析Excel內(nèi)容的方法

    Java解析Excel內(nèi)容的方法

    這篇文章主要介紹了Java解析Excel內(nèi)容的方法,實(shí)例分析了java解析excel文件的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-03-03
  • SpringBoot 日志的配置及輸出應(yīng)用教程

    SpringBoot 日志的配置及輸出應(yīng)用教程

    Spring Boot 默認(rèn)使用 SLF4J+Logback 記錄日志,并提供了默認(rèn)配置。本文我們將重點(diǎn)介紹Spring Boot日志的配置及輸出。感興趣的小伙伴可以了解一下
    2021-12-12
  • 如何解決UnsupportedOperationException異常問題

    如何解決UnsupportedOperationException異常問題

    這篇文章主要介紹了如何解決UnsupportedOperationException異常問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Java for循環(huán)性能優(yōu)化實(shí)現(xiàn)解析

    Java for循環(huán)性能優(yōu)化實(shí)現(xiàn)解析

    這篇文章主要介紹了Java for循環(huán)性能優(yōu)化實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-01-01
  • Java并發(fā)系列之CyclicBarrier源碼分析

    Java并發(fā)系列之CyclicBarrier源碼分析

    這篇文章主要為大家詳細(xì)分析了Java并發(fā)系列之CyclicBarrier源碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • Spring IoC容器常見獲取Bean的方式匯總示例解析

    Spring IoC容器常見獲取Bean的方式匯總示例解析

    這篇文章主要為大家介紹了Spring IoC容器常見獲取Bean的方式匯總示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • JavaScript的基本類型值-String類型

    JavaScript的基本類型值-String類型

    String類型用于表示由零或多個16位Unicode字符組成的字符序列,即字符串。在JavaScript中沒有單個的字符型,都是字符串。這篇文章主要介紹了JavaScript的基本類型值String類型,需要的朋友可以參考下
    2017-02-02
  • Java定義形式及可變參數(shù)實(shí)例解析

    Java定義形式及可變參數(shù)實(shí)例解析

    這篇文章主要介紹了Java定義形式及可變參數(shù)實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • 詳解Spring IOC 容器啟動流程分析

    詳解Spring IOC 容器啟動流程分析

    這篇文章主要介紹了Spring IOC 容器啟動流程分析,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-08-08

最新評論