SpringBoot 日志记录(面向切面)
引入依赖
<!--利用 AOP 做操作日志记录--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WebLog { /** * 渠道 * @return 渠道标识 */ String channel() default "web"; /** * 功能名称 * @return 功能名称 */ String name() default ""; /** * 方法名称 * @return 方法名称 */ String action() default ""; /** * 是否保存(默认不保存) * @return 是否保存 */ boolean saveFlag() default false; }
@Aspect // 表明此类为一个切面 @Component // 随着框架的启动而启动 public class WebLogAspect {/** * 获取日志类,方便直接在控制台输出统一格式的日志信息 */ private final static Logger logger = LoggerFactory.getLogger(WebLogAspect.class); /** * 以 controller 包下定义的所有请求为切入点 */ @Pointcut("execution(public * net.parallel.controller.*.*(..))" + "||execution(public * net.parallel.feign.*.*(..))") public void webLog() { } /** * 在切点之前织入 * * @param joinPoint * @throws Throwable */ @Before("webLog()") // webLog():是你@Pointcut注解的方法名 public void doBefore(JoinPoint joinPoint) throws Throwable { // 开始打印请求日志 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); if (BeanUtil.isEmpty(request) || StringUtils.isBlank(request.getRequestURL())) { return; } // 打印请求相关参数 logger.info("========================================== Start =========================================="); // 打印请求 url logger.info("URL : {}", request.getRequestURL().toString()); // 打印 Http method logger.info("HTTP Method : {}", request.getMethod()); // 打印调用 controller 的全路径以及执行方法 logger.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); // 打印请求的 IP logger.info("IP : {}", request.getRemoteAddr()); // 打印请求入参 logger.info("Request Args : {}", new Gson().toJson(joinPoint.getArgs())); // 获取 @ApiOperatjoinPoint = {MethodInvocationProceedingJoinPoint@21287} "execution(RestResponse net.evecom.parallel.controller.ParallelWorkController.businessAddParallelWork(String,String,String,String,String,String,String,String,String,String,String,String,String))"ion("") 注解中的信息,此注解属于swagger的,但也能获取,其他注解可举一反三 ApiOperation apiOperation = null; // JoinPoint:oinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.大概就是获取目标方法的一些信息 MethodSignature ms = (MethodSignature) joinPoint.getSignature(); apiOperation = ms.getMethod().getDeclaredAnnotation(ApiOperation.class); if (apiOperation != null) { ; logger.info("操作 : {}", apiOperation.value()); } } /** * 在切点之后织入 * * @throws Throwable */ @After("webLog()") public void doAfter() throws Throwable { logger.info("=========================================== End ==========================================="); // 每个请求之间空一行 logger.info(""); } /** * 环绕 * * @param pjp * @return * @throws Throwable */ @Around("webLog()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { long startTime = System.currentTimeMillis(); Object result = pjp.proceed(); // 打印出参 logger.info("Response Args : {}", new Gson().toJson(result)); // 执行耗时 logger.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime); Object[] paramValues = pjp.getArgs();//获取参数数组 Signature sig = pjp.getSignature();//获取方法对象 MethodSignature msig = (MethodSignature )sig; Method method = msig.getMethod(); //获取自定义注解的属性值 WebLog ann = method.getAnnotation(WebLog.class); if (BeanUtil.isEmpty(ann)) { return result; } logger.info("请求参数: {}", JSON.toJSONString(paramValues)); logger.info("返回值:{}", new Gson().toJson(result));return result; } }
controller层
/** * 新增联办件调用接口(营业执照)—— 变更/注销 * @return */ @ApiOperation("新增联办件调用接口") @PostMapping("businessAddParallelWork") @WebLog(channel = "web", name = "新增联办件调用接口", action = "parallelWork/businessAddParallelWork", saveFlag = true) public RestResponse businessAddParallelWork(@RequestBody ParallelWorkOrderActvEntity parallelWorkOrderActvEntity) { // 业务代码... return null; }
Feign接口调用
@FeignClient(name = "license-service", contextId = "license-service-approve") public interface LicServiceFeign { /** * 变更流程发起 * * @param json * @return */ @WebLog(channel = "feign", name = "变更流程发起", action = "/lic/lic-change/saveTempData", saveFlag = true) @PostMapping("/lic/lic-change/saveTempData") RestResponse licChangeFlowStart(@RequestBody JSONObject json, @RequestHeader("Authorization") String authorization); /** * 注销流程发起 * * @param json * @return */ @WebLog(channel = "feign", name = "注销流程发起", action = "/lic/lic-cancel/save", saveFlag = true) @PostMapping("/lic/lic-cancel/save") RestResponse licCancelFlowStart(@RequestBody JSONObject json, @RequestHeader("Authorization") String authorization); }