基于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);
}

给大家推荐一个程序员必备网站,功能方便、实用,页面精美,下面是部分功能截图:

代码生成
在这里插入图片描述

云剪切板
在这里插入图片描述

工作日报生成
在这里插入图片描述
专利文章生成
在这里插入图片描述
毕业论文生成
在这里插入图片描述
点击访问

猜你喜欢

转载自blog.csdn.net/qq_27574367/article/details/130380254
今日推荐