如何在 Spring Boot 中为所有控制器指定前缀?

Posted

技术标签:

【中文标题】如何在 Spring Boot 中为所有控制器指定前缀?【英文标题】:How to specify prefix for all controllers in Spring Boot? 【发布时间】:2015-03-16 09:19:23 【问题描述】:

我有到/user/order 的控制器映射:

@RestController
@RequestMapping("/users")
public class UserController 
    ...


@RestController
@RequestMapping("/orders")
public class OrderController 
    ...

我想通过 URL 分别访问 http://localhost:8080/api/usershttp://localhost:8080/api/orders

如何在 Spring Boot 中实现这一点?

【问题讨论】:

Spring Boot Context Root的可能重复 【参考方案1】:

您可以在自定义配置中提供到 Spring Boot 应用程序的根上下文路径到 /api/* 的映射。

import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;

@Configuration
public class DispatcherServletCustomConfiguration 

    @Bean
    public DispatcherServlet dispatcherServlet() 
        return new DispatcherServlet();
    

    @Bean
    public ServletRegistrationBean dispatcherServletRegistration() 
        ServletRegistrationBean registration = new ServletRegistrationBean(
                dispatcherServlet(), "/api/");
        registration.setName(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
        return registration;
    

或将其添加到您的application.properties src\main\resources 文件夹中

server.contextPath=/api/*

编辑

As of Spring Boot 2.x the property has been deprecated 应替换为

server.servlet.contextPath=/api/*

您可以在此处Spring Boot Context Root 和此处Add servlet mapping to DispatcherServlet 找到更多信息

【讨论】:

这会将前缀添加到所有内容,而不仅仅是控制器 它应该只是 "server.contextPath=/api/" 。在 Spring Boot 版本 1.3.5 中有一个尾随 * 会导致错误 请注意,org.springframework.boot.context.embedded.ServletRegistrationBean 在 1.4 中已被弃用,并引入了它的替代品 org.springframework.boot.web.servlet.ServletRegistrationBean。在 1.5 中删除了已弃用的类 位于application.properties 文件中的server.servlet.context-path = /api/* 给了我Error registering Tomcat:type=TomcatEmbeddedWebappClassLoader,host=localhost,context=/api/* - ContextPath must start with '/' and not end with '/' 错误。不带引号的 server.servlet.context-path = /api 属性是应用程序启动所需的属性。 对于 Spring Boot 2.0,它必须像 server.servlet.context-path=/api【参考方案2】:

如果您只想为某些控制器添加前缀,我找到了另外两个解决方案

选项 1 - 使用 spring SpEL 为您的控制器添加前缀变量

@RestController
@RequestMapping(path = "$v1API/users")
public class V1FruitsController 

    @GetMapping(path = "")
    @ResponseBody
    public String list()
        return "[\"Joe\", \"Peter\"]";
    

application.properties

v1API=/api/v1

选项 2 - 创建自定义控制器注释

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@RequestMapping("/api/v1")
public @interface V1APIController 
    @AliasFor(annotation = Component.class)
    String value() default "";



@V1APIController
public class UserController 

    @RequestMapping("/users")
    @ReponseBody
    public String index()
        return "[\"Joe\", \"Peter\"]";
    

然后测试一下

curl -X GET localhost:8080/api/v1/users

【讨论】:

是的,但是如果你的 UserController 中有很多方法呢?现在你已经权衡了在类级别编写 @RequestMapping("/api/users") 来为每个方法的 RequestMapping 加上 "users" 前缀。 您使用@Component 作为注解和别名而不是@RestController 有什么原因吗? @JimBob 不,你也可以使用@RestController【参考方案3】:

如果您使用的是spring boot 2(spring framework 5),则application.properties中的属性有一个替换:

server.contextPath

为:

server.servlet.context-path=

【讨论】:

谢谢。我想添加 '/api' 前缀并由 server.servlet.context-path=/api 添加【参考方案4】:

application.properties 中添加您的默认路径为:

server.servlet.contextPath=/mainPath

这里/mainPath是所有控制器的前缀

【讨论】:

在我当前版本的 spring boot 中,该属性名称是 context-path。【参考方案5】:

除了关于更改上下文路径的应用程序属性的其他 cmets,您还可以在 Spring Boot 2.3.1 中使用应用程序属性单独设置调度程序 servlet 的前缀。

spring.mvc.servlet.path=/api

请求映射不会在您的控制器中更改。虽然上下文路径将整个应用程序移动到不同的路径,但 servlet 路径仅限制调度程序 servlet 处理的 URL。 servlet 路径相当于 web.xml 中的 servlet 映射。其他不使用的资源 可以从任何其他 URL 访问调度程序 servlet。

如果您有其他未映射到 /api 前缀的控制器,那么这将不起作用,除非您为这些控制器声明具有不同前缀的第二个调度程序 servlet。

【讨论】:

【参考方案6】:

对于那些感兴趣的人,这里是 Kotlin 对 deFreitas' Option 2 Component 的看法,因为我无法在 application.yaml 中使用 spring.data.rest.basePathserver.servlet.contextPath。 (这是 Spring Boot 2.1.2 和 Kotlin 1.13.11)

package com.myproject.controller

import org.springframework.core.annotation.AliasFor
import org.springframework.stereotype.Component
import org.springframework.web.bind.annotation.RequestMapping

import kotlin.annotation.MustBeDocumented
import kotlin.annotation.Retention
import kotlin.annotation.Target
import kotlin.annotation.AnnotationRetention

@Target(AnnotationTarget.CLASS, AnnotationTarget.FILE)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Component
@RequestMapping("/api/v1")
annotation class V1ApiController(
    @get:AliasFor(annotation = Component::class)
    val value: String = ""
)

如果您使用的是 IntelliJ,为简洁起见,优化导入可能会删除 Kotlin 注释导入。

【讨论】:

【参考方案7】:

在 application.yml 中添加:

server:
  servlet:
    context-path: "/contextPath"

【讨论】:

【参考方案8】:

将此添加到 application.properties

server.servlet.context-path=/api/v1/

【讨论】:

【参考方案9】:

server.servlet.context-path 是正确的路径。不是server.servlet.contextPath,不幸的是它似乎不支持您可以在 web.xml 中执行的列表,如下所示:

    <servlet>
        <description>Servlet used by Spring MVC to handle all requests into the application</description>
        <servlet-name>spring</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/spring-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/app1/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/app2/*</url-pattern>
    </servlet-mapping>

【讨论】:

【参考方案10】:

附加。如果你使用.yaml,你可以写成:

server:
  servlet:
    context-path: /api

【讨论】:

以上是关于如何在 Spring Boot 中为所有控制器指定前缀?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 GET 方法中为 Spring Boot 控制器类传递多个路径变量?

忽略在 yaml 配置中为 Spring Boot 管理应用程序指定斜杠字符

如何在 Spring Boot 2 中为 Spring Batch 配置数据源以进行测试

你可以在 Spring Boot 中为多个模型设置一个控制器吗?

如何在 Spring Boot 中为 Spring LDAP 身份验证设置覆盖 BindAuthenticator handleBindException

如何在 Spring-boot 中不模拟服务类的情况下为 REST 控制器端点编写单元测试