最近有个新需求,就是要实现某个任务的追溯功能,就是这个任务的任何属性对应的值在编辑前后都需要记录下,记录下是谁在那个时间修改了该任务的什么值。
我的需求是在长链接的时候,某人修改了任务的某个属性需要实时通知其他在线人员,所以我需要在修改任务,删除任务,新增任务这个三个长链接里面添加操作记录,记录新增,删除,修改的操作,并且修改又包括修改任务进度,修改任务名称,修改任务状态等。
原文链接:
操作日志应记录编辑的前后内容变化_java记录修改前后信息-CSDN博客
首先感谢原文作者,在原有代码做了一点点小的修改,作为记录。直接贴代码
一.表结构设计
主键id,任务id,操作者,操作详情(值的前后变化或者删除或者新增),操作类型(新增任务,删除任务,修改任务)
二.总体思路是增加一个注解类,将注解加到要进行记录变化的Java类属性上却可。
1. 实现注解类:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldName {
String value();
boolean isIgnoreNull() default false;
}
2. 将注解加到Java类需要记录修改的属性
@ApiModelProperty(value = "任务名称")
@FieldName("任务名称")
private String taskName;
@ApiModelProperty(value = "该任务的负责人")
@FieldName("该任务的负责人")
private Long taskUserId;
@ApiModelProperty(value = "优先级")
@FieldName("优先级")
private String priority;
@FieldName("任务进度")
private Integer taskProgress;
3. 写一个LogUtil类,对新旧对象进行比较,将变化的内容记录下来,返回List<String>,为了防止异常出现影响正常的业务,用try-catch进行异常处理。
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.piesat.space.project.socket.annotation.FieldName;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
@Slf4j
public class LogUtil {
private static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
/**
* 记录修改信息
* @param newObj 当前最新的数据,将要update到数据库的数据
* @param oldObj 更新前数据, 一般是已经保存到数据库的数据,在update前从数据库查询获得
* @param clazz
* @return
*/
public static List<String> getUpdateContentList(Object newObj, Object oldObj, Class clazz) {
List<String> contentList = new ArrayList<>();
if (newObj == null || oldObj == null) {
return contentList;
}
try {
//通过hutool BeanUtil工具将实体类转换为Map
Map newMap = BeanUtil.beanToMap(newObj);
Map oldMap = BeanUtil.beanToMap(oldObj);
//通过类对象获取类字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//判断是否有FieldName注解
if (field.isAnnotationPresent(FieldName.class)) {
FieldName fieldName = field.getAnnotation(FieldName.class);
//空的和忽略的字段不进行处理
if (fieldName.isIgnoreNull() && ObjectUtil.isEmpty(newMap.get(field.getName()))) {
continue;
}
String newValue = newMap.get(field.getName()) == null ? "" : newMap.get(field.getName()).toString();
String oldValue = oldMap.get(field.getName()) == null ? "" : oldMap.get(field.getName()).toString();
if(field.getType() == Date.class){
try{
if(StringUtils.isNotEmpty(newValue)){
newValue = formatter.format(newMap.get(field.getName()));
}
if(StringUtils.isNotEmpty(oldValue)){
oldValue = formatter.format(oldMap.get(field.getName()));
}
}catch (Exception e){
e.printStackTrace();
}
}
String changeField;
Map<String, String> conMap = new HashMap<>();
//新旧记录内容不同,说明是修改过,因此记录起来
if (!newValue.equals(oldValue)) {
//CHANGE_TEXT 自定义拼接内容
//CHANGE_TEXT = "fieldName-oldValue --> 调整为 --> fieldName-newValue"
String CHANGE_TEXT = "fieldName:oldValue --> newValue";
changeField = CHANGE_TEXT.replaceAll("fieldName", fieldName.value())
.replaceAll("oldValue", oldValue)
.replaceAll("newValue", newValue);
log.info(changeField);
contentList.add(changeField);
}
}
}
}catch (Exception e){
e.printStackTrace();
}
return contentList;
}
}
4.一切准备就结果,接下来就是具体使用:
我的调用方式:
/**
* 获取编辑前后的变化内容
*/
public List<String> getUpdateTaskList(SpaceManageTask task) {
// product代表新数据,将要被update到数据库中
// oldObject 是数据库中的数据,用以跟新的数据进行比较
SpaceManageTask oldTask = taskMapper.getTaskById(task.getSpaceManageTaskId());
return LogUtil.getUpdateContentList(task, oldTask, SpaceManageTask.class);
}
//记录修改操作
List<String> updateContentList =taskService.getUpdateTaskList(task);
String updateContent = "修改任务";
if(!updateContentList.isEmpty()){
updateContent += ": "+updateContentList;
}
// 日志记录的service类新建一条更新日志
SpaceManageHistory history = new SpaceManageHistory();
history.setSpaceManageHistoryId(SnowflakeIdWorker.generateId());
history.setSpaceManageTaskId(task.getSpaceManageTaskId());
history.setSpaceManageMilestoneId(task.getSpaceManageMilestoneId());
history.setSpaceManageProjectId(task.getSpaceManageProjectId());
history.setOperator(spaceManageProjectDto.getOperatorId());
history.setOperateType("编辑");
history.setDetail(updateContent);
//基础字段赋值
history.setInsertTime(LocalDateTime.now());
history.setUpdateTime(LocalDateTime.now());
history.setInsertedBy(spaceManageProjectDto.getHhxsUserId());
history.setUpdatedBy(spaceManageProjectDto.getHhxsUserId());
history.setVersion("3.0.0");
history.setLogicDelete(0);
historyService.saveHistoryRecord(history);
//修改项目名称
taskService.updateTask(task);
...长链接操作
原作者的调用方式:
在Controller类的edit请求中:
// 某个Controller的edit方法中, 此处的product是新数据,一般是前端传回来的数据
List<String> updateContentList = getUpdateContentList(product);
String updateContent = "修改产品";
if(!updateContentList.isEmpty()){
updateContent += ": "+updateContentList;
}
// 日志记录的service类新建一条更新日志
updateRecordService.setProductUpdateRecord(product.getId(), "编辑", updateContent);
/**
* 获取编辑前后的变化内容
*/
private List<String> getUpdateContentList(Product product){
// product代表新数据,将要被update到数据库中
// oldObject 是数据库中的数据,用以跟新的数据进行比较
Product oldObject = productService.getById(product.getId());
return LogUtil.getUpdateContentList(product, oldObject, Product .class);
}
最后的效果如图: