如果写入公共组件作为第三方包导入需要维护自动装配:resources\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports
参考资料:https://halo.ljdzsk.com/archives/javaspring公共组件与自动装配
小坑:这里记得要用全局的ObjectMapper,否则在转义JSON返回时可能存在输出日志和返回的响应不一致的情况。
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Enumeration;
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class ApiLogAspect {
// TODO 用于过滤不输出日志的路由,暂时没想到怎么做
@Value("${api-log.exclude.routes:[]}")
public String[] EXCLUDE_ROUTES;
// 使用全局的objectMapper解析返回值。
private final ObjectMapper objectMapper;
//定义切入点
@Pointcut("execution(* com.*.*.controller.*.*(..))")
public void log() {
}
//定义通知,方法执行前
@Before("log()")
public void doBefore(JoinPoint point) throws IOException {
if (!log.isDebugEnabled()) return;
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
log.debug("---------- 请求内容开始 ----------");
// log.debug("IP来源: " + request.getRemoteAddr());
log.debug("路由: " + request.getRequestURI());
log.debug("请求模式: " + request.getMethod());
Enumeration<String> enumeration = request.getHeaderNames();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("请求头: ");
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
stringBuilder.append("\n" + name + ":" + request.getHeader(name));
}
log.debug(stringBuilder.toString());
stringBuilder.delete(0, stringBuilder.length());
Enumeration<String> enu = request.getParameterNames();
if (point.getArgs().length > 0) {
// @RequestParam 参数
stringBuilder.append("传参: ");
while (enu.hasMoreElements()) {
String name = enu.nextElement();
stringBuilder.append(name + "=" + new String(request.getParameter(name).getBytes("ISO-8859-1"), "utf-8") + "&");
}
log.debug(stringBuilder.toString());
stringBuilder.delete(0, stringBuilder.length());
// 所有请求参数
stringBuilder.append("Args");
for (Object o : point.getArgs()) {
stringBuilder.append("\n" + new ObjectMapper().writeValueAsString(o));
}
log.debug(stringBuilder.toString());
stringBuilder.delete(0, stringBuilder.length());
}
log.debug("---------- 请求内容结束 ----------");
}
//定义通知,方法返回前
@AfterReturning(pointcut = "log()", returning = "returnVal")
public void AfterReturning(JoinPoint point, Object returnVal) throws JsonProcessingException {
if (!log.isDebugEnabled()) return;
log.debug("********** 响应内容开始 **********");
log.debug(objectMapper.writeValueAsString(returnVal));
log.debug("********** 响应内容结束 **********");
}
@Around("log()")
public Object around(ProceedingJoinPoint point) throws Throwable {
if (log.isDebugEnabled()) {
log.debug("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 请求开始 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
Object result = point.proceed();
log.debug("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 请求结束 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
return result;
} else {
return point.proceed();
}
}
}