springboot中获取所有controller的请求路径,适合前端自动化测试

 返回的结果(前端拿到后使用“-”分割,一边是路径,一边是请求方法类型)

获取api路径的工具类

package com.mk.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
 * ControllerScanner类用于扫描指定包路径下的所有Controller类,并获取它们的所有请求路径。
 * 该类依赖于Spring的ApplicationContext来查找所有RequestMappingHandlerMapping实例,
 * 然后通过这些实例来获取每个Controller类的请求路径。
 */
@Component
public class ControllerScanner {

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 获取指定包路径下所有Controller类的请求路径。
     *
     * @return 包含所有请求路径的集合
     */
    public Set<String> getAllControllerEndpoints() {
        String basePackage = "com.mk.module.controller"; // 指定你的 Controller 包路径
        return scanPackage(basePackage);
    }

    /**
     * 扫描指定包路径,查找所有标注了@Controller或@RestController注解的类,并获取它们的请求路径。
     *
     * @param basePackage 要扫描的包路径
     * @return 包含所有请求路径的集合
     */
    private Set<String> scanPackage(String basePackage) {
        Set<String> endpoints = new HashSet<>();
        // 创建一个ClassPathScanningCandidateComponentProvider实例,用于扫描指定包路径下的候选组件
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        // 添加过滤器,只扫描标注了@Controller或@RestController注解的类
        scanner.addIncludeFilter(new AnnotationTypeFilter(Controller.class));
        scanner.addIncludeFilter(new AnnotationTypeFilter(RestController.class));

        // 查找指定包路径下的所有候选组件
        for (BeanDefinition beanDefinition : scanner.findCandidateComponents(basePackage)) {
            try {
                // 加载类
                Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());
                // 获取类上的@RequestMapping注解路径
                String classMappingPath = getClassMappingPath(clazz);

                // 获取所有RequestMappingHandlerMapping
                Map<String, RequestMappingHandlerMapping> handlerMappings = applicationContext.getBeansOfType(RequestMappingHandlerMapping.class);

                // 遍历所有RequestMappingHandlerMapping
                for (RequestMappingHandlerMapping handlerMapping : handlerMappings.values()) {
                    // 获取所有请求映射信息和处理方法
                    Map<RequestMappingInfo, HandlerMethod> methods = handlerMapping.getHandlerMethods();

                    // 遍历所有请求映射信息
                    for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : methods.entrySet()) {
                        RequestMappingInfo requestMappingInfo = entry.getKey();
                        // 获取请求方法类型(如GET、POST等)
                        RequestMethodsRequestCondition methodsCondition = requestMappingInfo.getMethodsCondition();
                        Optional<String> optionalS = methodsCondition.getMethods().stream().findFirst().map(Enum::name);

                        HandlerMethod handlerMethod = entry.getValue();
                        // 判断处理方法是否属于当前类
                        boolean flag = handlerMethod.getBeanType() == clazz;
                        if (flag) {
                            // 获取路径模式条件
                            PathPatternsRequestCondition pathPatternsCondition = requestMappingInfo.getPathPatternsCondition();
                            if (pathPatternsCondition != null) {
                                // 获取方法的路径映射
                                Set<String> methodMappingPaths = pathPatternsCondition.getPatternValues();
                                for (String methodMappingPath : methodMappingPaths) {
                                    String fullPath;
                                    /** 如果类的路径和方法的路径相同,添加请求方法类型
                                     * 例如:/user -> /user-GET
                                     *      /user -> /user-POST
                                     *      /user -> /user-PUT
                                     *      /user -> /user-DELETE
                                     *      不需要加类路径了,每个接口方法上已经加上了
                                     */
                                    if (classMappingPath.equals(methodMappingPath)){
//                                        fullPath = classMappingPath + methodMappingPath + "-" + (optionalS.orElseGet(() -> "NOT"));
                                        endpoints.add(methodMappingPath + "-" + (optionalS.orElseGet(() -> "NOT")));
                                        break;
                                    }
                                    // 组合类的路径和方法的路径
//                                    fullPath = classMappingPath + methodMappingPath;
                                    endpoints.add(methodMappingPath + "-" + (optionalS.orElseGet(() -> "NOT")));
                                }
                            }
                        }
                    }
                }
            } catch (ClassNotFoundException e) {
                // 处理类加载异常
                e.printStackTrace();
            }
        }
        return endpoints;
    }

    /**
     * 获取指定Controller类的基路径。
     *
     * @param controllerClass 要获取路径的Controller类
     * @return 该Controller类的基路径
     */
    private String getClassMappingPath(Class<?> controllerClass) {
        // 查找类上的@RequestMapping注解
        RequestMapping classMapping = AnnotationUtils.findAnnotation(controllerClass, RequestMapping.class);
        // 如果注解存在且有值,返回注解的第一个值,否则返回空字符串
        if (classMapping != null && classMapping.value().length > 0) {
            return classMapping.value()[0];
        }
        return "";
    }
}

写一个接口调用这个方法

package com.mk.module.controller.common;

import com.mk.constant.MessageErrorConstant;
import com.mk.module.service.EmailService;
import com.mk.pojo.dto.LoginDto;
import com.mk.pojo.result.Result;
import com.mk.utils.AliOssUtil;
import com.mk.utils.ControllerScanner;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@RestController
@RequestMapping("/common")
@Slf4j
@Api(tags = "通用接口")
public class CommonController {
    
    @Autowired
    private final ControllerScanner controllerScanner;



    /**
     * 获取所有controller包下的所有接口地址
     * @return
     */
    @GetMapping("/api-paths")
    public Result<Set<String>> getAllApiPath() {
        return Result.success(controllerScanner.getAllControllerEndpoints());
    }




}

封装数据的类

package com.mk.pojo.result;

import lombok.Data;

import java.io.Serializable;

/**
 * 后端统一返回结果
 * @param <T>
 */
@Data
public class Result<T> implements Serializable {

    private Integer code; //编码:1成功,0和其它数字为失败
    private String msg; //错误信息
    private T data; //数据



    public static <T> Result<T> success(T object) {
        Result<T> result = new Result<T>();
        result.data = object;
        result.code = 1;
        return result;
    }
    public static <T> Result<T> success(String msg,T object) {
        Result<T> result = new Result<T>();
        result.data = object;
        result.code = 1;
        result.msg = msg;
        return result;
    }

    public static <T> Result<T> error(String msg) {
        Result result = new Result();
        result.msg = msg;
        result.code = 0;
        return result;
    }

}

 最后,我在gitee上有一个适合单模块开发的springboot模板,配置了一些基础的东西,拉下来就可以直接开发,可以省下很多繁琐的步骤,地址:springboot单模块开发模板

  • 12
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值