应用场景:更新表单的时候需要记录更新了哪些内容
1. 创建对比修改的实体类ModifyLog
package com.kekePang.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
/**
* @Description: 修改记录
* @Author: kekePang
* @Date: 2022-02-23
* @Version: V1.0
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Builder
public class ModifyLog implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "主键")
private String id;
/**创建人*/
@Dict(dictTable = "sys_user",dicCode = "username",dicText ="realname")
@ApiModelProperty(value = "创建人")
private String createBy;
/**创建日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "创建日期")
private java.util.Date createTime;
/**更新人*/
@ApiModelProperty(value = "更新人")
private String updateBy;
/**更新日期*/
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "更新日期")
private java.util.Date updateTime;
/**修改栏位*/
@Excel(name = "修改栏位", width = 15)
@ApiModelProperty(value = "修改栏位")
private String modifiedField;
/**修改前的值*/
@Excel(name = "修改前的值", width = 15)
@ApiModelProperty(value = "修改前的值")
private String beforeModify;
/**修改后的值*/
@Excel(name = "修改后的值", width = 15)
@ApiModelProperty(value = "修改后的值")
private String afterModify;
/**实体ID*/
@ApiModelProperty(value = "修改后的值")
private String entityId;
/**实体表单*/
private String tableName;
}
2.创建对比修改需要的实体类ModifyInfo
package com.kekePang.utils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @Description //实体修改信息类
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ModifyInfo {
//修改字段
private String modifyField;
//修改前
private List<String> beforeModify;
//修改后
private List<String> afterModify;
//变更记录对应的实体表
private String tableName;
//变更记录对应的实体ID
private String entityId;
}
2.创建待修改的实体类
注意需要对比的字段上添加注解 @BeanContrast(fieldDesc="名称")
package com.kekePang.entity;
import lombok.Data;
import com.kekePang.utils.BeanContrast;
import java.util.Date;
/**
* @Description: 测试修改名称
* @Author: kekePang
* @Date: 2022-03-25
* @Version: V1.0
*/
@Data
public class Test{
private Long id;
@BeanContrast(fieldDesc="名称")
private java.lang.String name;
public void setName(String name) {
public String getName() {
return name;
}
}
3. 对比修改的工具类
package com.kekePang.utils;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.kekePang.DateUtils;
import com.kekePang.entity.Test;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
/**
* @Description //实体对象属性比较工具类
* @Author
**/
@Slf4j
public class BeanChangeUtils {
/**
* @param oldBean
* @param newBean
* @Description: 比较对象下同一属性的修改
* @Return: java.util.List<entity.ModifyInfo>
* @Author:
**/
public static List<ModifyLog> contrastObj(Object oldBean, Object newBean) {
Map<String, ModifyInfo> modifyInfos = new HashMap<>();
try {
// 通过反射获取类的类类型及字段属性
Class clazzOld = oldBean.getClass();
Class clazzNew = newBean.getClass();
if(getConfigs().get(clazzOld)==null){
throw new RuntimeException("请配置要记录的修改日志的实体的相关信息");
}
Field[] fields = clazzOld.getDeclaredFields();
String id = null;
String propertyNameValue = null;
for (Field field : fields) {
//获得entityId栏位要储存的值
PropertyDescriptor idField = new PropertyDescriptor((String)getConfigs().get(clazzOld)[1], clazzOld);
Method idMethod = idField.getReadMethod();
id = String.valueOf(idMethod.invoke(newBean));
ApiModelProperty propertyName = field.getAnnotation(ApiModelProperty.class);
if(propertyName!=null){
propertyNameValue = propertyName.value();
}
// 检查属性上有无 自定义对比 注解 -> 无则直接跳过
BeanContrast contrastAnnotation = field.getAnnotation(BeanContrast.class);
if (contrastAnnotation == null) {
continue;
}
//获取字段名描述
String modifyField = contrastAnnotation.fieldDesc();
PropertyDescriptor pdOld = new PropertyDescriptor(field.getName(), clazzOld);
PropertyDescriptor pdNew = new PropertyDescriptor(field.getName(), clazzNew);
// 获取对应属性值
Method getMethodOld = pdOld.getReadMethod();
Object o1 = getMethodOld.invoke(oldBean);
Method getMethodNew = pdNew.getReadMethod();
Object o2 = getMethodNew.invoke(newBean);
if (o1 == null && o2 == null) {
continue;
}
ModifyInfo modifyInfo = getModifiedValues(modifyInfos,clazzOld,id,"修改"+modifyField);
if (o1 == null) {
// o2不为null的情况
if (StringUtils.isNotBlank(o2.toString())) {
modifyInfo.getBeforeModify().add(propertyNameValue+"="+"");
modifyInfo.getAfterModify().add(propertyNameValue+"="+valueToString(o2));
}
} else {
// O1不为null
if (o2 == null) {
// o2为null的情况
if (StringUtils.isNotBlank(o1.toString())) {
modifyInfo.getBeforeModify().add(propertyNameValue+"="+valueToString(o1));
modifyInfo.getAfterModify().add(propertyNameValue+"="+"");
}
} else {
// o2 不为null的情况
if ((StringUtils.isNotBlank(o1.toString()) || StringUtils.isNotBlank(o2.toString())) && !compare(o1,o2)) {
modifyInfo.getBeforeModify().add(propertyNameValue+"="+valueToString(o1));
modifyInfo.getAfterModify().add(propertyNameValue+"="+valueToString(o2));
}
}
}
}
} catch (Exception e) {
log.error("对比实体变更信息失败:", e);
throw new RuntimeException("系统异常");
}
return generateEntity(modifyInfos);
}
private static boolean compare(Object oldVal,Object newVal){
if(oldVal instanceof BigDecimal){
return ((BigDecimal) oldVal).compareTo((BigDecimal) newVal) == 0;
}
return oldVal.equals(newVal);
}
private static String valueToString(Object value){
if(value == null){
return null;
}
if(value instanceof Date){
return DateUtils.formatDate((Date)value,"yyyy-MM-dd HH:mm:ss");
}
return String.valueOf(value);
}
private static ModifyInfo getModifiedValues(Map<String, ModifyInfo> map,Class clazz,String id, String fieldDesc) {
ModifyInfo values = map.get(fieldDesc);
if (values == null) {
values = ModifyInfo.builder()
.tableName(SqlHelper.table((Class)getConfigs().get(clazz)[0]).getTableName())
.modifyField(fieldDesc)
.entityId(id)
.afterModify(new ArrayList<>())
.beforeModify(new ArrayList<>()).build();
map.put(fieldDesc, values);
}
return values;
}
private static List<ModifyLog> generateEntity(Map<String, ModifyInfo> map){
List<ModifyLog> modifyLogs = new ArrayList<>();
for(Map.Entry<String,ModifyInfo> entry:map.entrySet()){
ModifyInfo mi = entry.getValue();
if(mi.getAfterModify().isEmpty()&&mi.getBeforeModify().isEmpty()){
continue;
}
ModifyLog modifyLog = ModifyLog.builder()
.modifiedField(mi.getModifyField())
.entityId(mi.getEntityId())
.tableName(mi.getTableName())
.afterModify(mi.getAfterModify().toString())
.beforeModify(mi.getBeforeModify().toString()).build();
modifyLogs.add(modifyLog);
}
return modifyLogs;
}
private static HashMap<Class,Object[]> configs;
public static HashMap<Class,Object[]> getConfigs(){
if(configs == null){
configs = new HashMap<>();
//key为要记录的实体的类,value为储存的相关关联信息[entityId栏位对应的实体,entityId要存的值对应的栏位]
configs.put(Test.class,new Object[]{Test.class,"id"});
}
return configs;
}
}
最后,我们可以在代码里使用
List<ModifyLog> ModifyLogs = BeanChangeUtils.contrastObj(oldOne, newOne);