业务需求
项目中有非常多的api接口,很多接口都有相应的权限限制,需要把对应的权限写入到数据库的权限表中,以供选择。节省人工输入的时间。
核心逻辑
创建一个@Component类 实现 ApplicationContextAware 接口,并实现其中的setApplicationContext拿到上下文 ApplicationContext。
通过ApplicationContext 的 getBeansWithAnnotation 方法可以拿在Springboot管理下的所有带指定注解的bean。
通过bean拿到类名反射获取其中的方法,使用方法对象的 getAnnotation 方法检查是否有我们需要的注解(本例中为 RequiresPermissions.class),如果有则保存到 API_LIST 中。
注:不能直接用bean的getClass方法提供的类对象,其无法扫描到正确的方法列表
代码
Api对象
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* Api 接口
* @author bx002
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Api implements Serializable {
String className;
String methodName;
String[] path;
String[] requiredPermissions;
}
获取Api信息
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Api接口工具类
* @author bx002
*/
@Slf4j
@Component
public class ApiUtils implements ApplicationContextAware {
public final static List<Api> API_LIST = new ArrayList<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(RequestMapping.class);
beans.forEach((name, bean) -> {
String className = bean.getClass().getName();
className = className.split("\\$\\$")[0];
try {
Class<?> clazz = Class.forName(className);
// 获取根路径
String[] rootPath = getApiPath(clazz);
if (rootPath == null) {
return;
}
for (Method method : clazz.getDeclaredMethods()) {
String[] methodPath = getApiPath(method);
if (methodPath == null) {
continue;
}
// api路径
List<String> pathList = new ArrayList<>();
for (String p1 : rootPath) {
for (String p2 : methodPath) {
pathList.add(String.format("/%s/%s", p1, p2).replace("//", "/"));
}
}
// api权限
RequiresPermissions permissions = method.getAnnotation(RequiresPermissions.class);
Api api = new Api();
api.setClassName(className)
.setMethodName(method.getName())
.setPath(pathList.toArray(new String[]{
}))
.setRequiredPermissions(permissions != null ? permissions.value() : null)
;
API_LIST.add(api);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
});
}
private static String[] getApiPath(AnnotatedElement annotatedElement) {
RequestMapping a1 = annotatedElement.getAnnotation(RequestMapping.class);
PostMapping a2 = annotatedElement.getAnnotation(PostMapping.class);
GetMapping a3 = annotatedElement.getAnnotation(GetMapping.class);
if (a1 != null) {
return a1.value();
}
if (a2 != null) {
return a2.value();
}
if (a3 != null) {
return a3.value();
}
return null;
}
}