基于Java反射技术扫描Controller接口列表(完整代码)
基于org.reflections依赖包简化反射代码
1. 导入依赖
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
2. 实现代码
2.1 配置类:ApiConfig
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
public class ApiConfig {
/**
* 扫描注解
*/
public Set<Class> annotations = new HashSet<>();
/**
* 扫描路径
*/
public String basePackage = "com.dwp";
/**
* 判断是否需要处理此文件,入参为文件名(含.class后缀)
*/
public Predicate<String> classPredicate = clazz -> clazz.endsWith("Controller.class");
protected ApiConfig() {
}
}
2.2 配置类构建类:ApiConfigBuilder
import java.util.Arrays;
import java.util.Collection;
public class ApiConfigBuilder {
private ApiConfig apiConfig;
public ApiConfigBuilder() {
this.apiConfig = new ApiConfig();
}
public ApiConfigBuilder addAnnotations(Class clazz) {
addAnnotations(Arrays.asList(clazz));
return this;
}
public ApiConfigBuilder addAnnotations(Collection<Class> clazz) {
apiConfig.annotations.addAll(clazz);
return this;
}
public ApiConfigBuilder forPackage(String basePackage) {
apiConfig.basePackage = basePackage;
return this;
}
public ApiConfig build() {
return this.apiConfig;
}
}
2.3 接口实体类:ApiEntity
import lombok.Data;
import java.io.Serializable;
@Data
public class ApiEntity implements Serializable {
private static final long serialVersionUID = 1L;
private String moduleName;
private String name;
private String remark;
private String path;
private String method;
public ApiEntity() {
}
public ApiEntity(String path) {
this.path = path;
}
public ApiEntity(String path, String method) {
this(path);
this.method = method;
}
public ApiEntity(String name, String remark, String path, String method) {
this(path, method);
this.name = name;
this.remark = remark;
}
}
2.4 核心逻辑工具类:ApiUtil
import com.dwp.entity.ApiEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.util.ConfigurationBuilder;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import static org.springframework.web.bind.annotation.RequestMethod.*;
@Slf4j
public class ApiUtil {
private static final Map<Class, RequestMethod> METHOD_TYPE = new HashMap<Class, RequestMethod>() {
{
put(PostMapping.class, POST);
put(PutMapping.class, PUT);
put(DeleteMapping.class, DELETE);
put(GetMapping.class, GET);
put(PatchMapping.class, PATCH);
}};
public ApiConfig config;
public ApiUtil() {
}
public ApiUtil(ApiConfig config) {
this.config = config;
}
/**
* 扫描所有文件下的方法,默认扫描具有以下注解的接口
* {@link RequestMapping},
* {@link PostMapping},
* {@link PutMapping},
* {@link GetMapping},
* {@link DeleteMapping},
* {@link PatchMapping}
*
* @return
*/
public List<ApiEntity> scanApis() {
return scanList(getMethods());
}
/**
* 构造反射器
*
* @return
*/
private Reflections buildReflections() {
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setInputsFilter(config.classPredicate)
.forPackage(config.basePackage)
.setScanners(new MethodAnnotationsScanner()));
return reflections;
}
/**
* 获取方法集合
*
* @return
*/
private Set<Method> getMethods() {
Reflections reflections = buildReflections();
Set<Method> result = new HashSet<>();
Set<Class> annotations = config.annotations;
if (CollectionUtils.isEmpty(annotations)) {
annotations.add(RequestMapping.class);
annotations.add(PostMapping.class);
annotations.add(PutMapping.class);
annotations.add(GetMapping.class);
annotations.add(DeleteMapping.class);
annotations.add(PatchMapping.class);
}
for (Class clazz : annotations) {
Set<Method> set = Optional.ofNullable(reflections.getMethodsAnnotatedWith(clazz)).orElse(new HashSet());
result.addAll(set);
}
return result;
}
/**
* 解析方法集合
*
* @param methods 方法集合
* @return
*/
private List<ApiEntity> scanList(Set<Method> methods) {
List<ApiEntity> list = new ArrayList<>();
try {
//循环获取方法
log.info("开始解析...");
long startTime = new Date().getTime();
for (Method method : methods) {
log.info("parsing class = '{}', method = '{}'", method.getDeclaringClass().getName(), method.getName());
List<ApiEntity> item = parser(method);
list.addAll(item);
}
log.info("解析完成, 耗时: {}ms", (new Date().getTime() - startTime));
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
/**
* 对扫描到的方法进行解析
*
* @param method 方法
* @return
*/
private List<ApiEntity> parser(Method method) {
List<ApiEntity> list = new ArrayList<>();
/**
* 同时存在RequestMapping和其它如PostMapping注解时,RequestMapping具有最高优先级
*/
if (method.getDeclaredAnnotation(RequestMapping.class) != null) {
parseRequestMapping(method, list);
return list;
}
/**
* 其它注解按顺序决定优先级
*/
Annotation[] annotations = method.getDeclaredAnnotations();
List<Annotation> annotationList = Arrays.stream(annotations).filter(annotation -> METHOD_TYPE.get(annotation.annotationType()) != null).collect(Collectors.toList());
if (CollectionUtils.isEmpty(annotationList)) {
return list;
}
Annotation annotation = annotationList.get(0);
RequestMethod methodType = METHOD_TYPE.get(annotation.annotationType());
switch (methodType) {
case POST:
parsePostMapping(method, list);
break;
case GET:
parseGetMapping(method, list);
break;
case PUT:
parsePutMapping(method, list);
break;
case DELETE:
parseDeleteMapping(method, list);
break;
case PATCH:
parsePatchMapping(method, list);
break;
default:
break;
}
return list;
}
private void parseRequestMapping(Method method, List<ApiEntity> list) {
RequestMapping annotation = method.getDeclaredAnnotation(RequestMapping.class);
if (annotation != null) {
List<String> paths = new ArrayList<>(Arrays.asList(annotation.value()));
RequestMethod[] methods = annotation.method();
if (methods.length == 0) {
methods = RequestMethod.values();
}
//处理接口前缀
addPrefix(method, paths);
for (String path : paths) {
for (RequestMethod methodType : methods) {
ApiEntity api = new ApiEntity(path, methodType.name());
//补充接口描述信息
parseSwaggerAnnotation(method, api);
list.add(api);
}
}
}
}
private void parseGetMapping(Method method, List<ApiEntity> list) {
GetMapping annotation = method.getDeclaredAnnotation(GetMapping.class);
if (annotation == null) {
return;
}
parseApiEntity(method, list, annotation.value(), GET.name());
}
private void parsePostMapping(Method method, List<ApiEntity> list) {
PostMapping annotation = method.getDeclaredAnnotation(PostMapping.class);
if (annotation == null) {
return;
}
parseApiEntity(method, list, annotation.value(), POST.name());
}
private void parsePutMapping(Method method, List<ApiEntity> list) {
PutMapping annotation = method.getDeclaredAnnotation(PutMapping.class);
parseApiEntity(method, list, annotation.value(), PUT.name());
}
private void parseDeleteMapping(Method method, List<ApiEntity> list) {
DeleteMapping annotation = method.getDeclaredAnnotation(DeleteMapping.class);
parseApiEntity(method, list, annotation.value(), DELETE.name());
}
private void parsePatchMapping(Method method, List<ApiEntity> list) {
PatchMapping annotation = method.getDeclaredAnnotation(PatchMapping.class);
parseApiEntity(method, list, annotation.value(), PATCH.name());
}
private void parseApiEntity(Method method, List<ApiEntity> list, String[] pathArr, String methodType) {
List<String> paths = new ArrayList<>(Arrays.asList(pathArr));
//处理根路径
addPrefix(method, paths);
for (String path : paths) {
ApiEntity api = new ApiEntity(path, methodType);
//补充接口描述信息
parseSwaggerAnnotation(method, api);
list.add(api);
}
}
/**
* 拼接Controller类上的路径前缀
*
* @param method
* @param paths
*/
private void addPrefix(Method method, List<String> paths) {
if (CollectionUtils.isEmpty(paths)) {
paths.add("");
}
paths = paths.stream().map(path -> path.startsWith("/") ? path : "/" + path).collect(Collectors.toList());
RequestMapping rootMapping = method.getDeclaringClass().getAnnotation(RequestMapping.class);
if (rootMapping == null || rootMapping.value().length == 0) {
return;
}
String[] roots = rootMapping.value();
for (String root : roots) {
paths = paths.stream().map(path -> {
String prefix = root.endsWith("/") ? root.substring(0, root.length() - 1) : root;
path = prefix + path;
return path;
}).collect(Collectors.toList());
}
}
/**
* 解析swagger注解
*
* @param method
* @param entity
* @return
*/
private ApiEntity parseSwaggerAnnotation(Method method, ApiEntity entity) {
Api api = method.getDeclaringClass().getAnnotation(Api.class);
if (api != null && api.tags().length > 0) {
String[] tags = api.tags();
entity.setModuleName(tags[0]);
}
ApiOperation apiOperation = method.getDeclaredAnnotation(ApiOperation.class);
if (apiOperation != null) {
entity.setName(apiOperation.value());
entity.setRemark(apiOperation.notes());
}
return entity;
}
}
3 使用示例
public static void main(String[] args) {
List<ApiEntity> list = new ApiUtil(new ApiConfigBuilder()
.forPackage("com.dwp.project")
.addAnnotations(ApiOperation.class)
.build()
).scanApis();
System.out.println(list);
}
给大家推荐一个程序员必备网站,功能方便、实用,页面精美,下面是部分功能截图:
代码生成
云剪切板
工作日报生成
专利文章生成
毕业论文生成
点击访问