springboot 自定义注解记录接口访问日志表
Advice:通知,某个连接点所采用的处理逻辑,也就是向连接点注入的代码, AOP在特定的切入点上执行的增强处理。
@Before:标识前置增强方法,相当于BeforeAdvice;
@Around:环绕增强,相当于MethodInterceptor;
@After:final增强,抛出异常和正常退出后都会执行;
@AfterReturning:后置增强,正常退出时执行,相当于AfterReturningAdvice;
@AfterThrowing:后置增强,抛出异常时执行,相当于ThrowsAdvice。
JointPoint:连接点,程序运行中的某个阶段点,比如方法的调用、异常的抛出等。
Object[] getArgs:返回目标方法的参数;
Signature getSignature:返回目标方法的签名;
Object getTarget:返回被织入增强处理的目标对象;
Object getThis:返回AOP框架为目标对象生成的代理对象。
/** Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.pig4cloud.pig.common.log.annotation;import java.lang.annotation.*;/*** 系统任务注解:用于标记需要记录操作任务的方法** @author lengleng* @date 2025/05/31*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysTask {/*** 描述* @return {String}*/String value() default "";/*** spel 表达式* @return 日志描述*/String expression() default "";}
/** Copyright (c) 2020 pig4cloud Authors. All Rights Reserved.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.pig4cloud.pig.common.log.aspect;import cn.hutool.core.util.StrUtil;
import com.pig4cloud.pig.common.core.util.SpringContextHolder;
import com.pig4cloud.pig.common.log.annotation.SysTask;
import com.pig4cloud.pig.common.log.event.SysTaskEvent;
import com.pig4cloud.pig.common.log.event.SysTaskEventSource;
import com.pig4cloud.pig.common.log.util.LogTypeEnum;
import com.pig4cloud.pig.common.log.util.SysLogUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;/*** 系统任务切面类,通过Spring AOP实现操作任务的异步记录** @author lengleng* @date 2025/05/31*/
@Aspect
@Slf4j
@RequiredArgsConstructor
public class SysTaskAspect {/*** 环绕通知方法,用于处理系统任务记录* @param point 连接点对象* @param sysTask 系统任务注解* @return 目标方法执行结果* @throws Throwable 目标方法执行可能抛出的异常@Around("@annotation(sysTask)")@SneakyThrowspublic Object around(ProceedingJoinPoint point, com.pig4cloud.pig.common.log.annotation.SysTask sysTask) {String strClassName = point.getTarget().getClass().getName();String strMethodName = point.getSignature().getName();log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);String value = sysTask.value();SysTaskEventSource logVo = SysLogUtils.getSysTask();logVo.setTitle(value);// 获取请求body参数if (StrUtil.isBlank(logVo.getParams())) {logVo.setBody(point.getArgs());}// 发送异步任务事件Long startTime = System.currentTimeMillis();logVo.setTitle(value+"[开始执行]");Object obj;try {obj = point.proceed();}catch (Exception e) {logVo.setLogType(LogTypeEnum.ERROR.getType());logVo.setException(e.getMessage());throw e;}finally {Long endTime = System.currentTimeMillis();logVo.setTime(endTime - startTime);SpringContextHolder.publishEvent(new SysTaskEvent(logVo));}return obj;}*//*** 定义切面* - 此处代表com.example.demo.module.controller包下的所有接口都会被统计@Pointcut("@annotation(com.pig4cloud.pig.common.log.annotation.SysTask)")// @Pointcut("execution(* cn.agile.platform.core.web.controller..*.*(..))")public void log() {log.info("loglog=loglog");} *//*** 在接口原有的方法执行前,将会首先执行此处的代码*/@Before("@annotation(sysTask)")public void doBefore(JoinPoint point,com.pig4cloud.pig.common.log.annotation.SysTask sysTask) {MethodSignature signature = (MethodSignature)point.getSignature();SysTask annotation = signature.getMethod().getAnnotation(SysTask.class);log.info("在接口原有的方法执行前");String strClassName = point.getTarget().getClass().getName();String strMethodName = point.getSignature().getName();log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);String value = sysTask.value();SysTaskEventSource logVo = SysLogUtils.getSysTask();logVo.setTitle(value);// 获取请求body参数if (StrUtil.isBlank(logVo.getParams())) {logVo.setBody(point.getArgs());}// 发送异步任务事件Long startTime = System.currentTimeMillis();logVo.setTitle(value+"[开始执行]");Long endTime = System.currentTimeMillis();logVo.setTime(endTime - startTime);SpringContextHolder.publishEvent(new SysTaskEvent(logVo));}/*** 只有正常返回才会执行此方法* 如果程序执行失败,则不执行此方法*/@AfterReturning(returning = "returnVal", pointcut = "@annotation(sysTask)")@SneakyThrowspublic void doAfterReturning(JoinPoint point, Object returnVal,com.pig4cloud.pig.common.log.annotation.SysTask sysTask) {log.info("只有正常返回才会执行此方法");String strClassName = point.getTarget().getClass().getName();String strMethodName = point.getSignature().getName();log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);String value = sysTask.value();SysTaskEventSource logVo = SysLogUtils.getSysTask();logVo.setTitle(value);// 获取请求body参数if (StrUtil.isBlank(logVo.getParams())) {logVo.setBody(point.getArgs());}// 发送异步任务事件Long startTime = System.currentTimeMillis();logVo.setTitle(value+"[结束执行]");Long endTime = System.currentTimeMillis();logVo.setTime(endTime - startTime);SpringContextHolder.publishEvent(new SysTaskEvent(logVo));}/*** 当接口报错时执行此方法*/@AfterThrowing(pointcut = "@annotation(sysTask)")public void doAfterThrowing(JoinPoint point,com.pig4cloud.pig.common.log.annotation.SysTask sysTask) {log.info("当接口报错时执行此方法");String strClassName = point.getTarget().getClass().getName();String strMethodName = point.getSignature().getName();log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);String value = sysTask.value();SysTaskEventSource logVo = SysLogUtils.getSysTask();logVo.setTitle(value);// 获取请求body参数if (StrUtil.isBlank(logVo.getParams())) {logVo.setBody(point.getArgs());}// 发送异步任务事件Long startTime = System.currentTimeMillis();logVo.setTitle(value+"[异常执行]");Long endTime = System.currentTimeMillis();logVo.setTime(endTime - startTime);SpringContextHolder.publishEvent(new SysTaskEvent(logVo));}/*** 在接口原有的方法执行后,都会执行此处的代码(final)@After("@annotation(sysTask)")public void doAfter(JoinPoint joinPoint,com.pig4cloud.pig.common.log.annotation.SysTask sysTask) {log.info("在接口原有的方法执行后 ");}*/}
/*** 导出角色数据到Excel表格* @return 角色数据列表*/@ResponseExcel@GetMapping("/export")@SysTask("导出角色EXCEL数据")@HasPermission("sys_role_export")public List<RoleExcelVO> exportRoles() {return sysRoleService.listRoles();}