本文共 6366 字,大约阅读时间需要 21 分钟。
在本文中,我们将探讨如何在Spring Boot项目中使用AOP(面向切面编程)技术来实现接口访问的统一日志记录。通过在Controller层定义一个切面,我们可以实现对所有接口方法的调用进行日志记录,包括操作描述、时间、耗时、URL、请求参数和返回结果等信息。
AOP是一种面向切面编程的技术,通过预编译和运行期动态代理实现程序功能的统一维护。AOP的主要优势在于能够对业务逻辑的各个部分进行隔离,从而降低耦合度,提高程序的可重用性和开发效率。在AOP中,通知(Advice)定义了切面要完成的工作,而切点(Pointcut)定义了通知应用的范围。
前置通知(Before)
在目标方法调用前执行通知功能。后置通知(After)
在目标方法返回或抛出异常后执行通知功能。返回通知(AfterReturning)
在目标方法成功返回后执行通知功能。异常通知(AfterThrowing)
在目标方法抛出异常后执行通知功能。环绕通知(Around)
将目标方法包裹在自定义逻辑中执行,适用于需要控制方法执行流程的场景。切点定义了通知功能应用的范围。例如,execution(public * com.macro.mall.tiny.controller.*.*(..)) 表示所有Controller层的public方法都会应用该切面的通知功能。
为了统一记录接口访问日志,我们定义了一个WebLog类,用于封装日志信息:
package com.macro.mall.tiny.dto;public class WebLog { private String description; private String username; private Long startTime; private Integer spendTime; private String basePath; private String uri; private String url; private String method; private String ip; private Object parameter; private Object result;} 我们定义了一个WebLogAspect切面类,使用@Around类型的通知来实现对Controller层接口方法的环绕日志记录:
package com.macro.mall.tiny.component;import cn.hutool.core.util.StrUtil;import cn.hutool.core.util.URLUtil;import cn.hutool.json.JSONUtil;import com.macro.mall.tiny.dto.WebLog;import io.swagger.annotations.ApiOperation;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.Signature;import org.aspectj.lang.annotation.*;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.Method;import java.lang.reflect.Parameter;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * 统一日志处理切面 */@Component@Order(1)public class WebLogAspect { private static final Logger LOGGER = LoggerFactory.getLogger(WebLogAspect.class); @Pointcut("execution(public * com.macro.mall.tiny.controller.*.*(..))") public void webLog() {} @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 初始化日志对象 WebLog webLog = new WebLog(); } @AfterReturning(value = "webLog()", returning = "ret") public void doAfterReturning(Object ret) throws Throwable { // 处理返回结果 LOGGER.info("{}", JSONUtil.parse(ret)); } @Around("webLog()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); WebLog webLog = new WebLog(); Object result = joinPoint.proceed(); Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); if (method.isAnnotationPresent(ApiOperation.class)) { ApiOperation apiOperation = method.getAnnotation(ApiOperation.class); webLog.setDescription(apiOperation.value()); } long endTime = System.currentTimeMillis(); webLog.setSpendTime((int) (endTime - startTime)); webLog.setStartTime(startTime); webLog.setBasePath(StrUtil.removeSuffix(request.getRequestURL().toString(), URLUtil.url(request.getRequestURL().toString()).getPath())); webLog.setUri(request.getRequestURI()); webLog.setUrl(request.getRequestURL().toString()); webLog.setMethod(request.getMethod()); webLog.setIp(request.getRemoteUser()); // 获取请求参数 webLog.setParameter(getParameter(method, joinPoint.getArgs())); webLog.setResult(result); LOGGER.info("{}", JSONUtil.parse(webLog)); return result; } private Object getParameter(Method method, Object[] args) { List 运行项目后,访问接口可以在控制台看到日志记录:
{ "result": { "code": 200, "data": { "total": 11, "totalPage": 11, "pageSize": 1, "list": [ { "productCommentCount": 100, "name": "万和", "bigPic": "", "logo": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg(5).jpg", "showStatus": 1, "id": 1, "sort": 0, "productCount": 100, "firstLetter": "W", "factoryStatus": 1 } ], "pageNum": 1 }, "message": "操作成功" }, "basePath": "http://localhost:8080", "method": "GET", "parameter": [ { "pageNum": 1 }, { "pageSize": 1 } ], "description": "分页查询品牌列表", "startTime": 1561273191861, "uri": "/brand/list", "url": "http://localhost:8080/brand/list", "spendTime": 101} 如需了解完整项目源码,可以访问以下地址:项目源码
转载地址:http://dzln.baihongyu.com/