本文首发在这里
本文代码在这里
在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)
日志新增成功
本文中有什么错误,请联系我修改,十分感谢
本文的代码在这里