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)。