侧边栏壁纸
博主头像
赫兹

谁辜负过自己,说不上可惜

  • 累计撰写 18 篇文章
  • 累计创建 13 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录

注解+反射判断对象是否被修改,比较新旧对象的差异性

赫兹
2022-09-21 / 0 评论 / 0 点赞 / 301 阅读 / 749 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-09-21,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

需求背景

​ 在开发过程中经常会使用到一种场景就是比较内存中的两个bean 数据有什么同,或者要识别一个数据前后的数据变更项有哪些。

使用说明

🥝1.自定义注解类PropertyMsg.java

/**
 * 字段的配置、提示信息
 *
 * @author 赫兹
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface PropertyMsg {

    String value();
}

🥝2.创建一个需要对比的User.java用户实体类,用于模拟对比用户信息修改前后的效果。并在需要做对比的字段加上@PropertyMsg注解

/**
 * @author 赫兹
 */
@Data
@AllArgsConstructor
public class User {

    private String name;

    @PropertyMsg("修改了昵称")
    private String nickName;

    private String sex;

    @PropertyMsg("修改了邮箱")
    private String email;

    @PropertyMsg("修改了年龄")
    private int age;
}

🥝3.创建自定义异常类(ApplicationExceptionEnum.javaApplicationException.java),用于捕获对比时可能产生的异常

ApplicationExceptionEnum.java

/**
 * @author 赫兹
 */
public enum ApplicationExceptionEnum {

    PARAM_NULL(90001, "参数为空!"),

    PARAM_ERROR(90002, "参数错误"),

    PARAM_REPEAT(90003, "重复参数"),
    ;

    private final Integer code;

    private final String message;

    ApplicationExceptionEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public Integer getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

ApplicationException.java

/**
 * @author 赫兹
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class ApplicationException extends RuntimeException {

    /**
     * 异常code
     */
    private Integer code;

    public ApplicationException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public ApplicationException(ApplicationExceptionEnum exceptionEnum) {
        this(exceptionEnum.getCode(), exceptionEnum.getMessage());
    }
}

🥝4.编写对比工具类BeanChangeUtil

/**
 * @author 赫兹
 */
public class BeanChangeUtil {

    /**
     * 比较新旧对象的差异性
     *
     * @param oldBean 旧实例
     * @param newBean 新实例
     * @return 差异描述
     */
    public static <T> String contrastObj(T oldBean, T newBean) {
        if (oldBean == null || newBean == null) {
            throw new ApplicationException(ApplicationExceptionEnum.PARAM_NULL);
        }
        // 创建字符串拼接对象
        StringBuilder str = new StringBuilder();
        // 通过反射获取类的Class对象
        Class<T> clazz = (Class<T>) oldBean.getClass();
        return difference(clazz.getDeclaredFields(), oldBean, newBean, str, clazz);
    }


    /**
     * 反射获取对象属性差异
     **/
    private static <T> String difference(Field[] fields, T pojo1, T pojo2, StringBuilder str, Class<T> clazz) {
        try {
            for (Field field : fields) {
                if (field.isAnnotationPresent(PropertyMsg.class)) {
                    PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                    // 获取对应属性值
                    Method getMethod = pd.getReadMethod();
                    Object o1 = getMethod.invoke(pojo1);
                    Object o2 = getMethod.invoke(pojo2);
                    boolean update;
                    if (o1 == null && o2 == null) {
                        continue;
                    }
                    if (o1 == null || o2 == null) {
                        update = true;
                    } else {
                        if (o1 instanceof String) {
                            o1 = ((String) o1).replace(" ", "");
                            o2 = ((String) o2).replace(" ", "");
                        } else {
                            o1 = o1.toString();
                            o2 = o2.toString();
                        }
                        update = !o1.equals(o2);
                    }
                    if (update) {
                        if (str.length() > 0) {
                            str.append("、");
                        }
                        str.append(field.getAnnotation(PropertyMsg.class).value());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str.toString();
    }

}

🥝5.编写单元测试,验证效果

/**
 * @author haizhou
 * @since 2022/9/21
 */
@Slf4j
public class JUnitText {

    @Test
    public void textBeanChangeUtil() {
        //模拟用户信息修改
        User oldUser = new User("张三", "小张", "男", "1234567@qq.com", 23);
        User newUser = new User("张三", "大张", "男", "6666666@qq.com", 18);
        String contractContent = BeanChangeUtil.contrastObj(oldUser, newUser);
        log.info("修改的字段有:{}", contractContent);
        if (contractContent.isEmpty()) {
            //说明用户信息没有修改
        } else {
            //说明用户信息已经被修改
        }
    }
}

🥝6.结果输出:

[main] INFO com.hz.codecase.test.JUnitText - 修改的字段有:修改了昵称、修改了邮箱、修改了年龄
0

评论区