【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;
}

  

原文地址:https://www.cnblogs.com/july-sunny/p/12434937.html