SpringBoot使用SpringAOP实现日志审计等功能

项目当中需要对用户操作菜单的行为记录日志,用SpringAOP写了个大概实现,切点是采用注解的方式,用包名的方式虽然也可以达到相同的效果,但是不如注解方式灵活方便。

不多说,直接上代码,此处只是简单写写实现原理。

 

工程目录:

 

pom.xml引入以下依赖:

<!-- 热部署模块 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional> <!-- 这个需要为 true 热部署才有效 -->
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- spring-boot aop依赖配置引入 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

 

 注解:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Action {
    String description() default "no description";
}

 

Controller类:

/**
 * @auther: gaopeng
 */
@RestController
public class AspectController {

    /**
     * 走切面
     * @return
     */
    @GetMapping("/test")
    @Action(description = "执行了test操作菜单")
    public String test(){
        return "method return";
    }

    /**
     * 不走切面
     */
    @GetMapping("/test1")
    private void test1(){
    }

    /**
     * 走切面,抛异常
     */
    @GetMapping("/throws")
    @Action(description = "执行了throws菜单但是抛了异常")
    public void throwsException(){
        throw new RuntimeException();
    }
}

 

切面类:

/**
 * @auther: gaopeng
 */
@Aspect
@Component
public class TestAspect {

    /**
     * 切入点
     */
    // 此处的切点是注解的方式,也可以用包名的方式达到相同的效果
    //@Pointcut("execution(public * com.gaopeng.springboot.mytest.controller.*.*(..))")
    @Pointcut("@annotation(com.gaopeng.springboot.mytest.annotation.Action)")
    public void execute(){
    }

    /**
     * 前置通知
     * @param joinPoint
     */
    @Before(value ="execute()")
    public void Before(JoinPoint joinPoint) {
        System.out.println("执行方法之前");
    }

    /**
     * 环绕通知
     * @param proceedingJoinPoint
     * @return
     */
    @Around(value ="execute()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("环绕通知开始");
        try {
            System.out.println("执行方法:" + proceedingJoinPoint.getSignature().getName());
            
            MethodSignature signature =(MethodSignature) proceedingJoinPoint.getSignature();
            Action action = signature.getMethod().getAnnotation(Action.class);
            
            System.out.println("菜单="+action.description());
            
            Object object =  proceedingJoinPoint.proceed();
            System.out.println("环绕通知结束,方法返回:" + object);
            return object;
        } catch (Throwable e) {
            System.out.println("执行方法异常:" + e.getClass().getName());
            return null;
        }
    }

    /**
     * 后置通知
     * @param joinPoint
     */
    @After(value ="execute()")
    public void After(JoinPoint joinPoint) {
        System.out.println("执行方法之后");
    }

    /**
     * 后置通知,带返回值
     * @param obj
     */
    @AfterReturning(pointcut = "execute()",returning = "obj")
    public void AfterReturning(Object obj) {
        System.out.println("执行方法之后获取返回值:"+obj);
    }

    /**
     * 后置通知,异常时执行
     * @param e
     */
    @AfterThrowing(throwing = "e",pointcut = "execute()")
    public void doAfterThrowing(Exception e) {
        System.out.println("执行方法异常:"+e.getClass().getName());
    }
}

 

运行结果:

 

posted @ 2019-11-20 15:12  gaopengpy  阅读(3153)  评论(0编辑  收藏  举报