需求背景
在开发过程中经常会使用到一种场景就是比较内存中的两个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.java
、ApplicationException.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 - 修改的字段有:修改了昵称、修改了邮箱、修改了年龄
评论区