通过切面日志实现业务数据历史变更

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";
}

切面实现类

/**
 * 操作日志,切面处理类
 */
@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;
        }
    }
}

实体类

/**
 * 操作日志
*
 * @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;
}

你可能感兴趣的:(spring,boot)