乐趣区

关于java:项目终于上了这个数据单位转换工具类金额转换太优雅了

起源:blog.csdn.net/qq_35387940/article/details/129167329

前言

平时做一些统计数据,常常从数据库或者是从接口获取进去的数据,单位是跟业务需要不统一的。

  • 比方,咱们拿进去的 分,实际上要是元
  • 又比方,咱们拿到的数据须要 乘以 100 返回给前端做 百分比展现
  • 又比方,千分比转换
  • 又比方,拿进去的金额须要变成 万为单位
  • 又比方,须要保留 2 位小数
  • ……
  • 等等等等

平时咱们怎么搞?

很多时候拿到的是一个数据汇合 list,就须要去遍历而后依据每个 DTO 的属性去做相干单位转换。

始终 get 完 set,get 完 set,get 完 set,get 完 set,get 完 set,人都麻了。

就像这样:

所以,如果通过反射主动匹配进去一些操作转换,是不是就看代码看起来难受一点,人也轻松一点。

举荐一个开源收费的 Spring Boot 实战我的项目:

https://github.com/javastacks/spring-boot-best-practice

答案:是的

而后,我就搞了。

注释

本篇内容简要:

  1. 初步的封装,通过 map 去标记须要转换的 类属性字段
  2. 进一步的封装,配合老朋友自定义注解搞事件

产品:

  • 领取总金额 换成万 为单位,不便经营统计;
  • 那个什么计数,要是百分比的;
  • 而后还有一个是千分比;
  • 另外,还有 2 个要保留 2 位小数;
  • 还有啊,那个。。。。。。

我:

别说了,喝口水吧。

拿到的数据都在这个 DTO 外面:

开始封装:

① 初步的封装,通过 map 去标记须要转换的 类属性字段

思路玩法:

  1. 通过反射拿出字段
  2. 配合传入的转换标记 Map 匹配哪些字段须要操作
  3. 而后从 map 取出相干字段的具体操作是什么,而后执行转换操作
  4. 从新赋值

① 简略弄个枚举,列出当初需要上的转换操作类型

UnitConvertType.java

/**
 * @Author : JCccc
 * @CreateTime : 2023/01/14
 * @Description :
 **/
public enum UnitConvertType {

    /**
     * 精度
     */
    R,
    /**
     * 万元
     */
    B,
    /**
     * 百分
     */
    PERCENTAGE,
    /**
     * 千分
     */
    PERMIL
}

② 外围封装的转换函数

UnitConvertUtil.java

import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author : JCccc
 * @CreateTime : 2023/01/14
 * @Description :
 **/
@Slf4j
public class UnitConvertUtil {public static <T> void unitMapConvert(List<T> list, Map<String, UnitConvertType> propertyMap) {for (T t : list) {Field[] declaredFields = t.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {if (propertyMap.keySet().stream().anyMatch(x -> x.equals(declaredField.getName()))) {
                    try {declaredField.setAccessible(true);
                        Object o = declaredField.get(t);
                        UnitConvertType unitConvertType = propertyMap.get(declaredField.getName());
                        if (o != null) {if (unitConvertType.equals(UnitConvertType.PERCENTAGE)) {BigDecimal bigDecimal = ((BigDecimal) o).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                                declaredField.set(t, bigDecimal);
                            }
                            if (unitConvertType.equals(UnitConvertType.PERMIL)) {BigDecimal bigDecimal = ((BigDecimal) o).multiply(new BigDecimal(1000)).setScale(2, BigDecimal.ROUND_HALF_UP);
                                declaredField.set(t, bigDecimal);
                            }
                            if (unitConvertType.equals(UnitConvertType.B)) {BigDecimal bigDecimal = ((BigDecimal) o).divide(new BigDecimal(10000)).setScale(2, BigDecimal.ROUND_HALF_UP);
                                declaredField.set(t, bigDecimal);
                            }
                            if (unitConvertType.equals(UnitConvertType.R)) {BigDecimal bigDecimal = ((BigDecimal) o).setScale(2, BigDecimal.ROUND_HALF_UP);
                                declaredField.set(t, bigDecimal);
                            }
                        }
                    } catch (Exception ex) {log.error("解决失败");
                        continue;
                    }

                }
            }
        }
    }

    public static void main(String[] args) {

        // 获取模仿数据
        List<MySumReportDTO> list = getMySumReportList();

        Map<String, UnitConvertType> map =new HashMap<>();
        map.put("payTotalAmount", UnitConvertType.B);
        map.put("jcAmountPercentage", UnitConvertType.PERCENTAGE);
        map.put("jcCountPermillage", UnitConvertType.PERMIL);
        map.put("length", UnitConvertType.R);
        map.put("width", UnitConvertType.R);
        unitMapConvert(list,map);
        System.out.println("通过 map 标识的主动转换玩法:"+list.toString());

    }

    private static List<MySumReportDTO> getMySumReportList() {MySumReportDTO mySumReportDTO = new MySumReportDTO();
        mySumReportDTO.setPayTotalAmount(new BigDecimal(1100000));
        mySumReportDTO.setJcAmountPercentage(BigDecimal.valueOf(0.695));
        mySumReportDTO.setJcCountPermillage(BigDecimal.valueOf(0.7894));
        mySumReportDTO.setLength(BigDecimal.valueOf(1300.65112));
        mySumReportDTO.setWidth(BigDecimal.valueOf(6522.12344));

        MySumReportDTO mySumReportDTO1 = new MySumReportDTO();
        mySumReportDTO1.setPayTotalAmount(new BigDecimal(2390000));
        mySumReportDTO1.setJcAmountPercentage(BigDecimal.valueOf(0.885));
        mySumReportDTO1.setJcCountPermillage(BigDecimal.valueOf(0.2394));
        mySumReportDTO1.setLength(BigDecimal.valueOf(1700.64003));
        mySumReportDTO1.setWidth(BigDecimal.valueOf(7522.12344));

        List<MySumReportDTO> list = new ArrayList<>();

        list.add(mySumReportDTO);
        list.add(mySumReportDTO1);
        return list;
    }

}

代码简析:

看看怎么调用的:

public static void main(String[] args) {

    // 获取模仿数据
    List<MySumReportDTO> list = getMySumReportList();
    System.out.println("转换前:"+list.toString());
    Map<String, UnitConvertType> map =new HashMap<>();
    map.put("payTotalAmount", UnitConvertType.B);
    map.put("jcAmountPercentage", UnitConvertType.PERCENTAGE);
    map.put("jcCountPermillage", UnitConvertType.PERMIL);
    map.put("length", UnitConvertType.R);
    map.put("width", UnitConvertType.R);
    unitMapConvert(list,map);
    System.out.println("通过 map 标识的主动转换玩法:"+list.toString());

}

代码简析:

成果:

整个汇合 list 的 对应字段都主动转换胜利(转换逻辑想怎么样就本人在对应 if 外面调整、拓展):

② 进一步的封装,配合老朋友自定义注解搞事件

实说实话,第一步的封装水平曾经够用了,就是传 map 标识进去哪些须要转换,对应转换枚举类型是什么。

其实我感觉是够用的。

然而么,为了用起来更加不便,或者说 更加地可拓展,那么配合自定义注解是更 nice 的。

开搞。

创立一个自定义注解,JcBigDecConvert.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author : JCccc
 * @CreateTime : 2023/01/14
 * @Description :
 **/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface JcBigDecConvert {UnitConvertType name();
}

怎么用?就是在咱们的报表 DTO 外面,去标记字段。

示例:

MyYearSumReportDTO.java

ps:能够看到咱们在字段下面应用了自定义注解

import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;

/**
 * @Author : JCccc
 * @CreateTime : 2023/2/03
 * @Description :
 **/

@Data
public class MyYearSumReportDTO implements Serializable {
    private static final long serialVersionUID = 5285987517581372888L;

    // 领取总金额
    @JcBigDecConvert(name=UnitConvertType.B)
    private BigDecimal payTotalAmount;

    //jc 金额百分比
    @JcBigDecConvert(name=UnitConvertType.PERCENTAGE)
    private BigDecimal jcAmountPercentage;

    //jc 计数千分比
    @JcBigDecConvert(name=UnitConvertType.PERMIL)
    private BigDecimal jcCountPermillage;

    // 保留 2 位
    @JcBigDecConvert(name=UnitConvertType.R)
    private BigDecimal length;

    // 保留 2 位
    @JcBigDecConvert(name=UnitConvertType.R)
    private BigDecimal width;

}

而后针对配合咱们的自定义,封一个转换函数,反射获取属性字段,而后解析注解,而后做对应转换操作。

代码:

public static <T> void unitAnnotateConvert(List<T> list) {for (T t : list) {Field[] declaredFields = t.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
                try {if (declaredField.getName().equals("serialVersionUID")){continue;}
                    JcBigDecConvert myFieldAnn = declaredField.getAnnotation(JcBigDecConvert.class);
                    if(Objects.isNull(myFieldAnn)){continue;}
                    UnitConvertType unitConvertType = myFieldAnn.name();
                    declaredField.setAccessible(true);
                    Object o = declaredField.get(t);
                    if (Objects.nonNull(o)) {if (unitConvertType.equals(UnitConvertType.PERCENTAGE)) {BigDecimal bigDecimal = ((BigDecimal) o).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                            declaredField.set(t, bigDecimal);
                        }
                        if (unitConvertType.equals(UnitConvertType.PERMIL)) {BigDecimal bigDecimal = ((BigDecimal) o).multiply(new BigDecimal(1000)).setScale(2, BigDecimal.ROUND_HALF_UP);
                            declaredField.set(t, bigDecimal);
                        }
                        if (unitConvertType.equals(UnitConvertType.B)) {BigDecimal bigDecimal = ((BigDecimal) o).divide(new BigDecimal(10000)).setScale(2, BigDecimal.ROUND_HALF_UP);
                            declaredField.set(t, bigDecimal);
                        }
                        if (unitConvertType.equals(UnitConvertType.R)) {BigDecimal bigDecimal = ((BigDecimal) o).setScale(2, BigDecimal.ROUND_HALF_UP);
                            declaredField.set(t, bigDecimal);
                        }
                    }
                } catch (Exception ex) {log.error("解决失败");
                }
        }
    }
}

写个调用示例看看成果:

public static void main(String[] args) {List<MyYearSumReportDTO> yearsList = getMyYearSumReportList();
    unitAnnotateConvert(yearsList);
    System.out.println("通过注解标识的主动转换玩法:"+yearsList.toString());
}

private static List<MyYearSumReportDTO> getMyYearSumReportList() {MyYearSumReportDTO mySumReportDTO = new MyYearSumReportDTO();
    mySumReportDTO.setPayTotalAmount(new BigDecimal(1100000));
    mySumReportDTO.setJcAmountPercentage(BigDecimal.valueOf(0.695));
    mySumReportDTO.setJcCountPermillage(BigDecimal.valueOf(0.7894));
    mySumReportDTO.setLength(BigDecimal.valueOf(1300.65112));
    mySumReportDTO.setWidth(BigDecimal.valueOf(6522.12344));
    MyYearSumReportDTO mySumReportDTO1 = new MyYearSumReportDTO();
    mySumReportDTO1.setPayTotalAmount(new BigDecimal(2390000));
    mySumReportDTO1.setJcAmountPercentage(BigDecimal.valueOf(0.885));
    mySumReportDTO1.setJcCountPermillage(BigDecimal.valueOf(0.2394));
    mySumReportDTO1.setLength(BigDecimal.valueOf(1700.64003));
    mySumReportDTO1.setWidth(BigDecimal.valueOf(7522.12344));

    List<MyYearSumReportDTO> list = new ArrayList<>();
    list.add(mySumReportDTO);
    list.add(mySumReportDTO1);
    return list;
}

成果也是很 OK:

抛砖引玉,传递‘玩’代码思维,学编程,哎我就是玩。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿 (2022 最新版)

2. 劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版