1. 通过切面环绕通知获取方法访问前,后的参数来实现日志及业务数据变化
2. 前端实现数据列表查询
3. 业务数据对比,每一行数据根据当前的业务主键查询上一条业务数据,
通过两次的传输参数进行对比实现直观的数据变化
4. 此种方法缺点:
每次对比只能对比已有参数的变化,没有传输的无法对比,(可以通过找权限变化的数据来实现全部对比)
元数据注解
/**
* 操作日志注解
*
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogOperation {
String value() default "";
/**
* 传参中已有业务主键
* @return
*/
String primaryKey() default "id";
/**
* 返回参数中已有业务主键,JSON字符串中多层嵌套,自定义 如 data.id
* @return
*/
String resultPrimaryKey() default "data";
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
切面实现类
/**
* 操作日志,切面处理类
*/
@Aspect
@Component
public class LogOperationAspect {
@Autowired
private SysLogOperationService sysLogOperationService;
@Pointcut("@annotation(com.mv.common.annotation.LogOperation)")
public void logPointCut() {
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
long beginTime = System.currentTimeMillis();
Object result = null;
try {
//执行方法结果
result = point.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//保存日志
saveLog(point, time, OperationStatusEnum.SUCCESS.value(), result);
return result;
} catch (Exception e) {
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
//保存日志
saveLog(point, time, OperationStatusEnum.FAIL.value(), result);
throw e;
}
}
private void saveLog(ProceedingJoinPoint joinPoint, long time, Integer status, Object result) throws Exception {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(), signature.getParameterTypes());
LogOperation annotation = method.getAnnotation(LogOperation.class);
SysLogOperationEntity log = new SysLogOperationEntity();
String primaryKey = null;
String resultPrimaryKey = null;
if (annotation != null) {
//注解上的描述
log.setOperation(annotation.value());
primaryKey = annotation.primaryKey();
resultPrimaryKey = annotation.resultPrimaryKey();
}
//登录用户信息
UserDetail user = SecurityUser.getUser();
if (user != null) {
log.setCreatorName(user.getUsername());
}
log.setStatus(status);
log.setRequestTime((int) time);
//请求相关信息
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
if (null == request) {
return;
}
log.setIp(IpUtils.getIpAddr(request));
log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
log.setRequestUri(request.getRequestURI());
log.setRequestMethod(request.getMethod());
//请求参数
Object[] args = joinPoint.getArgs();
try {
String params = JSON.toJSONString(args[0]);
log.setRequestParams(params);
// 业务主键获取
String tableKey = getTabkeKey(params, result, primaryKey, resultPrimaryKey);
log.setBusinessId(tableKey);
//判断参数 是否等于uri最后一个参数一样
String[] paths = log.getRequestUri().split("/");
if (paths[paths.length - 1].equals(params)) {
log.setRequestUri(log.getRequestUri().replaceAll(params, ""));
}
} catch (Exception e) {
}
//保存到DB
sysLogOperationService.save(log);
}
private String getTabkeKey(String params, Object result, String primaryKey, String resultPrimaryKey) {
try {
JSONObject json = JSONObject.parseObject(params);
String tableKey = null == json.get(primaryKey) ? null : json.get(primaryKey).toString();
if (StringUtils.isEmpty(tableKey)) {
json = JSONObject.parseObject(JSON.toJSONString(result));
if (resultPrimaryKey.contains(":")) {
String[] keys = resultPrimaryKey.split(":");
for (int i = 0; i < keys.length; i++) {
if (i == keys.length - 1) {
tableKey = null == json.get(keys[i]) ? null : json.get(keys[i]).toString();
} else {
json = json.getJSONObject(keys[i]);
}
}
} else {
tableKey = null == json.get(resultPrimaryKey) ? null : json.get(resultPrimaryKey).toString();
}
}
return tableKey;
} catch (Exception e) {
return null;
}
}
}
- 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
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
实体类
/**
* 操作日志
*
* @since 1.0.0
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("sys_log")
public class SysLogOperationEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 用户操作
*/
private String operation;
/**
* 请求URI
*/
private String requestUri;
/**
* 请求方式
*/
private String requestMethod;
/**
* 请求参数
*/
private String requestParams;
/**
* 业务主键
*/
private String businessId;
/**
* 请求时长(毫秒)
*/
private Integer requestTime;
/**
* 用户代理
*/
private String userAgent;
/**
* 操作IP
*/
private String ip;
/**
* 状态 0:失败 1:成功
*/
private Integer status;
/**
* 用户名
*/
private String creatorName;
}
- 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
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51