【操作日志】如何在一个SpringBoot+Mybatis的项目中设计一个自定义ChangeLog记录?
设计一个业务改动信息时的自定义记录,例如新增、修改、删除数据等。并且记录的规则可以通过配置的方式控制。大家需要根据各自业务场景参考,欢迎讨论。伪代码如下:
实体类:
@TableName("tbl_user")
User{
String id
String name
Integer age
String addr
}
DAO层:
UserDao{
getById(Long id);
list(Wrapper wrapper);
}
自定义注解:
MybatisPropAnno{ String value Class<?> daoClazz }
Http接口请求参数:
SaveReq{ @MybatisPropAnno(value="name", daoClazz = UserDao.class) String userName; @MybatisPropAnno(value="age", daoClazz = UserDao.class) Integer userAge; } UpdateReq{ @MybatisPropAnno(value="id", daoClazz = UserDao.class) String userNo; @MybatisPropAnno(value="name", daoClazz = UserDao.class) String userName; @MybatisPropAnno(value="age", daoClazz = UserDao.class) Integer userAge; @MybatisPropAnno(value="id", daoClazz = DepartDao.class) String departId; String departAddress; }
Http接口:
TestController{ public void save(SaveReq saveReq){ operTypeInheritedThreadLocal.set(Enum."添加数据"); sthInheritedThreadLocal.set(saveReq); }; public void update(UpdateReq updateReq){ operTypeInheritedThreadLocal.set(Enum."更新数据"); sthInheritedThreadLocal.set(updateReq); }; @MybatisLogAnno("删除数据") public void delete(){}; @MybatisLogAnno("查询数据") public void query(){}; public void other(){}; }
SQL拦截器:
SqlInterceptor{ public Object intercept(Mybatis param){ OperType operType = operTypeInheritedThreadLocal.get if(operType == null){ return ; } // insert/update/delete/select String type = param.getSqlType(); if(operType == select){ return ; } String sql = param.getSql(); String tableName = sql.getTableName(); List<Field> fields = Reflect.getFields(sthInheritedThreadLocal.get()); for(Field field : fields){ MybatisPropAnno propAnno = field.getAnnotation(MybatisPropAnno); if(propAnno == null){ continue; } if(propAnno.getDaoClazz.getEntity.getTableName.equals(tableName )){ User oldUser = new JSONObject(); User newUser = new JSONObject(); if(type == insert){ oldUser = new JSONObject(); newUser = getInsertInfo(sql); } if(type == update){ oldUser = SpringContext.get(daoClazz).getById(field.value()); newUser = getUpdateInfo(sql); insertChangeLog(new JSONObject(), JSON.toJson(newUser)); } if(type == delete){ oldUser = SpringContext.get(daoClazz).getById(field.value()); newUser = new JSONObject(); } insertChangeLog(operType, traceId, oldUser, newUser); break; } } } }
Spring切面:
SpringAop { public Object doAround(){ operTypeInheritedThreadLocal.remove } }
数据库设计:
Table:dc_change_log
id changeTime changeType traceId oldInfo newInfo httpMethod table operator changeDesc
1 2020-01-01 添加用户 123 {} {"name":"lil"} com.xx.TestCtrl.saveUser tbl_user admin descxxxxxxxxxxxx
2 2020-01-01 修改用户 124 {"name":"lil"} {"name":"a"} com.xx.TestCtrl.updateUser tbl_user admin descxxxxxxxxxxxx
3 2020-01-01 修改用户 124 {"addr":"南山"} {"addr":"福田"} com.xx.TestCtrl.updateUser tbl_department admin descxxxxxxxxxxxx
Table:dc_change_rule
id httpMethod table showRule
1 com.xx.TestCtrl.saveUser tbl_user [{"propKey":"name", "propDesc":"name detail info"}]
1 com.xx.TestCtrl.updateUser tbl_user [{"propKey":"name", "propDesc":"name detail info"}]
1 com.xx.TestCtrl.updateUser tbl_department [{"propKey":"addr", "propDesc":"addr detail info"}]