Spring Web 日志记录切面
Spring Web 日志记录切面
应用: 在我们进行 rest 接口编写时需要对该接口的耗时、参数、请求路径、返回值进行对应的记录
日志注解
把日志封装成注解的形式可以更好的供使用者使用,同时也利于解耦合
- 代码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MLog {
// 是否记录输入参数
boolean input() default true;
// 是否记录输出参数
boolean output() default true;
}
切面类
- 利用 Spring AOP 机制对日志注解进行处理
@Aspect
public class MLogPrintAspect {
@Around("@within(com.ayi.annotation.MLog) || @annotation(com.ayi.annotation.MLog)")
public Object printMLog(ProceedingJoinPoint joinPoint) throws Throwable {
// 切面开始时间
long startTime = SystemClock.now();
// 获取方法签名
MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
Logger log = LoggerFactory.getLogger(methodSignature.getDeclaringType());
String beginTime = DateUtil.now();
// 方法返回结果
Object result = null;
try {
result = joinPoint.proceed();
} finally {
// 获取目标方法
Method targetMethod = joinPoint.getTarget().getClass().getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
// 获取日志
MLog mLog = Optional.ofNullable(targetMethod.getAnnotation(MLog.class)).orElse(joinPoint.getTarget().getClass().getAnnotation(MLog.class));
if (null != mLog) {
MLogPrint mLogPrint = new MLogPrint();
mLogPrint.setBeginTime(beginTime);
if (mLog.input()) {
mLogPrint.setInputParams(buildInput(joinPoint , targetMethod));
}
if (mLog.output()) {
mLogPrint.setOutputParams(result);
}
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
Preconditions.checkNotNull(servletRequestAttributes , "servletRequestAttributes is not null");
HttpServletRequest request;
String requestURI = "";
String methodType = "";
try {
request = servletRequestAttributes.getRequest();
requestURI = request.getRequestURI();
/**
处理请求 URI 前缀 http://localhost:8080/test
/test
*/
requestURI = CharSequenceUtil.removeSuffix(requestURI, URLUtil.url(requestURI).getPath());
methodType = request.getMethod();
}catch (Exception ignored) {
}
// 打印日志
log.info("[{}] {}, executeTime: {}ms, info: {}", methodType, requestURI, SystemClock.now() - startTime, JSON.toJSONString(mLogPrint));
}
}
return result;
}
/**
* 输入日志集合处理
* @param joinPoint
* @param method
* @return
*/
public Object[] buildInput(ProceedingJoinPoint joinPoint , Method method) {
Object[] args = joinPoint.getArgs();
Object[] printArgs = new Object[args.length];
Parameter[] parameters = method.getParameters();
for (int i = 0; i < args.length; i++) {
if ((args[i] instanceof HttpServletRequest) || args[i] instanceof HttpServletResponse) {
continue;
}
if (args[i] instanceof byte[]) {
printArgs[i] = "byte array";
} else if (args[i] instanceof MultipartFile) {
printArgs[i] = "file";
} else {
printArgs[i] = args[i];
}
}
return printArgs;
}
@Data
private class MLogPrint {
private String beginTime;
private Object[] inputParams;
private Object outputParams;
}
}
封装 LogConfig 并进行 Spring Boot 模块封装
public class LogAutoConfiguration {
@ConditionalOnMissingBean
@Bean
MLogPrintAspect mLogPrintAspect() {
return new MLogPrintAspect();
}
}
注意: 在 resource/META-INFO/spring.factories
里面进行相关配置
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.ayi.config.LogAutoConfiguration
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)