数据业务级⽇志记录业务操作前后数据(springBoot)续    关于这个级别的⽇志,上次讲了2个⽅案:
1、aop切⾯,使⽤环绕事件,在proceed()前后分别处理,组织操作前后的参数
2、提供公⽤的⼯具类⽅法,开启线程处理
今天主要是再补充下⽅案1,⽅案⼀其实可以增加⼀个声明注解,接⼝⽅法上注解,描述⽅法的具体作⽤。看硬货:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OperateLogAnno {
/**
* ⽇志描述
*springboot aop
* @return
*/
String logDesc();
}
增加⼀个上⾯这样的声明类。然后⽅法名上注解:
@OperateLogAnno(logDesc = "操作描述说明")
剩下就是aop切⾯类了:
@Around("addPointcut() || updatePointcut()")
public Object Around(ProceedingJoinPoint pjp) throws Throwable {
Signature sig = Signature();
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("该注解只能⽤于⽅法");
}
MethodSignature msig = (MethodSignature) sig;
Object target = Target();
Method currentMethod = Class().Name(), ParameterTypes());
// 类名
String targetName = Class().getSimpleName();
// ⽅法名
String methodName = Name();
Object[] args = Args();
// ⽅法的第1个参数
Object model = args[0];
Class modelClass = Class();
// 查询ID
Integer id = null;
// 需要通过反射获取的Mapper类
Mapper<Object> mapper = null;
// 更新前数据⾏
String beforeJson = "{}";
// 更新后数据⾏
String afterJson;
// 是否要记录数据⾏⽇志
boolean need = false;
/
/ 是否是新增操作,默认为新增
boolean isAdd = true;
OperateLogAnno anno = Annotation(OperateLogAnno.class);
if (anno != null) {
need = true;
}
if (need) {
// 获取查询ID
Method getId = Method("getId");
id = Integer.class.cast(getId.invoke(model));
if (id != null && id > 0) {
isAdd = false; // 修改操作
}
targetName = targetName.substring(0, targetName.indexOf("ServiceImpl"));
String mapperName = (new StringBuilder()).LowerCase(targetName.charAt(0)))                .append(targetName.substring(1)).toString() + "Mapper";
mapper = Bean(mapperName);
}
if (need) {
Object before;
// 修改操作,先取出未修改的数据⾏
if (!isAdd) {
before = mapper.selectByPrimaryKey(id);
} else {
before = "{}";
}
beforeJson = JSONString(before);
}
// 执⾏原始⽅法
Object object = pjp.proceed();
Result<?> result = (Result<?>) object;
// 返回值异常,直接返回结果
if (Code() != de()) {
return result;
}
if (need) {
// 新增操作,从返回结果中获取数据⾏id
if (isAdd) {
Result<Integer> addResult = (Result<Integer>) object;
id = Data();
}
if (id != null && id > 0) {
Object after = mapper.selectByPrimaryKey(id);
afterJson = JSONString(after);
Class clazz = Class();
/
/ 机构ID
Integer orgId = 0;
try {
Method getOrgId = Method("getOrgId");
orgId = Integer.class.cast(getOrgId.invoke(after));
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.info("对象{}没有⽅法getOrgId,设置默认值", SimpleName());
}
// 项⽬ID
Integer subjectId = 0;
try {
Method getSubjectId = Method("getSubjectId");
subjectId = Integer.class.cast(getSubjectId.invoke(after));
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.info("对象{}没有⽅法getSubjectId,设置默认值", SimpleName());
}
// 创建者ID
Integer createBy = BusinessConstant.CREATE_BY_DEFAULT;
try {
Method getCreateBy = Method("getCreateBy");
createBy = Integer.class.cast(getCreateBy.invoke(model));
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.info("对象{}没有⽅法getCreateBy设置默认值", SimpleName());
}
// 更新者ID
Integer updateBy = BusinessConstant.CREATE_BY_DEFAULT;
try {
Method getUpdateBy = Method("getUpdateBy");
updateBy = Integer.class.cast(getUpdateBy.invoke(model));
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.info("对象{}没有⽅法getUpdateBy设置默认值", SimpleName());
}
//记录数据业务级⽇志
OperateLogUtil.sendOperateLog(afterJson, beforeJson, orgId, subjectId, targetName, anno.logDesc(),
methodName, isAdd ? createBy : updateBy);
}
}
return result;
}
上⾯这个⽅法是以Object object = pjp.proceed();这⾏为界,前⾯组织操作前的json字符串,后⾯组织操作后的json字符串。当然都是通过反射获取对应的mapper,从参数⾥取id,然后查询,组织参数。保存依然是调⽤的开启线程保存⽇志的公共⽅法。
到这⾥就没有什么其他可说的了,关键点都跟⼤家分享了。下⾯总结下这个⽅案的优劣吧。
1、在proceed()前后写的代码,没有开启线程,肯定对接⼝响应有影响
2、只能单表操作
第1点可以使⽤多线程,前后分别开线程,ThreadLocal 配合CountDownLatch在调⽤保存⽇志⽅法,减少对接⼝响应的影响。
第2点那⼏乎就是⽆解了。除⾮将⼀个⽅法⾥的多表操作拆分成多个⽅法,⼀个⽅法⾥只操作⼀张表,如果操作多表就⼀个⽅法⾥调⽤多个⽅法,不知道这样是否可⾏,没有实际试验。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。