Jackson自定义序列化注解之 保留小数位数 (默认2位小数 四舍五入)

目录

1. 注解类

2. 注解处理类DecimalPrecisionHandler


        此文章需要先看Jackson自定义序列化注解 (支持同时使用多个自定义序列化注解)

  1. 注解类

    import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.math.RoundingMode;
    
    /**
     * 保留小数位数 (默认2位小数 四舍五入)
     *
     * @author ds
     */
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @JacksonAnnotationsInside
    @JacksonBaseSerialize(handlerClazz = DecimalPrecisionHandler.class)
    public @interface DecimalPrecision {
    
        /**
         * 保留小数位数 (默认2位小数)
         */
        int precision() default 2;
    
        /**
         * 舍入模式 (默认四舍五入)
         */
        RoundingMode roundingMode() default RoundingMode.HALF_UP;
    
        /**
         * 是否单独返回 (默认否)
         */
        boolean isSeparately() default false;
    
        /**
         * 是否去除末尾的0 (默认是)
         */
        boolean isStripTrailingZeros() default true;
    }
    
  2. 注解处理类DecimalPrecisionHandler

    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.BeanProperty;
    import com.fasterxml.jackson.databind.SerializerProvider;
    
    import java.io.IOException;
    import java.math.BigDecimal;
    import java.math.BigInteger;
    import java.math.RoundingMode;
    
    /**
     * Jackson 序列化处理类
     * 保留小数位数 (默认2位小数 四舍五入)
     *
     * @author ds
     */
    public class DecimalPrecisionHandler implements IJacksonBaseSerializeHandler<DecimalPrecision, Object> {
    
        /**
         * Method that can be called to ask implementation to serialize
         * values of type this serializer handles.
         *
         * @param value       Value to serialize; can <b>not</b> be null.
         * @param gen         Generator used to output resulting Json content
         * @param serializers Provider that can be used to get serializers for
         *                    serializing Objects value contains, if any.
         */
        @Override
        public void serializeHandler(BeanProperty beanProperty, DecimalPrecision annotation, Object value, JsonGenerator gen, SerializerProvider serializers)
                throws IOException {
    
            // 为空直接跳过
            if (beanProperty == null) {
                return;
            }
            BigDecimal temp = this.handlerBigDecimal(value);
    
            int precision = annotation.precision();
            RoundingMode roundingMode = annotation.roundingMode();
    
            temp = temp.setScale(precision, roundingMode);
    
            // 是否去除末尾的0 (默认是)
            if (annotation.isStripTrailingZeros()) {
                temp = temp.stripTrailingZeros();
            }
    
            String valueStr = temp.toPlainString();
            if (annotation.isSeparately()) {
                // 单独返回
                gen.writeStringField(beanProperty.getName() + "DecimalPrecision", valueStr);
            } else {
                // 当前字段中返回
                gen.writeStringField(beanProperty.getName(), valueStr);
            }
        }
    
        /**
         * 处理成BigDecimal类型
         *
         * @param value Value to serialize; can <b>not</b> be null.
         * @return 对应的BigDecimal类型实例
         */
        private BigDecimal handlerBigDecimal(Object value) {
            BigDecimal temp;
            if (value instanceof BigDecimal) {
                temp = (BigDecimal) value;
            } else if (value instanceof Integer) {
                temp = BigDecimal.valueOf((Integer) value);
            } else if (value instanceof Long) {
                temp = BigDecimal.valueOf((Long) value);
            } else if (value instanceof BigInteger) {
                temp = new BigDecimal((BigInteger) value);
            } else if (value instanceof String) {
                temp = new BigDecimal((String) value);
            } else {
                throw new NumberFormatException("No digits found.");
            }
            return temp;
        }
    }
    

<think>好的,我现在需要帮助用户解决在Spring Boot和MyBatis环境下如何让BigDecimal类型的实体类默认保留小数的问题。首先,我得理清楚用户的具体需求。用户提到实体类中使用BigDecimal,并且希望默认保留小数,可能涉及到数据库存储和Java层面的处理。 首先,BigDecimal本身是一个可以表示任意精度的十进制数,所以它不会自动限制小数位数。用户需要的是在存储到数据库或者从数据库读取时,自动保持两小数,或者在Java代码中处理时保留小数。 接下来,我需要考虑可能的实现方式。通常,保留小数位数可以通过数据库的字段定义、MyBatis的类型处理器(TypeHandler)、或者在实体类中使用注解进行格式化。 关于数据库层面,比如MySQL,可以设置字段类型为DECIMAL(19,2),这样存储时会固定两小数。这可能是最直接的方式,但用户可能已经存在数据库表结构,或者希望不依赖数据实现,所以需要考虑其他方法。 然后是MyBatis的处理。MyBatis在将Java对象映射到数据库时,可以使用自定义的TypeHandler来处理BigDecimal的转换。例如,在插入或更新时,将BigDecimal四舍五入到两小数。这里需要编写一个自定义的TypeHandler,重写setNonNullParameter方法,在设置参数时对值进行处理。 另外,在实体类中,可能需要在字段上使用注解格式化数值。例如,使用Jackson的@JsonFormat注解可以在序列化为JSON时保留小数,但这可能不适用于数据库存储,只是影响JSON输出。用户的需求可能更关注数据库存储,所以这个可能作为补充方案。 还有Spring注解@DecimalMin和@DecimalMax可以用来验证数值范围,但不会改变存储的值。所以可能不适用。 还需要考虑的是,当从数据库读取数据时,如果数据库存储的是更多的小数位,可能需要使用TypeHandler在结果映射时进行四舍五入。或者在实体类的setter方法中直接处理,设置值的精度。 另外,使用Hibernate Validator的@Digits注解可以验证整数和小数部分的数,但这同样只是验证,不会自动截断或四舍五入。 综合来看,最可靠的方法可能是结合数据库字段定义和MyBatis的TypeHandler。确保数据库存储时使用DECIMAL(19,2),然后在Java层面通过TypeHandler处理数据的转换,或者在实体类的setter方法中设置精度。 可能还需要考虑四舍五入的模式,比如HALF_UP,以及处理可能出现的精度丢失问题。此外,需要测试各种情况,比如插入、更新、查询时,确保数据的一致性和正确性。 最后,可能需要指导用户如何具体实现这些步骤,包括代码示例和配置说明,确保他们能够正确应用这些方法到自己的项目中。</think>在Spring Boot和MyBatis中,让实体类的`BigDecimal`类型默认保留小数,可以通过以下步骤实现: --- ### 一、数据库层面设置(推荐) 在数据库表设计时,直接定义字段精度为`DECIMAL(19,2)`,强制保留小数: ```sql CREATE TABLE your_table ( amount DECIMAL(19,2) -- 总长度19小数部分2 ); ``` --- ### 二、MyBatis TypeHandler处理 通过自定义TypeHandler,在数据读写时自动格式化`BigDecimal`。 1. **编写自定义TypeHandler**: ```java @MappedTypes(BigDecimal.class) public class BigDecimalTypeHandler extends BaseTypeHandler<BigDecimal> { @Override public void setNonNullParameter(PreparedStatement ps, int i, BigDecimal parameter, JdbcType jdbcType) throws SQLException { // 写入数据库时四舍五入保留小数 ps.setBigDecimal(i, parameter.setScale(2, RoundingMode.HALF_UP)); } @Override public BigDecimal getNullableResult(ResultSet rs, String columnName) throws SQLException { // 读取时直接返回原始值(或也可在此处格式化) return rs.getBigDecimal(columnName); } // 其他重写方法(略) } ``` 2. **在MyBatis配置中注册TypeHandler**: ```yaml # application.yml mybatis: type-handlers-package: com.example.handler # 自定义TypeHandler所在包 ``` --- ### 三、实体类Setter方法控制 在实体类的Setter方法中直接格式化: ```java public class YourEntity { private BigDecimal amount; public void setAmount(BigDecimal amount) { this.amount = amount != null ? amount.setScale(2, RoundingMode.HALF_UP) : null; } } ``` --- ### 四、Jackson序列化格式化(仅影响JSON输出) 若需在返回JSON时保留小数,使用`@JsonFormat`注解: ```java public class YourEntity { @JsonFormat(shape = JsonFormat.Shape.STRING) private BigDecimal amount; } ``` --- ### 五、验证与测试 1. **插入数据测试**: ```java YourEntity entity = new YourEntity(); entity.setAmount(new BigDecimal("3.1415")); // 插入数据库后实际存储为3.14 ``` 2. **查询数据验证**: ```java YourEntity result = mapper.selectById(1); System.out.println(result.getAmount()); // 输出3.14 ``` --- ### 六、注意事项 1. **四舍五入模式**:根据需求选择`RoundingMode.HALF_UP`(四舍五入)或其他模式。 2. **全局一致性**:确保数据库、TypeHandler和业务代码中的精度处理逻辑一致。 3. **空值处理**:在Setter和TypeHandler中需判断`BigDecimal`是否为`null`。 --- 通过上述方法,可以确保`BigDecimal`类型在存储、传输和展示时始终保留小数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值