对视图模型构造相关参数的轮子

前言

清明放假没事在家写一些常用的轮子,以便减少一些重复繁琐的编码工作。

话不多说,继续往下看

有时我们的接口数据返回给前端或者导出为excel时,需要给相关值带单位(kg/立方米/%等)、或保留小数位等。尤其是一些统计类的报表,值特别多、单位也就贼多了。

做法

  1. 查询时在sql中拼接。给sql添加了好多无聊的字符,看起来都不好看,维护性不好,看起来都头疼
  2. 业务代码中循环拼接。这也很麻烦
  3. 交给前端回显时去拼接。前端有可能要骂娘

想法

  1. 既然是面向对象编程,那最好就是有维护一个视图对象,供我们返回到前端
  2. 一般我们通过sql查出来的po、dto模型或者通过业务处理后的bo模型不会直接给到前端,而是处理到vo再给到前端。
  3. 所以我就在想,我可以定义一些注解指明这个属性的单位是啥、保留小数位、或者替换符,然后通过一个对象转换的方法,获取到该属性注解的值,再通过反射赋予到vo模型中去。
  4. 想起来很简单,说干就干。不到两小时就撸出来了这个轮子,代码都很简单,主要是要有一些可以简化撸码的想法。也方便我们工作。

代码

可置于需要注解的对象的属性

/**
 * 响应体vo属性
 * 
 * @author MinWeikai
 * @date 2021/3/25 9:34
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RespVoProperty {

    /**
     * 保留小数位数
     * 默认-1不进行保留
     *
     * @return
     */
    int keepDecimal() default -1;

    /**
     * 单位
     *
     * @return
     */
    String unit() default "";

    /**
     * 替换值
     *
     * @return
     */
    String replaceStr() default "";
}

vo模型使用示例

@Data
public class PersonVo {

    private String name;

    @RespVoProperty(unit = "块")
    private String money;

    @RespVoProperty(unit = "岁", replaceStr = "-")
    private String age;

    @RespVoProperty(unit = "kg", keepDecimal = 2)
    private String weight;

}

转换方法

/**
 * 数值集合对象转换为字符集合对象,
 * 可自定义数值保留位数,无值时的替换符、单位等
 *
 * @author MinWeikai
 * @date 2021/4/3 11:20
 */
public class Converts {


    /**
     * 匹配并格式化属性
     *
     * @param source
     * @param keepDecimal
     * @param unit
     * @param replaceStr
     * @param data
     * @param field
     * @param <T>
     */
    private static <T> void formatVoField(Object source, int keepDecimal, String unit, String replaceStr, T data, Field field) {
        if (Objects.equals("serialVersionUID", field.getName())) {
            return;
        }
        Object oldTemp = null;
        try {
            oldTemp = ReflectionUtil.invokeGetterMethod(source, field.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 此处可自定义规则
        switch (field.getType().getSimpleName()) {
            case "Float":
                if (ObjectUtil.isNotNull(oldTemp)) {
                    if (keepDecimal == -1) {
                        oldTemp = new BigDecimal((float) oldTemp);
                    } else {
                        oldTemp = new BigDecimal((float) oldTemp)
                                .setScale(keepDecimal, BigDecimal.ROUND_HALF_UP);
                    }
                    oldTemp = String.valueOf(oldTemp).concat(unit);
                } else {
                    oldTemp = replaceStr;
                }
                break;
            case "Integer":
                if (ObjectUtil.isNotNull(oldTemp)) {
                    oldTemp = String.valueOf(oldTemp).concat(unit);
                } else {
                    oldTemp = replaceStr;
                }
                break;
            case "BigDecimal":
                if (ObjectUtil.isNotNull(oldTemp)) {
                    if (keepDecimal == -1) {
                        oldTemp = new BigDecimal(oldTemp.toString());
                    } else {
                        oldTemp = new BigDecimal(oldTemp.toString())
                                .setScale(keepDecimal, BigDecimal.ROUND_HALF_UP);
                    }
                    oldTemp = String.valueOf(oldTemp).concat(unit);
                } else {
                    oldTemp = replaceStr;
                }
                break;
            default:
        }
        if (ObjectUtil.isNotNull(oldTemp)) {
            ReflectionUtil.invokeSetterMethod(data, field.getName(), oldTemp);
        }
    }


    /**
     * 转化为响应模型
     *
     * @param source  源对象
     * @param voClass vo类
     * @param <T>
     * @return
     */
    public static <T> T toRespVo(Object source, final Class<T> voClass) {
        T data = null;
        try {
            data = voClass.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        // 返回模型属性map
        Map<String, Field> voFieldsMap = Arrays.stream(voClass.getDeclaredFields())
                .collect(Collectors.toMap(Field::getName, Function.identity()));
        // 对老属性赋予参数并置返回模型
        for (Field field : source.getClass().getDeclaredFields()) {
            RespVoProperty property = Optional.ofNullable(voFieldsMap.get(field.getName()))
                    .map(annotationClass -> annotationClass.getAnnotation(RespVoProperty.class))
                    .orElse(null);
            if (Objects.isNull(property)) {
                formatVoField(source, -1, "", "", data, field);
            } else {
                formatVoField(source, property.keepDecimal(), property.unit(), property.replaceStr(), data, field);
            }
        }
        return data;
    }


    /**
     * 集合转化为响应模型集合
     *
     * @param sources 源对象集合
     * @param voClass vo类
     * @param <T>
     * @return
     */
    public static <T> List<T> toRespVos(List<? extends Object> sources, final Class<T> voClass) {
        List<T> targets = new ArrayList<>();
        if (CollectionUtils.isEmpty(sources)) {
            return targets;
        }
        sources.parallelStream().forEach(source -> targets.add(toRespVo(source, voClass)));
        return targets;
    }


    // 测试方法
    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        Person data1 = new Person();
        data1.setName("李三");
        data1.setAge(14);
        data1.setMoney(BigDecimal.ONE);
        data1.setWeight(15.2f);

        System.out.println("-----------------单对象转化vo----------------");

        System.out.println(toRespVo(data1, PersonVo.class));

        System.out.println("--------------------------------------------");


        System.out.println("-----------------集合对象转化vo----------------");

        list.add(data1);

        Person data2 = new Person();
        data2.setName("wangwu");
        data2.setAge(45);
        data2.setMoney(BigDecimal.valueOf(6.41f));
        data2.setWeight(null);
        list.add(data2);

        Person data3 = new Person();
        data3.setName("张思");
        data3.setAge(null);
        data3.setMoney(BigDecimal.valueOf(25f));
        data3.setWeight(17.689f);
        list.add(data3);

        System.out.println(toRespVos(list, PersonVo.class));
    }
}

方法中用到了一个反射方法工具

[ReflectionUtil工具地址](

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

猜你喜欢

转载自blog.csdn.net/weixin_41187876/article/details/115415670