1. 需要监听类 要记录的字段名称 年龄、身高变化
日志例子: 修改年龄"1-2"为"1-6";修改身高"3-4"为"7-8";
@Ignore
@Data
@AllArgsConstructor
@NoArgsConstructor
class Bean {
private Long id; //不需要记录变化的字段,无需添加注解 @ForUpdate
@ForUpdate(fieldName = "性别")
private String sex;
@ForUpdate(fieldName = "姓名") //需要记录变化的字段,需添加注解@ForUpdate
private String name;
@ForUpdate(fieldName = "年龄")
private Integer ageMin;
@ForUpdate(fieldName = "年龄")
private Integer ageMax;
@ForUpdate(fieldName = "身高")
private Integer lengthMin;
@ForUpdate(fieldName = "身高")
private Integer lengthMax;
}
2. 工具类
2.1 自定义注解类
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ForUpdate {
String fieldName() default "";
}
2.2 工具方法
static final String Min = "Min";
static final String Max = "Max";
/**
* 最大最小2个字段值更新
* 运行结果: 修改ageMin1-2为5-6;修改lengthMin3-4为7-8;
*/
public static <T> String filedUpdateLog(T beforeBean, T afterBean) {
StringBuilder msgBuilder = new StringBuilder();
List<FiledChangeVO> filedChangeVOList = getChangedMoreFields(beforeBean, afterBean);
List<String> filedNameReplace = filedChangeVOList.stream().map(filedChangeVO -> {
String filedName = filedChangeVO.filedName;
if (filedName.contains(Min) || filedName.contains(Max)) {
filedName = filedName.replace(Min, "");
filedName = filedName.replace(Max, "");
return filedName;
}
return null;
}).collect(Collectors.toList());
filedNameReplace.removeAll(Collections.singleton(null));
filedNameReplace = filedNameReplace.stream().distinct().collect(Collectors.toList());
filedNameReplace.forEach(filedNameReplaceMinMax -> {
List<FiledChangeVO> filedChangeVOList1 = filedChangeVOList.stream().map(filedChangeVO1 -> {
if (filedChangeVO1.getFiledName().contains(filedNameReplaceMinMax)) {
return filedChangeVO1;
}
return null;
}).collect(Collectors.toList());
filedChangeVOList1.removeAll(Collections.singleton(null));
if (CollectionUtils.isEmpty(filedChangeVOList1)) {
return;
}
FiledChangeVO filedChangeMinVO = null;
FiledChangeVO filedChangeMaxVO = null;
if (!filedChangeVOList1.stream().filter(filedChangeVO1 -> filedChangeVO1.getFiledName().contains(Min)).findFirst().isPresent()) {
// Min 值无变化 手动获取
filedChangeMinVO = getFiledChangeVO(beforeBean, filedNameReplaceMinMax, Min);
if (filedChangeMinVO == null) {
return;
}
} else {
filedChangeMinVO = filedChangeVOList1.stream().filter(filedChangeVO1 -> filedChangeVO1.getFiledName().contains(Min)).findFirst().get();
}
if (!filedChangeVOList1.stream().filter(filedChangeVO1 -> filedChangeVO1.getFiledName().contains(Max)).findFirst().isPresent()) {
// Max 值无变化 手动获取
filedChangeMaxVO = getFiledChangeVO(beforeBean, filedNameReplaceMinMax, Max);
if (filedChangeMaxVO == null) {
return;
}
} else {
filedChangeMaxVO = filedChangeVOList1.stream().filter(filedChangeVO1 -> filedChangeVO1.getFiledName().contains(Max)).findFirst().get();
}
String fileNameStr = filedChangeMinVO.getFileNameStr();
Object oldMin = filedChangeMinVO.getBeforeValue();
Object oldMax = filedChangeMaxVO.getBeforeValue();
Object newMin = filedChangeMinVO.getAfterValue();
Object newMax = filedChangeMaxVO.getAfterValue();
msgBuilder.append("修改" + fileNameStr + "\"" + oldMin + "-" + oldMax + "\"为\"" + newMin + "-" + newMax + "\";");
});
return msgBuilder.toString();
}
/**
* 获取变更内容
*
* @param <T>修改姓名"小白"为"小黑";修改年龄"10"为"20";
* @param beforeBean 更改前的Bean
* @param afterBean 更改后的Bean
* @return
*/
public static <T> List<FiledChangeVO> getChangedMoreFields(T beforeBean, T afterBean) {
List<FiledChangeVO> filedChangeVOList = new ArrayList<>();
Field[] fields = beforeBean.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (field.isAnnotationPresent(ForUpdate.class)) {
try {
String fieldName = field.getName();
Object beforeValue = field.get(beforeBean);
Object afterValue = field.get(afterBean);
if (!Objects.equals(beforeValue, afterValue)) {
String fieldNameStr = field.getAnnotation(ForUpdate.class).fieldName();
FiledChangeVO filedChangeVO = new FiledChangeVO(fieldName, fieldNameStr, beforeValue, afterValue);
filedChangeVOList.add(filedChangeVO);
}
} catch (Exception e) {
log.error( e.getMessage());
}
}
}
return filedChangeVOList;
}
/**
* 值无变化,获取属性值
*
* @param beforeBean
* @param filedNameReplaceMinMax
* @param minOrMax
* @param <T>
* @return
*/
public static <T> FiledChangeVO getFiledChangeVO(T beforeBean, String filedNameReplaceMinMax, String minOrMax) {
Field[] fields = beforeBean.getClass().getDeclaredFields();
if (!Arrays.stream(fields).filter(fie -> fie.getName().equals(filedNameReplaceMinMax + minOrMax)).findFirst().isPresent()) {
return null;
}
Field field = Arrays.stream(fields).filter(fie -> fie.getName().equals(filedNameReplaceMinMax + minOrMax)).findFirst().get();
String fieldNameStr = field.getAnnotation(ForUpdate.class).fieldName();
try {
field.setAccessible(true);
FiledChangeVO filedChangeVO = new FiledChangeVO(field.getName(), fieldNameStr, field.get(beforeBean), field.get(beforeBean));
return filedChangeVO;
} catch (IllegalAccessException e) {
log.error(e.getMessage());
}
return null;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
static class FiledChangeVO {
String filedName;// 属性字段
String fileNameStr;//属性字段中文意思
Object beforeValue;//字段原来值
Object afterValue;//字段更新后值
}
3. 测试
3.1 test
@Test
public void test() {
Bean beforeBean = new Bean(1L, "男", "小白", 1, 2, 3, 4);
Bean afterBean = new Bean(1L, "男", "小白", 5, 6, 7, 8);
String filedUpdateLog = filedUpdateLog(beforeBean, afterBean);
if (StringUtil.isNotBlack(filedUpdateLog)) {
String msg = filedUpdateLog;
System.out.println(msg);
}
}
3.2 运行结果
修改年龄"1-2"为"5-6";修改身高"3-4"为"7-8";