SpringBoot应用中利用AOP实现操作日志记录

本文首发在这里
本文代码在这里

引出问题

在web应用开发中,记录用户的操作日志是必不可少的,下面介绍一下利用AOP实现操作日志记录。

本文使用了Lombok,不懂的同学建议了解一下

引入依赖

首先构建一个SpringBoot项目,引入依赖


        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.projectlombok
            lombok
            true
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
        
        
            cn.hutool
            hutool-core
            LATEST
        
        
        
            org.aspectj
            aspectjweaver
            1.9.4
        
    

定义日志实体

这里只是列举了一些简单的字段

@Data
public class OperationLog {

    private Long id;
    private String operation;
    private Long operatTime;
    /**
     * 操作结果:0成功;-1失败
     */
    private Short operatType;
    /**
     * 异常日志
     */
    private String exceptionLog;
}

业务层

由于数据库操作并不是本文的重点,所以这里只是模拟数据库的新增操作。

public interface OperationLogService {

    /**
     * 新增日志
     * @param operationLog
     * @return
     */
    int insert(OperationLog operationLog);
}
@Service
public class OperationLogServiceImpl implements OperationLogService {
    @Override
    public int insert(OperationLog operationLog) {
        System.out.println(operationLog);
        System.out.println("日志新增成功");
        return 1;
    }
}

定义日志注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {

    String value();
}

切面的实现

@Aspect
@Component
public class LogAspect {

    @Autowired
    private OperationLogService operationLogService;

    @Pointcut(value = "@annotation(com.smile2coder.springboot.aspect.Log)")
    public void pointcut() {
    }

    @Around(value = "pointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed;
        try {
            proceed = pjp.proceed();
        } catch (Throwable throwable) {
            save(pjp, start, throwable);
            throw throwable;
        }
        save(pjp, start, null);
        return proceed;
    }

    private void save(ProceedingJoinPoint pjp, long start, Throwable throwable) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        try {
            Log annotation = method.getAnnotation(Log.class);
            String operation = annotation.value();

            OperationLog operationLog = new OperationLog();
            operationLog.setId(1L);
            operationLog.setOperation(operation);
            operationLog.setOperatTime(System.currentTimeMillis() - start);

            if (throwable == null) {
                operationLog.setOperatType((short)0);
            }else {
                operationLog.setOperatType((short)-1);
                //如果有异常,保存堆栈信息  
                operationLog.setExceptionLog(ExceptionUtil.stacktraceToString(throwable, 999));
            }

            this.operationLogService.insert(operationLog);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

控制层的应用

@RestController
public class TestController {

    @RequestMapping("/test")
    @Log(value = "这是一个测试接口")
    public String test() {
//        int i = 1/0;
        return "success";
    }
}

运行结果

正常结果:

OperationLog(id=1, operation=这是一个测试接口, operatTime=21, operatType=0, exceptionLog=null)
日志新增成功

异常结果:

OperationLog(id=1, operation=这是一个测试接口, operatTime=10, operatType=-1, exceptionLog=java.lang.ArithmeticException: / by zero
	at com.smile2coder.springboot.controller.TestController.test(TestController.java:18)
	at com.smile2coder.springboot.controller.TestController$$FastClassBySpringCGLIB$$d515e671.invoke()
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
	at com.smile2coder.springboot.aspect.LogAspect.around(LogAspect.java:39)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.r)
日志新增成功

本文中有什么错误,请联系我修改,十分感谢

本文的代码在这里

你可能感兴趣的:(SpringBoot,Java,aop,java,spring,boot)