利用AOP的方式自定義注解


使用背景:

公司的維護項目提出一個比較惡心的需求,添加針對系統的人員和部門,企業等不同維度進行考核(考核的標准大體是根據登錄、使用系統內部按鈕、審批流轉等...)大體就是要通過活躍度,這一下懵逼了,這肯定要在不同的接口寫業務邏輯了,根據token獲取登錄人的所屬部門等信息,然后獲取對應的業務信息;

解決方法:利用AOP自定義注解的方法可以減少很大一部分工作。這里提供一個簡單的測試方法,僅僅只起到提示的作用;

一、首先需要在pom文件中集成aop的包

這里如果你想找不同版本的pom依賴:

https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

二、Controller層:利用AOP自定義注解的方式解決問題

package com.dongl.controller;

import com.dongl.utils.CheckManagement;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author D-L
 * @Classname AnnotationController
 * @Version 1.0
 * @Description   使用AOP測試自定義注解 controller
 * @Date 2020/8/4
 */

@RestController
@RequestMapping("Annotation")
public class AnnotationController {

    @CheckManagement("annotation-one")
    @GetMapping(value = "annotation")
    public Boolean Annotation (){
        System.out.println("interface start -----------------------------");
        return true;
    }
}

三、自定義注解

package com.dongl.utils;

import java.lang.annotation.*;
/**
 * @author D-L
 * @Classname CheckManagement
 * @Version 1.0
 * @Description  自定義注解
 * @Date 2020/8/4
 */

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckManagement {
    String value() default "";
}

四、切面類

package com.dongl.utils;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.stereotype.Component;
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.util.HashMap;
import java.util.Map;

/**
 * @author D-L
 * @Classname AnnotationController
 * @Version 1.0
 * @Description   使用AOP測試自定義注解 切面類
 * @Date 2020/8/4
 */

@Aspect
@Component
public class CheckManagementAspect {

    /**
     * 切入點
     * 切入點為包路徑下的:execution(public * org.ylc.note.aop.controller..*(..)):
     * com.dongl.controller包下任意類任意返回值的 public 的方法
     *
     * 切入點為注解的: @annotation(CheckManagement)
     * 存在 CheckManagement 注解的方法
     */
    @Pointcut("@annotation(com.dongl.utils.CheckManagement)")
    private void check() {
    }

    /**
     * 目標方法調用之前執行
     * 注意這里不能使用 ProceedingJoinPoint
     * @param joinPoint
     */
    @Before("check()")
    public void doBefore(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        CheckManagement visitPermission = method.getAnnotation(CheckManagement.class);
        String value = visitPermission.value();
        System.out.println("before--------------"+ value);
    }

    /**
     *  目標方法調用之后執行
     *  注意這里不能使用 ProceedingJoinPoint
     * @param joinPoint
     */
    @After("check()")
    public void doAfter(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        CheckManagement visitPermission = method.getAnnotation(CheckManagement.class);
        String value = visitPermission.value();
        //根據不同的value處理不同的業務
        if(value.equals("annotation-one")){
            System.out.println("after-處理方式1 :------------------");
        }else if (value.equals("annotation-two")){
            System.out.println("after-處理方式2 :------------------");
        }else if (value.equals("annotation-three")){
            System.out.println("after-處理方式3 :------------------");
        }
        System.out.println("after--------------"+ value);
    }

    /**
     * 環繞
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("check()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("around start --------------------------");
        long startTime = System.currentTimeMillis();

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
        CheckManagement visitPermission = method.getAnnotation(CheckManagement.class);
        String value = visitPermission.value();

        Object result = proceedingJoinPoint.proceed();
        long endTime = System.currentTimeMillis();
        Map<String, Object> infomation = getInfomation(request, proceedingJoinPoint, startTime, endTime);
        System.out.println("around end --------------------------");
        return result;
    }

    /**
     * 處理執行結果
     * @param request 請求體
     * @param proceedingJoinPoint
     * @param startTime 開始時間
     * @param endTime 結束時間
     * @return
     */
    private Map<String ,Object> getInfomation(HttpServletRequest request ,ProceedingJoinPoint proceedingJoinPoint,  long startTime, long endTime){
        Map<String , Object> map = new HashMap<>();
        // 請求 url
        String url = request.getRequestURL().toString();
        map.put("url" , url);
        //  Http method
        String HttpMethod = request.getMethod();
        map.put("HttpMethod" , HttpMethod);
        // 調用 controller 的全路徑以及執行方法
        String declaringTypeName = proceedingJoinPoint.getSignature().getDeclaringTypeName();
        map.put("declaringTypeName",declaringTypeName);
        // 調用方法
        String method = proceedingJoinPoint.getSignature().getName();
        map.put("method",method);
        // 執行耗時
        map.put("time",(endTime - startTime));
        return map;
    }
}

五、測試方法:使用postman調用具體的接口

 六、測試結果:

around start --------------------------
before--------------annotation-one
interface start -----------------------------
around end --------------------------
after-處理方式1 :------------------
after--------------annotation-one

 根據測試結果你也可以看出不同類型的方式執行的順序;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM