数据变更记录

9/1/2022

# 一、背景与问题

对于中后台系统中的数据都是非常重要的,但是如有人不小心修改了数据,异或有意而为之等等,这样都会对系统造成很大的影响,甚至对于公司可能也会造成一些影响。所以对于一个个重要的数据但凡谁去改动,都应该有详细的记录变更,就好比大家熟悉的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;
}
1
2
3
4
5
6
7
8
9
10
11

# 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;
    
    ......
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

通过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); // 批量删除商品 记录
1
2
3
4
5
6
7

# 3.4、其他记录

任何数据除了: 新增、修改、删除 ,还有其他操作记录,这个时候需要用到:

DataTracerService.addTrace(...); // 添加数据痕迹  方法
1

比如,企业信息中的调用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();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 四、实现原理

# 4.1、表结构

t_data_tracer

其中 git diff 主要面向diff_olddiff_new 两个字段的比较

# 4.2、解析Javabean

我们知道比较javabean对象利用反射就可以解析,但是我们无法知道一些特殊事项:

  • 比如 enterpriseName字段的中文名称是什么意思?我们给用户显示总不能显示enterpriseName,应该显示企业名称字样
  • 比如 对于一些枚举值,用户希望显示具体的中文含义,而不是 数值
  • 比如 字典 字段,用户希望显示 字典的中文含义,而不是字典值
  • 比如 关联关系id,用户希望显示 关联的对象信息,而不是 关联id

以上几个问题,我们使用几个注解来对应解决的,如下:

@DataTracerFieldBigDecimal 用于 BigDecimal 类型字段
@DataTracerFieldDict 用于 字典 类型字段
@DataTracerFieldEnum 用于 枚举 类型字段
@DataTracerFieldLabel 用于 字段名称
@DataTracerFieldSql 用于 sql 查询注入字段
1
2
3
4
5

具体如何解析这些注解,请看DataTracerChangeContentService.java具体代码 (opens new window)

# 4.3、其他

整个datatracer模块在 sa-common项目中的 support.datatracer包;
具体使用可以查看sa-admin项目中的net.lab1024.sa.admin.module.business.oa.enterprise


# 联系我们

1024创新实验室-主任:卓大 (opens new window),混迹于各个技术圈,研究过计算机,熟悉点 java,略懂点前端。
1024创新实验室(河南·洛阳) (opens new window) 致力于成为中原领先、国内一流的技术团队,以技术创新为驱动,合作各类项目。

加 主任 “卓大” 微信
拉你入群,一起学习
关注 “小镇程序员”
分享代码与生活、技术与赚钱
请 “1024创新实验室” 喝咖啡
支持我们的开源与分享

告白气球 (钢琴版)
JESSE T