【SpringBoot】SpringBoot 處理后端返回的小數(全局配置 + 定制化配置)


一.拋出問題:

  現在的項目中,存在這樣的幾個問題:

    問題一.數據庫存的數據類型是BigDecimal,或者代碼中計算需要返回BigDecimal的值,由於BigDecimal返回給前端可能存在精度丟失情況

    問題二.BigDecimal再后台計算后,通常需要保留兩位小數或者三位小數返回給前端,每個數據都需要處理,代碼太過於冗余;

 

二.解決方式:

  問題一的解決方案:

    使用全局的序列化配置,統一將BigDecimal的數據類型轉換為String類型,前端將String解析為小數即可;

    代碼如下

    

package com.gabriel.stage.config;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.google.common.collect.ImmutableList;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * @author Gabriel
 * @date 2020-01-08
 * @description  自定義SpringMvc轉換器 解決數據轉換問題(例如BigDecimal轉換為String,解決精度問題)
 * 注意:springboot2.x以后繼承 WebMvcConfigurationSupport 會覆蓋"所有的WebMvc默認的配置,比如WebMvcConfigure",因此不推薦該中方法
 */
//@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {


    /**
     * Date格式化字符串
     */
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    /**
     * DateTime格式化字符串
     */
    private static final DateTimeFormatter DATETIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    /**
     * Time格式化字符串
     */
    private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss");

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);
        final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = converter.getObjectMapper();

        // 反序列化失敗
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        // long 轉換為字符串
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);

        // 浮點型使用字符串
        simpleModule.addSerializer(Double.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Double.TYPE, ToStringSerializer.instance);
        simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);

        // java8 時間格式化
        simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DATETIME_FORMAT));
        simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer(DATE_FORMAT));
        simpleModule.addSerializer(LocalTime.class, new LocalTimeSerializer(TIME_FORMAT));

        objectMapper.registerModule(simpleModule);

        // 為mapper注冊一個帶有SerializerModifier的Factory,處理null值
        objectMapper.setSerializerFactory(objectMapper.getSerializerFactory()
                //CustomizeBeanSerializerModifier 自定義序列化修改器
                .withSerializerModifier(new CustomizeBeanSerializerModifier()));

        // 處理中文亂碼問題
        converter.setSupportedMediaTypes(ImmutableList.of(MediaType.APPLICATION_JSON_UTF8));

        converter.setObjectMapper(objectMapper);
        converters.add(converter);
        converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
    }
}

  問題二的解決方案:

    自定義序列器,使用  @JsonSerialize(using = 自定義序列化器類.class)去序列化指定的屬性

    代碼如下

package com.in.g.data.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.math.BigDecimal;

/**
 * @author: Gabriel
 * @date: 2020/3/7 15:28
 * @description 小數保留2位返回給前端序列化器
 */
public class Decimal2Serializer extends JsonSerializer<Object> {

    /**
     * 將返回的BigDecimal保留兩位小數,再返回給前端
     * @param value
     * @param jsonGenerator
     * @param serializerProvider
     * @throws IOException
     * @throws JsonProcessingException
     */
    @Override
    public void serialize(Object value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        if (value != null) {
            BigDecimal bigDecimal = new BigDecimal(value.toString()).setScale(2,BigDecimal.ROUND_HALF_UP);
            jsonGenerator.writeString(bigDecimal.toString());
        }
    }
}
package com.gabriel.stage.vo;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.gabriel.stage.config.Decimal2Serializer;
import lombok.Data;

import java.math.BigDecimal;

/**
 * @author: Gabriel
 * @date: 2020/3/7 15:45
 * @description
 */
@Data
public class TestVO {

    @JsonSerialize(using = Decimal2Serializer.class)
    private BigDecimal bigDecimal;
}

 

 

  


免責聲明!

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



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