# spring-boot-demo-log-aop > 此 demo 主要是演示如何使用 aop 切面对请求进行日志记录,并且记录 UserAgent 信息。 ## pom.xml ```xml 4.0.0 spring-boot-demo-log-aop 1.0.0-SNAPSHOT jar spring-boot-demo-log-aop Demo project for Spring Boot com.xkcoding spring-boot-demo 1.0.0-SNAPSHOT UTF-8 UTF-8 1.8 com.google.guava guava org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-aop org.springframework.boot spring-boot-starter-test test org.projectlombok lombok true cn.hutool hutool-all eu.bitwalker UserAgentUtils spring-boot-demo-log-aop org.springframework.boot spring-boot-maven-plugin ``` ## AopLog.java ```java /** *

* 使用 aop 切面记录请求日志信息 *

* * @author yangkai.shen * @author chen qi * @date Created in 2018-10-01 22:05 */ @Aspect @Component @Slf4j public class AopLog { /** * 切入点 */ @Pointcut("execution(public * com.xkcoding.log.aop.controller.*Controller.*(..))") public void log() { } /** * 环绕操作 * * @param point 切入点 * @return 原方法返回值 * @throws Throwable 异常信息 */ @Around("log()") public Object aroundLog(ProceedingJoinPoint point) throws Throwable { // 开始打印请求日志 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = Objects.requireNonNull(attributes).getRequest(); // 打印请求相关参数 long startTime = System.currentTimeMillis(); Object result = point.proceed(); String header = request.getHeader("User-Agent"); UserAgent userAgent = UserAgent.parseUserAgentString(header); final Log l = Log.builder() .threadId(Long.toString(Thread.currentThread().getId())) .threadName(Thread.currentThread().getName()) .ip(getIp(request)) .url(request.getRequestURL().toString()) .classMethod(String.format("%s.%s", point.getSignature().getDeclaringTypeName(), point.getSignature().getName())) .httpMethod(request.getMethod()) .requestParams(getNameAndValue(point)) .result(result) .timeCost(System.currentTimeMillis() - startTime) .userAgent(header) .browser(userAgent.getBrowser().toString()) .os(userAgent.getOperatingSystem().toString()).build(); log.info("Request Log Info : {}", JSONUtil.toJsonStr(l)); return result; } /** * 获取方法参数名和参数值 * @param joinPoint * @return */ private Map getNameAndValue(ProceedingJoinPoint joinPoint) { final Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; final String[] names = methodSignature.getParameterNames(); final Object[] args = joinPoint.getArgs(); if (ArrayUtil.isEmpty(names) || ArrayUtil.isEmpty(args)) { return Collections.emptyMap(); } if (names.length != args.length) { log.warn("{}方法参数名和参数值数量不一致", methodSignature.getName()); return Collections.emptyMap(); } Map map = Maps.newHashMap(); for (int i = 0; i < names.length; i++) { map.put(names[i], args[i]); } return map; } private static final String UNKNOWN = "unknown"; /** * 获取ip地址 */ public static String getIp(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } String comma = ","; String localhost = "127.0.0.1"; if (ip.contains(comma)) { ip = ip.split(",")[0]; } if (localhost.equals(ip)) { // 获取本机真正的ip地址 try { ip = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { log.error(e.getMessage(), e); } } return ip; } @Data @Builder @NoArgsConstructor @AllArgsConstructor static class Log { // 线程id private String threadId; // 线程名称 private String threadName; // ip private String ip; // url private String url; // http方法 GET POST PUT DELETE PATCH private String httpMethod; // 类方法 private String classMethod; // 请求参数 private Object requestParams; // 返回参数 private Object result; // 接口耗时 private Long timeCost; // 操作系统 private String os; // 浏览器 private String browser; // user-agent private String userAgent; } } ``` ## TestController.java ```java /** *

* 测试 Controller *

* * @author yangkai.shen * @author chen qi * @date Created in 2018-10-01 22:10 */ @Slf4j @RestController public class TestController { /** * 测试方法 * * @param who 测试参数 * @return {@link Dict} */ @GetMapping("/test") public Dict test(String who) { return Dict.create().set("who", StrUtil.isBlank(who) ? "me" : who); } /** * 测试post json方法 * @param map 请求的json参数 * @return {@link Dict} */ @PostMapping("/testJson") public Dict testJson(@RequestBody Map map) { final String jsonStr = JSONUtil.toJsonStr(map); log.info(jsonStr); return Dict.create().set("json", map); } } ```