springboot中讀取所有添加指定註解的方法

springboot中讀取所有添加了自定義標籤的方法

需求描述

最近公司要求用springSecurity搞一套權限管理(RBAC),單獨就tb_permission表數據來說,我需要讀取到Controller中所有添加了自定義註解的函數並將其路由存入數據庫,需要達到效果如下:

在這裏插入圖片描述

自定義註解

import java.lang.annotation.*;


@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckPermission {
    /**
     * 描述
     *
     * @return
     */
    String descrption() default "" ;
}

測試Controller

import com.dar.road.core.annotation.CheckPermission;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


/**
 * @Author weiwenbin
 * @Date 2020/5/20 上午9:40
 */
@RestController
@RequestMapping("/test")
public class TestController {
    @PostMapping("/justTest")
    @CheckPermission(descrption = "測試-只是個測試")
    public void justTest() {
        System.out.println("我只是個測試方法");
    }
}

AnnotationUtil工具類

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import java.util.*;

/**
 * @Author weiwenbin
 * @Date 2020/5/14 下午5:31
 */
@Component
public class AnnotationUtil {
    @Autowired
    private ResourceLoader resourceLoader;

    private static final String VALUE = "value";

    /**
     * 獲取指定包下所有添加了執行註解的方法信息
     * @param classPath 包名
     * @param tagAnnotationClass 指定註解類型
     * @param <T>
     * @return
     * @throws Exception
     */
    public  <T> Map<String, Map<String, Object>> getAllAddTagAnnotationUrl(String classPath, Class<T> tagAnnotationClass) throws Exception {
        Map<String, Map<String, Object>> resMap = new HashMap<>();
        ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
        MetadataReaderFactory metaReader = new CachingMetadataReaderFactory(resourceLoader);
        Resource[] resources = resolver.getResources(classPath);

        for (org.springframework.core.io.Resource r : resources) {
            MetadataReader reader = metaReader.getMetadataReader(r);
            resMap = resolveClass(reader, resMap, tagAnnotationClass);
        }


        return resMap;
    }

    private <T> Map<String, Map<String, Object>> resolveClass(
            MetadataReader reader, Map<String, Map<String, Object>> resMap, Class<T> tagAnnotationClass)
            throws Exception {
        String tagAnnotationClassCanonicalName = tagAnnotationClass.getCanonicalName();
        //獲取註解元數據
        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
        //獲取類中RequestMapping註解的屬性
        Map<String, Object> annotationAttributes =
                annotationMetadata.getAnnotationAttributes(RequestMapping.class.getCanonicalName());

        //若類無RequestMapping註解
        if (annotationAttributes == null) return resMap;

        //獲取RequestMapping註解的value
        String[] pathParents = (String[]) annotationAttributes.get(VALUE);
        if (0 == pathParents.length) return resMap;

        //獲取RequestMapping註解的value
        String pathParent = pathParents[0];

        //獲取當前類中已添加要掃描註解的方法
        Set<MethodMetadata> annotatedMethods = annotationMetadata.getAnnotatedMethods(tagAnnotationClassCanonicalName);

        for (MethodMetadata annotatedMethod : annotatedMethods) {
            //獲取當前方法中要掃描註解的屬性
            Map<String, Object> targetAttr = annotatedMethod.getAnnotationAttributes(tagAnnotationClassCanonicalName);
            //獲取當前方法中要xxxMapping註解的屬性
            Map<String, Object> mappingAttr = getPathByMethod(annotatedMethod);
            if (mappingAttr == null){
                continue;
            }

            String[] childPath = (String[]) mappingAttr.get(VALUE);
            if (targetAttr == null || childPath == null || childPath.length == 0) {
                continue;
            }

            String path = pathParent + childPath[0];

            boolean isHas = resMap.containsKey(path);
            if (isHas){
                throw new Exception("重複定義了相同的映射關係");
            }

            resMap.put(path, targetAttr);
        }

        return resMap;
    }


    private Map<String, Object> getPathByMethod(MethodMetadata annotatedMethod) {
        Map<String, Object> annotationAttributes = annotatedMethod.getAnnotationAttributes(GetMapping.class.getCanonicalName());
        if (annotationAttributes != null && annotationAttributes.get(VALUE) != null) {
            return annotationAttributes;
        }
        annotationAttributes = annotatedMethod.getAnnotationAttributes(PostMapping.class.getCanonicalName());
        if (annotationAttributes != null && annotationAttributes.get(VALUE) != null) {
            return annotationAttributes;
        }

        annotationAttributes = annotatedMethod.getAnnotationAttributes(DeleteMapping.class.getCanonicalName());
        if (annotationAttributes != null && annotationAttributes.get(VALUE) != null) {
            return annotationAttributes;
        }

        annotationAttributes = annotatedMethod.getAnnotationAttributes(PutMapping.class.getCanonicalName());
        if (annotationAttributes != null && annotationAttributes.get(VALUE) != null) {
            return annotationAttributes;
        }
        annotationAttributes = annotatedMethod.getAnnotationAttributes(RequestMapping.class.getCanonicalName());
        return annotationAttributes;
    }
}

調用

上面做完之後直接調用,獲取到map如圖, 我這邊直接將map做一次處理後直接存庫(tb_permission)。
在這裏插入圖片描述

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章