You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Web中获取@RestController完整URL及关联基础URL的方法

如何在Spring Web中获取@RestController的完整URL及基础路径

我来帮你搞定这两个问题,结合你给出的ServiceEnumerator代码示例,下面是具体的实现方案:

一、获取单个@RestController对应的完整URL

要拿到控制器对应的完整URL,得把三个部分拼起来:

  • 应用的上下文路径(如果配置了server.servlet.context-path的话)
  • 控制器类上的类级别请求映射路径(比如@RequestMapping("/api"))
  • 控制器方法上的方法级别请求映射路径(比如@GetMapping("/users/{id}"))

举个实际例子:

@RestController
@RequestMapping("/api/users")
public class UserController {
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        // 业务逻辑
    }
}

如果你的应用上下文路径是/my-app,那这个方法的完整URL就是/my-app/api/users/{id}。

二、通过ApplicationContext获取所有@RestController的基础URL

你已经通过context.getBeansWithAnnotation(RestController.class)拿到了所有RestController Bean,接下来有两种靠谱的方式获取它们的基础URL:

方式1:反射读取类上的请求映射注解

直接通过反射读取控制器类上的@RequestMapping(或它的派生注解)的路径值,代码可以这样改:

@Component
public class ServiceEnumerator {
    @Autowired
    private ApplicationContext context;

    // 注入上下文路径,默认是空字符串(没配置的情况)
    @Value("${server.servlet.context-path:}")
    private String contextPath;

    @PostConstruct
    private void postConstruct() {
        final Map<String, Object> restControllers = context.getBeansWithAnnotation(RestController.class);
        
        for (Object controllerBean : restControllers.values()) {
            Class<?> controllerClass = controllerBean.getClass();
            // 处理Spring生成的CGLIB代理类,拿到真实的控制器类
            if (controllerClass.getName().contains("$$EnhancerBySpringCGLIB$$")) {
                controllerClass = controllerClass.getSuperclass();
            }
            
            // 获取类级别的@RequestMapping注解(包括@GetMapping等派生注解)
            RequestMapping classLevelMapping = controllerClass.getAnnotation(RequestMapping.class);
            if (classLevelMapping != null) {
                String[] basePaths = classLevelMapping.value();
                for (String basePath : basePaths) {
                    // 拼接上下文路径和基础路径,处理重复斜杠的情况
                    String fullBaseUrl = contextPath + basePath;
                    fullBaseUrl = fullBaseUrl.replaceAll("//", "/");
                    System.out.println("RestController基础URL前缀:" + fullBaseUrl);
                }
            } else {
                // 如果没有类级别映射,基础路径就是上下文路径(或根路径)
                String fullBaseUrl = contextPath.isEmpty() ? "/" : contextPath;
                System.out.println("RestController基础URL前缀:" + fullBaseUrl);
            }
        }
    }
}

方式2:用Spring的RequestMappingHandlerMapping(更推荐)

Spring的RequestMappingHandlerMapping维护了所有请求映射的元数据,包括类和方法的完整路径,用它能更准确地获取信息,还能自动处理代理类等问题:

@Component
public class ServiceEnumerator {
    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @PostConstruct
    private void postConstruct() {
        // 获取所有已注册的请求映射
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
        
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
            RequestMappingInfo mappingInfo = entry.getKey();
            HandlerMethod handlerMethod = entry.getValue();
            
            // 判断当前方法所属的类是否是@RestController
            if (handlerMethod.getBeanType().isAnnotationPresent(RestController.class)) {
                // 获取所有路径模式(包括方法级别的)
                Set<String> pathPatterns = mappingInfo.getPathPatternsCondition().getPatterns();
                // 读取上下文路径
                String contextPath = requestMappingHandlerMapping.getApplicationContext()
                        .getEnvironment().getProperty("server.servlet.context-path", "");
                
                for (String pathPattern : pathPatterns) {
                    String fullUrl = contextPath + pathPattern;
                    fullUrl = fullUrl.replaceAll("//", "/");
                    System.out.println("完整请求URL:" + fullUrl);
                    System.out.println("所属控制器:" + handlerMethod.getBeanType().getSimpleName());
                }
            }
        }
    }
}

这种方式的好处:

  • 自动处理代理类,不用手动判断父类
  • 直接拿到包含方法级别的完整路径,支持路径变量、通配符等
  • 能准确获取Spring解析后的路径规则

几个关键注意事项

  • 上下文路径不要忘:如果你的应用配置了server.servlet.context-path,一定要拼接进去,否则得到的是相对路径
  • 代理类处理:Spring可能会给Bean生成CGLIB代理,这时候直接getClass()拿到的是代理类,要切换到父类才能读取到真实的注解信息
  • 派生注解兼容:类级别如果用了@GetMapping、@PostMapping这类派生注解,getAnnotation(RequestMapping.class)依然能读取到路径,因为它们本身就包含@RequestMapping的元数据

内容的提问来源于stack exchange,提问作者Jonathan S. Fisher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:48:00