对比新文件 |
| | |
| | | package com.iailab.framework.apilog.core.interceptor; |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.io.FileUtil; |
| | | import cn.hutool.core.io.resource.ResourceUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import com.iailab.framework.common.util.servlet.ServletUtils; |
| | | import com.iailab.framework.common.util.spring.SpringUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.util.StopWatch; |
| | | import org.springframework.web.method.HandlerMethod; |
| | | import org.springframework.web.servlet.HandlerInterceptor; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.lang.reflect.Method; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Optional; |
| | | import java.util.stream.IntStream; |
| | | |
| | | /** |
| | | * API 访问日志 Interceptor |
| | | * |
| | | * 目的:在非 prod 环境时,打印 request 和 response 两条日志到日志文件(控制台)中。 |
| | | * |
| | | * @author iailab |
| | | */ |
| | | @Slf4j |
| | | public class ApiAccessLogInterceptor implements HandlerInterceptor { |
| | | |
| | | public static final String ATTRIBUTE_HANDLER_METHOD = "HANDLER_METHOD"; |
| | | |
| | | private static final String ATTRIBUTE_STOP_WATCH = "ApiAccessLogInterceptor.StopWatch"; |
| | | |
| | | @Override |
| | | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { |
| | | // 记录 HandlerMethod,提供给 ApiAccessLogFilter 使用 |
| | | HandlerMethod handlerMethod = handler instanceof HandlerMethod ? (HandlerMethod) handler : null; |
| | | if (handlerMethod != null) { |
| | | request.setAttribute(ATTRIBUTE_HANDLER_METHOD, handlerMethod); |
| | | } |
| | | |
| | | // 打印 request 日志 |
| | | if (!SpringUtils.isProd()) { |
| | | Map<String, String> queryString = ServletUtils.getParamMap(request); |
| | | String requestBody = ServletUtils.isJsonRequest(request) ? ServletUtils.getBody(request) : null; |
| | | if (CollUtil.isEmpty(queryString) && StrUtil.isEmpty(requestBody)) { |
| | | log.info("[preHandle][开始请求 URL({}) 无参数]", request.getRequestURI()); |
| | | } else { |
| | | log.info("[preHandle][开始请求 URL({}) 参数({})]", request.getRequestURI(), |
| | | StrUtil.blankToDefault(requestBody, queryString.toString())); |
| | | } |
| | | // 计时 |
| | | StopWatch stopWatch = new StopWatch(); |
| | | stopWatch.start(); |
| | | request.setAttribute(ATTRIBUTE_STOP_WATCH, stopWatch); |
| | | // 打印 Controller 路径 |
| | | printHandlerMethodPosition(handlerMethod); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { |
| | | // 打印 response 日志 |
| | | if (!SpringUtils.isProd()) { |
| | | StopWatch stopWatch = (StopWatch) request.getAttribute(ATTRIBUTE_STOP_WATCH); |
| | | stopWatch.stop(); |
| | | log.info("[afterCompletion][完成请求 URL({}) 耗时({} ms)]", |
| | | request.getRequestURI(), stopWatch.getTotalTimeMillis()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 打印 Controller 方法路径 |
| | | */ |
| | | private void printHandlerMethodPosition(HandlerMethod handlerMethod) { |
| | | if (handlerMethod == null) { |
| | | return; |
| | | } |
| | | Method method = handlerMethod.getMethod(); |
| | | Class<?> clazz = method.getDeclaringClass(); |
| | | try { |
| | | // 获取 method 的 lineNumber |
| | | List<String> clazzContents = FileUtil.readUtf8Lines( |
| | | ResourceUtil.getResource(null, clazz).getPath().replace("/target/classes/", "/src/main/java/") |
| | | + clazz.getSimpleName() + ".java"); |
| | | Optional<Integer> lineNumber = IntStream.range(0, clazzContents.size()) |
| | | .filter(i -> clazzContents.get(i).contains(" " + method.getName() + "(")) // 简单匹配,不考虑方法重名 |
| | | .mapToObj(i -> i + 1) // 行号从 1 开始 |
| | | .findFirst(); |
| | | if (!lineNumber.isPresent()) { |
| | | return; |
| | | } |
| | | // 打印结果 |
| | | System.out.printf("\tController 方法路径:%s(%s.java:%d)\n", clazz.getName(), clazz.getSimpleName(), lineNumber.get()); |
| | | } catch (Exception ignore) { |
| | | // 忽略异常。原因:仅仅打印,非重要逻辑 |
| | | } |
| | | } |
| | | |
| | | } |