java-2個自定義註解+1個工具類對小數型別欄位進行四捨五入處理

風雪十年燈發表於2023-03-08

java中有時候需要對返回前端的資料做統一的資料格式化,如小數型別的欄位需要格式化成保留兩位小數的四捨五入格式; 這裡使用兩個註解: 一個標註類,一個標註欄位,在返回前使用工具類方法呼叫一次,完成此目標.

1. 類上標註的註解@RoundMark

package com.niewj.common.annotation;

import java.lang.annotation.*;

/**
 * 數學欄位需要格式化的類標記註解
 *
 * @author niewj  
 * @date 2023/3/8 16:03
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RoundMark {
}

2. 欄位上標註的註解@Round

package com.niewj.common.annotation;

import java.lang.annotation.*;

/**
 * 實體欄位格式化:float/double/decimal欄位四捨五入保留2位小數(預設)
 *
 * @author niewj
 * @date 2023/3/8 16:03
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Round {
    int value() default 2;
}

3. 註解的使用

package com.niewj.business.model;

import com.niewj.common.annotation.Round;
import com.niewj.common.annotation.RoundMark;
import lombok.Data;

import java.math.BigDecimal;

/**
 * 明細資料
 *
 * @author niewj
 * @date 2023-02-12
 */
@Data
@RoundMark
public class DataReturnToFront {
    /**
     * 商品skuid
     */
    private Long skuId;
    /**
     * 總商品量
     */
    private Long count;

    /**
     * 商品平均曝光量
     */
    @Round
    private Double avgExp;
    /**
     * 商品平均曝光量-環比昨日
     */
    @Round
    private Double avgExpDodRatio;
    /**
     * 商品平均曝光量-(新增)
     */
    @Round
    private Double avgExpIncrement;
    /**
     * 商品[平均曝光量]-環比昨日-新增
     */
    @Round
    private Double avgExpIncrementDodRatio;
    /**
     * 商品[平均成交額]
     */
    @Round
    private Double avgSaleAmt;
    /**
     * 商品[平均成交額]-環比(昨日)
     */
    @Round
    private Double avgSaleAmtDodRatio;
    /**
     * 商品[平均成交額]-新增
     */
    @Round
    private Float avgSaleAmtIncrement;
    /**
     * 管控[平均成交額]-環比(昨日)-新增
     */
    @Round
    private BigDecimal avgSaleAmtIncrementDodRatio;
}

4.註解的處理過程,工具類:

package com.niewj.common.util;

import com.niewj.common.annotation.Round;
import com.niewj.common.annotation.RoundMark;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;

/**
 * 註解工具類:用於對實體物件透過類和欄位上標記註解來處理物件
 */
@Slf4j
public class AnnotationUtil {

    /**
     * 遍歷格式化列表List內元素物件的數字欄位
     *
     * @param targetList 待處理資料集合
     * @param <T>
     */
    public static <T> void roundListItemFields(List<T> targetList) {
        if (CollectionUtils.isEmpty(targetList)) {
            log.info("targetList為空,不需要處理");
            return;
        }
        targetList.stream().forEach(e -> {
            roundDecimalValues(e);
        });
    }

    /**
     * 對小數數字格式的資料四捨五入:對類上標註了@RoundMark/欄位上標註了@Round的資料進行四捨五入
     *
     * @param target 待處理實體物件
     * @param <T>
     */
    public static <T> void roundDecimalValues(T target) {
        Class<? extends Object> targetClass = target.getClass();
        boolean hasRoundingNumberAnno = targetClass.isAnnotationPresent(RoundMark.class);
        if (hasRoundingNumberAnno) {
            //為屬性處理欄位值
            roundDecimalField(targetClass, target);
        }
    }

    /**
     * 對目標類中的每個欄位來匹配field註解,如果匹配則進行四捨五入
     *
     * @param targetClass 標註了Round註解的類
     * @param target      類的例項物件-即需要處理的欄位所在物件
     * @param <T>
     */
    private static <T> void roundDecimalField(Class<? extends Object> targetClass, T target) {
        Field[] fields = targetClass.getDeclaredFields();
        Arrays.stream(fields).forEach(field -> {
            boolean hasRoundingNumberAnno = field.isAnnotationPresent(Round.class);
            if (hasRoundingNumberAnno) {
                //獲取註解的值
                int scale = field.getAnnotation(Round.class).value();

                Object originFieldVal;
                Object roundedFieldVal;
                try {
                    field.setAccessible(true);
                    originFieldVal = field.get(target);

                    if (originFieldVal instanceof Float) {
                        BigDecimal value = new BigDecimal(String.valueOf(originFieldVal)).setScale(scale, RoundingMode.HALF_UP);
                        roundedFieldVal = value.floatValue();
                    } else if (originFieldVal instanceof Double) {
                        BigDecimal value = new BigDecimal(String.valueOf(originFieldVal)).setScale(scale, RoundingMode.HALF_UP);
                        roundedFieldVal = value.doubleValue();
                    } else if (originFieldVal instanceof BigDecimal) {
                        roundedFieldVal = new BigDecimal(String.valueOf(originFieldVal)).setScale(scale, RoundingMode.HALF_UP);
                    } else {
                        roundedFieldVal = originFieldVal;
                    }

                    field.set(target, roundedFieldVal);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

5.使用方式:controller端

@GetMapping("/test")
    @ResponseBody
    @RecCostTime
    public List<DataReturnToFront> test() {
        log.info("======================");
        DataReturnToFront detail = new DataReturnToFront();
        detail.setSkuId(233230L);
        detail.setCount(0L);
        detail.setAvgExp(2220.1234566D);
        detail.setAvgExpDodRatio(2220.1254566D);
        detail.setAvgExpIncrement(-2220.1254566D);
        detail.setAvgExpIncrementDodRatio(-2220.1264566D);
        detail.setAvgSaleAmt(2220.1234566D);
        detail.setAvgSaleAmtDodRatio(2220.1254566D);
        detail.setAvgSaleAmtIncrement(2220.1254566F);
        detail.setAvgSaleAmtIncrementDodRatio(BigDecimal.valueOf(0.1234566D));

        DataReturnToFront detail2 = new DataReturnToFront();
        detail2.setSkuId(5230L);
        detail2.setCount(2330L);
        detail2.setAvgExp(20.135634566D);
        detail2.setAvgExpDodRatio(22.55554566D);
        detail2.setAvgExpIncrement(-2220.5555D);
        detail2.setAvgExpIncrementDodRatio(-2220.5555D);
        detail2.setAvgSaleAmt(2220.5555D);
        detail2.setAvgSaleAmtDodRatio(2220.5555D);
        detail2.setAvgSaleAmtIncrement(2220.5555F);
        detail2.setAvgSaleAmtIncrementDodRatio(BigDecimal.valueOf(0.5555D));

        List list = new ArrayList();
        list.add(detail);
        list.add(detail2);
        // 四捨五入格式化-批次處理
        AnnotationUtil.roundListItemFields(list);
        // 單個處理
        AnnotationUtil.roundDecimalValues(detail);

        return list;
    }
  • roundDecimalValues是對單個物件的標註了@Round欄位(前提是類上有@RoundMark標記)進行四捨五入修改欄位值.
  • roundListItemFields是對list遍歷了一下.

相關文章