天天看点

springboot AOP 切面配合自定义注解获取行为日志

获取swagger APIOperation上的注解,进行操作日志输出,非常方便。

1.自定义注解

//指明了修饰的这个注解的使用范围,即被描述的注解可以用在哪里
@Target(ElementType.METHOD)
//指明修饰的注解的生存周期,即会保留到哪个阶段(RUNTIME: 运行级别保留,编译后的class文件中存在,在jvm运行时保留,可以被反射调用)
@Retention(RetentionPolicy.RUNTIME)
//指明修饰的注解,可以被例如javadoc此类的工具文档化,只负责标记,没有成员取值
@Documented
public @interface RecordLog {

}
           

2.切面类

@Component
//把当前类标识为一个切面供容器读取
@Aspect
public class LogAspect {

    @Resource
    private SystemLogRepository logRepository;

    //客户端请求,大部分信息可以在这里面获取到
    @Resource
    private HttpServletRequest request;
    
    //将添加了RecordLog这个注解的地方作为一个切入点
    @Pointcut("@annotation(com.xxx.RecordLog)")
    public void logPointCut() {
    }

    /**
     * 方法正常退出时执行
     */
    @AfterReturning(pointcut = "logPointCut()")
    public void doAfterReturning(JoinPoint joinPoint) {
        try {
            saveLog(joinPoint, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //这个方法用于对切面获取到的数据进行处理,根据实际应用场景可以选择存到数据库或者打印到日志文件中
    private void saveLog(JoinPoint joinPoint, String e) throws Exception {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        //获取ApiOperation注解的value,同样的方法可以获取你加在切入点方法上的注解的各种参数      
        ApiOperation annotation = method.getAnnotation(ApiOperation.class);
        String userId = request.getParameter("userId");
        SystemOperationLog operationLog = new SystemOperationLog();
        operationLog.setOperationId(UUID.randomUUID().toString().replace("-", ""));
        operationLog.setTitle(annotation.value());
        //获取请求方法(POST、GET等)
        operationLog.setBusinessType(request.getMethod());
        //获取方法名
        operationLog.setOperationMethod(methodSignature.getName());
        operationLog.setUserId(userId);
        operationLog.setUrl(request.getRequestURL().toString());
        //获取调用方本地ip地址
        operationLog.setUserIp(InetAddress.getLocalHost().getHostAddress());
        //获取请求参数并转换成json格式
        operationLog.setOperationParam(JSON.toJSONString(joinPoint.getArgs()));
        operationLog.setStatus(e == null ? 0 : 1);
        operationLog.setErrorMessage(e);
        operationLog.setOperationTime(new Date());
        logRepository.save(operationLog);
    }

    /**
     * 方法抛出异常时执行
     */
    @AfterThrowing(pointcut = "logPointCut()", throwing = "exception")
    public void doAfterThrowing(JoinPoint joinPoint, Exception exception) {
        try {
            saveLog(joinPoint, exception.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
           

本篇文章中只用到了doAfterThrowing和doAfterReturning,通常根据业务场景选择切面方法在什么时候执行,以后用到其他场景再来更新

参考文章:

https://www.cnblogs.com/hyc-ana/p/9325618.html

https://www.cnblogs.com/jap6/p/10637429.html

https://blog.csdn.net/fz13768884254/article/details/83538709