需求说明
工作中,经常会有业务会要求展示某个业务字段的变更信息或变更流水线,为方便,对不同业务表也能使用同样的数据结构,因此需要构建一个公共日志记录类型来处理。
思路
通过java自带反射、注解简单记录。
1.创建公共日志记录表
2.通过反射、注解获取新旧记录自定义字段名称和字段值等
3.比较新旧记录,拼接日志
代码实现
1.表及数据结构设计
字段 | 名称 | 备注 |
---|---|---|
logNo | 日志编号 | 日志主键 |
businessType | 业务类型 | 自定义业务类型 |
businessNo | 业务编号 | 具体关联的业务编号 |
changeDate | 修改时间 | YYYY-MM-DD |
changeContent | 修改内容 | 每个字段变更都是一个JONS格式。 |
remark | 备注 | |
createTime | 创建时间 | YYYY-MM-DD hh:mm:sss |
creatorId | 创建人Id | |
creatorName | 创建人名称 |
注:changeContent修改内容数据格式如下:
[
{
"field": "字段英文名",
"fieldName": "字段名称",
"oldValue": "变更前的值",
"newValue": "变更后的值",
"content": "变更内容拼接(自定义拼接,比如:成立日期-20220101 --> 调整为 --> 成立日期-20220106"
}
]
2.核心代码
(1)自定义注解
/**
* 自定义属性名称
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldName {
/**
* 字段名称
* @return
*/
String value();
/**
* 解析时是否忽略空值
* @return
*/
boolean isIgnoreNull() default false;
}
(2)字段使用注解示例
/**
* 成立日期
*/
@FieldName("成立日期")
private String startDate;
/**
* 费率
*/
@FieldName("费率")
private String rate;
@FieldName(value = "ID",isIgnoreNull = true)
private String id;
(3)日志保存
/**
* 保存修改日志
* @param newObj 更新后数据
* @param oldObj 更新前数据
* @param businessType 业务类型
* @param businessNo 业务主键
* @param clazz
* @return
*/
public int saveLog(Object newObj, Object oldObj, String businessType, String businessNo, Class clazz) {
if (newObj == null || oldObj == null) {
return 0;
}
//这里对应上面日志表实体类
BusinessChangeLog log = new BusinessChangeLog();
//通过hutool BeanUtil工具将实体类转换为Map
Map newMap = BeanUtil.beanToMap(newObj);
Map oldMap = BeanUtil.beanToMap(oldObj);
//通过类对象获取类字段
Field[] fields = clazz.getDeclaredFields();
Map<String, Map> changeMap = new HashMap<>();
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();
String changeField;
Map<String, String> conMap = new HashMap<>();
//新旧记录内容不同,说明是修改过,因此记录起来
if (!StringUtils.equals(newValue, oldValue)) {
//CHANGE_TEXT 自定义拼接内容
//CHANGE_TEXT = "fieldName-oldValue --> 调整为 --> fieldName-newValue"
changeField = CHANGE_TEXT.replaceAll("fieldName", fieldName.value())
.replaceAll("oldValue", oldValue)
.replaceAll("newValue", newValue);
conMap.put("field", field.getName());
conMap.put("fieldName",fieldName.value());
conMap.put("newValue", newValue);
conMap.put("oldValue", oldValue);
conMap.put("content", changeField);
changeMap.put(field.getName(), conMap);
}
}
}
log.setBusinessType(businessType);
log.setBusinessNo(businessNo);
if (!changeMap.isEmpty()) {
log.setChangeContent(JSON.toJSONString(changeMap.values()).replaceAll("\\\\",""));
}
log.setCreatorId(SessionUtil.getUser().getEmpId());
log.setCreatorName(SessionUtil.getUserName());
//入库(需要自己实现入库代码编写)
return logMapper.insertLog(log);
}