添加依赖
视情况添加spring-boot-starter-aop依赖。
配置AOP切面
常用注解作用:
@Aspect:声明该类为一个注解类;
@Pointcut:定义一个切点,后面跟随一个表达式,表达式可以定义为某个 package 下的方法,也可以是自定义注解等;
切点定义好后,就是围绕这个切点做文章了:
@Before: 在切点之前,织入相关代码;
@After: 在切点之后,织入相关代码;
@AfterReturning: 在切点返回内容后,织入相关代码,一般用于对返回值做些加工处理的场景;
@AfterThrowing: 用来处理当织入的代码抛出异常后的逻辑处理;
@Around: 在切入点前后织入代码,并且可以自由的控制何时执行切点;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.OutputStream;
//@Component
//@Aspect
@Slf4j
public class WebLogAspect {
@Autowired
protected ObjectMapper objectMapper;
// @Pointcut("execution(public * com.guomz.shangyitong.controller..*.*(..))" +
// "&& !execution(public * com.guomz.shangyitong.cmn.controller.DictController.exportDict(..))" +
// "&& !execution(public * com.guomz.shangyitong.cmn.controller.DictController.importData(..))")
public void webLog(){
}
/**
* 在切点之前织入
* @param joinPoint
* @throws Throwable
*/
@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 开始打印请求日志
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 打印请求相关参数
log.info("========================================== Start ==========================================");
// 打印请求 url
log.info("URL : {}", request.getRequestURL().toString());
// 打印 Http method
log.info("HTTP Method : {}", request.getMethod());
// 打印调用 controller 的全路径以及执行方法
log.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
// 打印请求的 IP
log.info("IP : {}", request.getRemoteAddr());
//输出cookie
printCookie(request);
// 输出url请求入参
log.info("queryString : {}", request.getQueryString());
// 打印请求入参
if (joinPoint.getArgs() != null){
logInputArgs(joinPoint.getArgs());
}
}
/**
* 在切点之后织入
* @throws Throwable
*/
@After("webLog()")
public void doAfter() throws Throwable {
log.info("=========================================== End ===========================================");
// 每个请求之间空一行
log.info("");
}
/**
* 环绕
* @param proceedingJoinPoint
* @return
* @throws Throwable
*/
@Around("webLog()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = proceedingJoinPoint.proceed();
// 打印出参
if (result != null && !(result instanceof OutputStream)){
log.info("Response Args : {}", objectMapper.writeValueAsString(result));
}
// 执行耗时
log.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
return result;
}
/**
* 输出cookie信息
* @param request
*/
protected void printCookie(HttpServletRequest request){
if (request.getCookies() != null){
for (Cookie cookie : request.getCookies()) {
log.info("cookie: {}, {}", cookie.getName(), cookie.getValue());
}
}else {
log.info("无cookie信息");
}
}
/**
* 输出入参
* @param args
* @throws JsonProcessingException
*/
protected void logInputArgs(Object args[]) throws JsonProcessingException {
for (Object arg : args) {
if (arg instanceof MultipartFile ||
arg instanceof HttpServletRequest){
continue;
}
log.info("Request Args : {}", objectMapper.writeValueAsString(arg));
}
}
}
在切点注解中对controller包下的全部方法进行了植入,JSONUtil为自己实现的json序列化工具。printCookie()方法为输出请求中的cookie信息,hasMultipartInput()为判断请求参数中是否包含流,包含流则无法被序列化。
注意
如果该类被多个项目作为依赖引用,则需要注意@Pointcut注解配置的类与方法是否在当前项目中存在,不存在会启动报错。可以公共提取一个切面,然后在不同项目中继承重写被标注@Pointcut的方法,进行切点的自定义。上面的示例中这个类是一个基类,在其他模块中可以再创建其他切面类去继承。
如果controller方法存在使用HttpServletResponse.getOutputStream()
进行文件下载,则需要进行方法排除不进行拦截,否则会报错。
本文引用自:
Spring Boot AOP 切面统一打印请求与响应日志
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。