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 ====================");// 打印请求urllog.info("URL : {}", request.getRequestURL().toString());// 打印Httpmethodlog.info("HTTP Method : {}", request.getMethod());// 打印调用 controller 的全路径以及执行方法log.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());// 打印请求的IPlog.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发送对应请求,观察控制台输出
可以看到日志可以正常输出,如有必要保存相关数据到数据库即可。