You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中如何实现Double类型字段值自动四舍五入

核心结论

Spring Boot 没有提供内置的属性或开箱即用的注解,可以直接实现Double类型字段的自动四舍五入、null值默认转0.00的效果。你期望的@roundOfDouble式的能力完全可以通过Spring生态的扩展点自定义实现,以下是几种生产环境常用的落地方案:

可行实现方案
  • 方案1:自定义注解 + Jackson序列化器(最贴合注解使用习惯,适配接口返回场景)
    这个方案实现后和你预期的用法完全一致,只需要在字段上标注注解就能自动处理序列化时的数值转换,支持自定义小数位数、默认值、舍入规则:
    第一步先定义自定义注解:
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.RoundingMode;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = RoundDoubleSerializer.class)
public @interface RoundOfDouble {
    // 保留小数位数,默认2位
    int scale() default 2;
    // null值时返回的默认值
    double defaultValue() default 0.00;
    // 舍入规则,默认使用常规四舍五入HALF_UP
    RoundingMode roundingMode() default RoundingMode.HALF_UP;
}

第二步实现对应的Jackson序列化处理器,拦截标注了注解的字段做值转换:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;

public class RoundDoubleSerializer extends JsonSerializer<Double> implements ContextualSerializer {
    private int scale;
    private double defaultValue;
    private RoundingMode roundingMode;

    @Override
    public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        double targetVal = value == null ? defaultValue : value;
        BigDecimal processedVal = BigDecimal.valueOf(targetVal).setScale(scale, roundingMode);
        gen.writeNumber(processedVal.doubleValue());
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider provider, BeanProperty property) {
        RoundOfDouble annotation = property.getAnnotation(RoundOfDouble.class);
        if (annotation != null) {
            this.scale = annotation.scale();
            this.defaultValue = annotation.defaultValue();
            this.roundingMode = annotation.roundingMode();
        }
        return this;
    }
}

使用时直接在字段上标注即可,比如@RoundOfDouble(scale = 2)标注在amount字段上,接口返回时1500.95会自动转为1501.00,null值会自动返回0.00,需要特殊配置时直接给注解传参就行。

  • 方案2:字段Setter方法拦截(适配参数接收、内部赋值场景,无额外依赖)
    如果不需要在全链路做通用处理,只是单个类的字段需要做转换,直接在字段的set方法里写转换逻辑就行,不需要额外写注解和配置:
import java.math.BigDecimal;
import java.math.RoundingMode;

public class TradeOrder {
    private Double amount;

    public void setAmount(Double amount) {
        if (amount == null) {
            this.amount = 0.00;
            return;
        }
        this.amount = BigDecimal.valueOf(amount)
                .setScale(2, RoundingMode.HALF_UP)
                .doubleValue();
    }

    // 省略getter方法
}

如果要做全场景的参数绑定自动转换,可以结合Spring的WebDataBinder写自定义属性编辑器,拦截所有Double类型的参数注入做统一处理。

  • 方案3:全局Jackson序列化配置(适配全项目统一规则场景,无需逐字段加注解)
    如果项目里所有Double类型字段都需要统一做2位四舍五入、null转0.00的处理,不需要逐字段配置,直接注册全局的Double类型序列化器即可:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;

@Configuration
public class GlobalDoubleConfig {
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer doubleSerializeCustomizer() {
        return builder -> builder.serializerByType(Double.class, new JsonSerializer<Double>() {
            @Override
            public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                double targetVal = value == null ? 0.00 : value;
                double processedVal = BigDecimal.valueOf(targetVal)
                        .setScale(2, RoundingMode.HALF_UP)
                        .doubleValue();
                gen.writeNumber(processedVal);
            }
        });
    }
}

注意:Double是浮点数类型,本身存在天然的精度丢失问题,如果是金额、费率这类对精度要求高的业务场景,不建议用Double做存储和计算,优先选择BigDecimal类型,上述实现逻辑只需要把泛型从Double替换为BigDecimal就可以直接复用。

内容的提问来源于stack exchange,提问作者Sophia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 23:12:22