一、背景与问题
对于中后台系统中的数据都是非常重要的,但是如有人不小心修改了数据,异或有意而为之等等,这样都会对系统造成很大的影响,甚至对于公司可能也会造成一些影响。所以对于一个个重要的数据但凡谁去改动,都应该有详细的记录变更,就好比大家熟悉的git一样,任何变动都有对应的记录。
那么具体需要记录哪些呢?
- 时间:什么时候修改的
- 用户:具体谁修改的
- 设备:在哪个设备、ip等修改的
- 修改前:修改之前的数据
- 修改后:修改之后的数据
二、架构与思想
具体前端的架构设计请看前端数据变动记录设计 ;
对于后端而言我们应该做到如下:
- 对于一些简单变动,我们 只需记录一些 简单的字符串就可以
- 对于复杂javabean对象,我们需要进行 javabean对象的比较操作,比较的结果作为字符串存起来
- 任何数据都有: 新增、修改、删除 ;这三样类型应该默认提供
三、具体使用
3.1、定义数据业务类型
在DataTracerTypeEnum.java
中定义自己的业务类型,如下:
@AllArgsConstructor
@Getter
public enum DataTracerTypeEnum implements BaseEnum {
GOODS(1, "商品"),
OA_NOTICE(2, "OA-通知公告"),
OA_ENTERPRISE(3, "OA-企业信息");
private final Integer value;
private final String desc;
}
3.2、JavaBean注解
我们提供字段的如下几种注解用于 两个javabean之间的对象比较,生成满足git diff
格式的对比数据:
@DataTracerFieldBigDecimal
用于 BigDecimal 类型字段@DataTracerFieldDict
用于 字典 类型字段@DataTracerFieldEnum
用于 枚举 类型字段@DataTracerFieldLabel
用于 字段名称@DataTracerFieldSql
用于 sql 查询注入字段
比如:EnterpriseEntity.java
的javabean:
@Data
@TableName("t_oa_enterprise")
public class EnterpriseEntity {
@TableId(type = IdType.AUTO)
private Long enterpriseId;
@DataTracerFieldLabel("企业名称")
private String enterpriseName;
@DataTracerFieldLabel("企业logo")
private String enterpriseLogo;
@DataTracerFieldLabel("统一社会信用代码")
private String unifiedSocialCreditCode;
@DataTracerFieldLabel("类型")
@DataTracerFieldEnum(enumClass = EnterpriseTypeEnum.class)
private Integer type;
......
}
通过DataTracerService.getChangeContent(enterpriseDetail)
方法,可以拿到具体的对象内容
3.3、 新增、删除、修改
任何数据都有: 新增、修改、删除 ;这三样类型应该默认提供如下方法: DataTracerService.java
中,如下方法:
// 新增
DataTracerService.insert(1,DataTracerTypeEnum.GOODS); // 新增商品 记录
// 更新
DataTracerService.update(1,DataTracerTypeEnum.GOODS, oldGoods, newGoods); // 更新商品,传入新、旧 对象
// 删除
DataTracerService.delete(1,DataTracerTypeEnum.GOODS); // 删除商品 记录
DataTracerService.batchDelete(1,DataTracerTypeEnum.GOODS); // 批量删除商品 记录
3.4、其他记录
任何数据除了: 新增、修改、删除 ,还有其他操作记录,这个时候需要用到:
DataTracerService.addTrace(...); // 添加数据痕迹 方法
比如,企业信息中的调用EnterpriseService.updateEnterprise
方法中:
@Transactional(rollbackFor = Exception.class)
public ResponseDTO<String> updateEnterprise(EnterpriseUpdateForm updateVO) {
Long enterpriseId = updateVO.getEnterpriseId();
// 校验企业是否存在
EnterpriseEntity oldEnterprise = enterpriseDao.selectById(enterpriseId);
if (Objects.isNull(oldEnterprise) || oldEnterprise.getDeletedFlag()) {
return ResponseDTO.userErrorParam("企业不存在");
}
// 数据编辑
EnterpriseEntity newEnterprise = SmartBeanUtil.copy(oldEnterprise, EnterpriseEntity.class);
SmartBeanUtil.copyProperties(updateVO, newEnterprise);
enterpriseDao.updateById(newEnterprise);
//变更记录
DataTracerForm dataTracerForm = DataTracerForm.builder()
.dataId(updateVO.getEnterpriseId())
.type(DataTracerTypeEnum.OA_ENTERPRISE)
.content("修改企业信息")
.diffOld(dataTracerService.getChangeContent(oldEnterprise))
.diffNew(dataTracerService.getChangeContent(newEnterprise))
.build();
dataTracerService.addTrace(dataTracerForm);
return ResponseDTO.ok();
}
四、实现原理
4.1、表结构
t_data_tracer
表
其中 git diff
主要面向diff_old
和diff_new
两个字段的比较
4.2、解析Javabean
我们知道比较javabean对象
利用反射就可以解析,但是我们无法知道一些特殊事项:
- 比如
enterpriseName
字段的中文名称是什么意思?我们给用户显示总不能显示enterpriseName
,应该显示企业名称
字样 - 比如 对于一些枚举值,用户希望显示具体的中文含义,而不是 数值
- 比如 字典 字段,用户希望显示 字典的中文含义,而不是字典值
- 比如 关联关系id,用户希望显示 关联的对象信息,而不是 关联id
以上几个问题,我们使用几个注解来对应解决的,如下:
@DataTracerFieldBigDecimal 用于 BigDecimal 类型字段
@DataTracerFieldDict 用于 字典 类型字段
@DataTracerFieldEnum 用于 枚举 类型字段
@DataTracerFieldLabel 用于 字段名称
@DataTracerFieldSql 用于 sql 查询注入字段
具体如何解析这些注解,请看DataTracerChangeContentService.java
,具体代码
4.3、其他
整个datatracer
模块在 sa-base
项目中的 support.datatracer
包;
具体使用可以查看sa-admin
项目中的net.lab1024.sa.admin.module.business.oa.enterprise
包
outline: 'deep'
联系我们
1024创新实验室-主任:卓大,混迹于各个技术圈,研究过计算机,熟悉点 java,略懂点前端。
1024创新实验室(河南·洛阳) 致力于成为中原领先、国内一流的技术团队,以技术创新为驱动,合作各类项目(软件外包、技术顾问、培训等等)。
加微信: 卓大 拉你入群,一起学习 | 公众号 :六边形工程师 分享:赚钱、代码、生活 | 请 “1024创新实验室” “烩面里加肉” “ 咖啡配胡辣汤,提神又饱腹” | 抖音 : 六边形工程师 直播:赚钱、代码、中医 |