springboot集成aop实现日志
1. 添加依赖
<!-- aop 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActionLog {
String action() default "";
String topic() default "";
}
3. 定义切面类
import com.cnhqd.authcenter.framework.common.utils.IpUtils;
import com.cnhqd.authcenter.framework.common.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Slf4j
@Aspect
@Component
public class ActionLogAspect {
@Pointcut("@annotation(com.cnhqd.authcenter.framework.common.log.ActionLog)")
public void actionLog() {
}
/*** 在切点之前织入* @param joinPoint* @throws Throwable*/
@Before("actionLog()")
public void doBefore(JoinPoint joinPoint) throws Exception {
// 开始打印请求日志
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();// 打印请求相关参数
log.info("=================== Start ====================");
// 打印请求url
log.info("URL : {}", request.getRequestURL().toString());
// 打印Httpmethod
log.info("HTTP Method : {}", request.getMethod());
// 打印调用 controller 的全路径以及执行方法
log.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
// 打印请求的IP
log.info("IP : {}", IpUtils.getIpAddr(request));
// 打印请求入参
log.info("Request Args : {}", JsonUtils.toJsonString(joinPoint.getArgs()));
ActionLog annotation = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(ActionLog.class);
log.info("topic :{}", annotation.topic());
log.info("action :{}", annotation.action());
}
@AfterReturning("actionLog()")
public void afterReturning(){
log.info("result :{}", 200);
log.info("=================== End ====================");
}
@AfterThrowing(pointcut = "actionLog()", throwing = "ex")
public void afterThrowing(Throwable ex) {
log.info("result :{}", ex.getMessage());
log.info("=================== End ====================");
}
}
各注解说明:
@Aspect:声明该类为一个注解类;
@Pointcut:定义一个切点,后面跟随一个表达式,表达式可以定义为某个 package 下的方法,也可以是自定义注解等;
@Before: 在切点之前,织入相关代码;
@After: 在切点之后,织入相关代码;
@AfterReturning: 在切点返回内容后,织入相关代码,一般用于对返回值做些加工处理的场景;
@AfterThrowing: 用来处理当织入的代码抛出异常后的逻辑处理;
@Around: 在切入点前后织入代码,并且可以自由的控制何时执行切点;
4. 简单测试
编写测试controller
import com.cnhqd.authcenter.framework.common.log.ActionLog;
import com.cnhqd.authcenter.system.vo.SysAccountLoginVO;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("testAops")
public class TestAopsController {
@GetMapping("get")
@ActionLog(action = "get", topic = "测试AOP")
public String get(String id) {
return id;
}
@PostMapping("post")
@ActionLog(action = "post", topic = "测试AOP")
public String post(@RequestBody SysAccountLoginVO vo) {
System.out.println(JsonUtils.toJsonString(vo));
return "success";
}
@GetMapping("getEx")
@ActionLog(action = "getEx", topic = "测试AOP")
public String getEx() {
throw new RuntimeException("getEx-这里是异常输出测试");
}
@PostMapping("postEx")
@ActionLog(action = "postEx", topic = "测试AOP")
public String postEx() {
throw new RuntimeException("postEx-这里是异常输出测试");
}
}
使用postman发送对应请求,观察控制台输出
可以看到日志可以正常输出,如有必要保存相关数据到数据库即可。