【问题标题】:How to set base url for rest in spring boot?如何在春季启动中设置休息的基本网址?
【发布时间】:2015-12-31 21:21:27
【问题描述】:

我正在尝试将 mvc 和 rest 混合在一个 spring boot 项目中。

我想为所有的 rest 控制器设置基本路径(例如 example.com/api) 在一个地方(我不想用@RequestMapping('api/products') 注释每个控制器,而是只用@RequestMapping('/products')

应该可以通过 example.com/whatever 访问 Mvc 控制器

有可能吗?

(我不使用spring data rest,只使用spring mvc)

【问题讨论】:

  • server.servlet.contextPath=/api
  • spring boot 2.1.4.RELEASE、spring.mvc.servlet.path=/api 和 server.servlet.context-path=/api 都可以
  • server.servlet.context-path=/api 解决方案适用于 APPLICATION ,而不仅仅是 REST。它也适用于 SOAP 服务。如果你想分开你的 SOAP 和 REST 服务路径,你应该使用 @RequestMapping('api/...')... medium.com/@bm.celalkartal/…

标签: java spring rest spring-boot spring-mvc


【解决方案1】:

使用 Spring Boot 1.2+ (

spring.data.rest.basePath=/api

参考链接:https://docs.spring.io/spring-data/rest/docs/current/reference/html/#getting-started.changing-base-uri

对于 2.x,使用

server.servlet.context-path=/api

【讨论】:

  • 这是 thorinkor 给出的确切答案。
  • 谢谢,但这在 Spring Boot v1.5.7.RELEASE 中对我不起作用。另一个答案 server.contextPath=/api 工作
  • @Suroj 该解决方案仅适用于带 RepositoryRestController 注释的控制器,不适用于 RestController...
  • 对于 SB 2+ 它是 server.servlet.context-path=/url
  • 我不明白这个答案是如何被接受或获得如此多的赞成票的。正如其他几个 cmets 所提到的,这个答案不起作用(对于@RestController),相当于近 6 个月前给出的另一个答案。
【解决方案2】:

有点晚了,但同样的问题在得到答案之前把我带到了这里,所以我把它贴在这里。 创建(如果你还没有)一个 application.properties 并添加

server.contextPath=/api

因此,在前面的示例中,如果您有一个带有 @RequestMapping("/test") 的 RestController,您将像 localhost:8080/api/test/{your_rest_method} 一样访问它

问题来源:how do i choose the url for my spring boot webapp

【讨论】:

  • 你如何强制它只使用 RestControllers 并在没有“/api”的情况下访问普通控制器
  • @Stoan 我找到了解决方案,检查我的答案 :-)
  • 不要这样做!请参阅 thorinkor 的回答。
  • Thorinkor 的回答专门针对 Spring Data REST。
  • server.contextPath 现在已弃用,请改用 server.servlet.context-path
【解决方案3】:

适用于 Spring Boot 框架版本2.0.4.RELEASE+。将此行添加到application.properties

server.servlet.context-path=/api

【讨论】:

  • 这也会影响公用文件夹:-(
  • 这是 Spring boot 2+ 的正确答案。 spring.data.rest.basePath 不适用于 Spring boot 2
  • server.servlet.context-path 适用于 spring boot 2
【解决方案4】:

我无法相信这个看似简单的问题的答案是多么复杂。以下是一些参考资料:

有很多不同的事情需要考虑:

  1. 通过在application.properties 中设置server.context-path=/api,您可以为everything配置前缀。(它的server.context-path 不是server.contextPath!)
  2. 使用@RepositoryRestController 注释的Spring Data 控制器将存储库公开为rest 端点,将使用application.properties 中的环境变量spring.data.rest.base-path。但是普通的@RestController 不会考虑到这一点。根据spring data rest documentation,您可以使用注释@BasePathAwareController。但是当我尝试保护这样的控制器时,我确实遇到了与 Spring-security 相关的问题。已经找不到了。

另一种解决方法是一个简单的技巧。您不能在注解中为静态字符串添加前缀,但可以使用如下表达式:

@RestController
public class PingController {

  /**
   * Simple is alive test
   * @return <pre>{"Hello":"World"}</pre>
   */
  @RequestMapping("${spring.data.rest.base-path}/_ping")
  public String isAlive() {
    return "{\"Hello\":\"World\"}";
  }
}

【讨论】:

  • 你会如何放入Annotation?
  • meh,那么你每次创建新控制器时都要记住添加这个前缀
【解决方案5】:

由于这是该问题的第一个谷歌点击,我假设更多的人会搜索这个。自 Spring Boot '1.4.0' 以来有一个新选项。 现在可以定义一个自定义 RequestMappingHandlerMapping,它允许为使用 @RestController

注释的类定义不同的路径

可以在blog post

找到结合了 @RestController@RequestMapping 的自定义注释的不同版本
@Configuration
public class WebConfig {

    @Bean
    public WebMvcRegistrationsAdapter webMvcRegistrationsHandlerMapping() {
        return new WebMvcRegistrationsAdapter() {
            @Override
            public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
                return new RequestMappingHandlerMapping() {
                    private final static String API_BASE_PATH = "api";

                    @Override
                    protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
                        Class<?> beanType = method.getDeclaringClass();
                        if (AnnotationUtils.findAnnotation(beanType, RestController.class) != null) {
                            PatternsRequestCondition apiPattern = new PatternsRequestCondition(API_BASE_PATH)
                                    .combine(mapping.getPatternsCondition());

                            mapping = new RequestMappingInfo(mapping.getName(), apiPattern,
                                    mapping.getMethodsCondition(), mapping.getParamsCondition(),
                                    mapping.getHeadersCondition(), mapping.getConsumesCondition(),
                                    mapping.getProducesCondition(), mapping.getCustomCondition());
                        }

                        super.registerHandlerMethod(handler, method, mapping);
                    }
                };
            }
        };
    }
}

【讨论】:

  • 在 Spring Boot 2.0.0+ 中,直接关闭 WebMvcRegistrations 接口。 WebMvcRegistrationsAdapter 已被移除,以支持向接口添加默认方法。
【解决方案6】:

尝试使用 PathMatchConfigurer (Spring Boot 2.x):

@Configuration
public class WebMvcConfig implements WebMvcConfigurer  {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("api", HandlerTypePredicate.forAnnotation(RestController.class));
    }
}

【讨论】:

  • 谢谢,这正是我想要的!这允许您为通过此 WebMvcConfig 配置的所有 RestControllers 设置上下文路径元素,类似于 spring.data.rest.base-path 所做的。
  • 你的答案在@HaraldWendel 上:+1:你可以通过扩展它来进一步改进它,比如解释你的代码究竟做了什么(正如我在我的评论)和/或可能链接到一些描述此用法的 javadoc 或文档。
  • 这是唯一对我有用的解决方案,因为我正在使用控制器接口
  • 这是唯一正确的答案。它应该被标记为答案。
【解决方案7】:

您可以为控制器创建自定义注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@RestController
@RequestMapping("/test")
public @interface MyRestController {
}

在控制器类上使用它而不是通常的 @RestController 并使用 @RequestMapping 注释方法。

刚刚测试 - 在 Spring 4.2 中工作!

【讨论】:

  • 谢谢。我试过这个。但是现在我必须用@RequestMapping("/products")、@RequestMapping("/products/{id}") 来注释每个方法。相反,我需要使用 @RequestMapping("/products") 和 @RequestMapping、@RequestMapping("/:id") 来注释控制器。并且产品控制器应该可以在 api/products 访问(例如在一个地方设置 api 前缀)
  • 在那种情况下,不,没有开箱即用的解决方案,AFAIK。您可以尝试实现自己的RequestMappingHandlerMapping。 Spring Data REST 有一个类似于您需要的映射器 - BasePathAwareHandlerMapping
  • @moreo,你找到合适的解决方案了吗?如果您可以将其发布为回复,我会很高兴。我这里有同样的要求。
  • @fischermatte,不,我没有找到我想要的东西,我将 @RequestMapping("/api/products") 或 @RequestMapping("/api/users") 放在每个控制器类之前然后,在方法之前只是另一个@RequestMapping("/{id}")。但是我觉得这不是什么大问题,如果我想把“api”改成什么东西,我会在每节课开始时改。
  • @IlyaNovoseltsev 有解决办法,看我的回答:-)
【解决方案8】:

对于 Boot 2.0.0+,这对我有用:server.servlet.context-path = /api

【讨论】:

  • 这似乎把所有东西都放在了 /api 下,而不仅仅是 @RestController 映射器。不过还是谢谢。您的信息仍然有用。
【解决方案9】:

我找到了一个干净的解决方案,它只影响休息控制器。

@SpringBootApplication
public class WebApp extends SpringBootServletInitializer {

    @Autowired
    private ApplicationContext context;

    @Bean
    public ServletRegistrationBean restApi() {
        XmlWebApplicationContext applicationContext = new XmlWebApplicationContext();
        applicationContext.setParent(context);
        applicationContext.setConfigLocation("classpath:/META-INF/rest.xml");

        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        dispatcherServlet.setApplicationContext(applicationContext);

        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/rest/*");
        servletRegistrationBean.setName("restApi");

        return servletRegistrationBean;
    }

    static public void main(String[] args) throws Exception {
        SpringApplication.run(WebApp.class,args);
    }
}

Spring boot 将注册两个调度器 servlet - 默认dispatcherServlet 用于控制器,restApi 调度器用于@RestControllersrest.xml 中定义:

2016-06-07 09:06:16.205  INFO 17270 --- [           main] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'restApi' to [/rest/*]
2016-06-07 09:06:16.206  INFO 17270 --- [           main] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]

例子rest.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <context:component-scan base-package="org.example.web.rest"/>
    <mvc:annotation-driven/>

    <!-- Configure to plugin JSON as request and response in method handler -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="jsonMessageConverter"/>
            </list>
        </property>
    </bean>

    <!-- Configure bean to convert JSON to POJO and vice versa -->
    <bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    </bean>
</beans>

但是,您不限于

  • 使用XmlWebApplicationContext,您可以使用任何其他可用的上下文类型,即。 AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • 在 rest 上下文中定义 jsonMessageConvertermessageConverters bean,它们可以在父上下文中定义

【讨论】:

  • 是否可以在不使用 xml 的情况下以编程方式执行此操作?
  • @ArianHosseinzadeh 是的。可以以编程方式进行。有很多方法可以设置弹簧上下文。在示例中,我展示了如何为 REST API 处理创建子上下文。只需学习如何在 Java 中设置上下文,然后将这些知识与此答案中的知识相结合。这就是编程。
【解决方案10】:

我可能有点晚了,但是...我相信这是最好的解决方案。在你的 application.yml(或类似的配置文件)中设置它:

spring:
    data:
        rest:
            basePath: /api

据我所知,就是这样 - 您的所有存储库都将在此 URI 下公开。

【讨论】:

  • 您能稍微解释一下或指向相关文档吗?
  • 环境变量 spring.data.rest.base-path 仅影响 spring-data-rest 和 spring-hateoas。普通的 @RestController 仍将位于根目录!
  • @thorinkor 根据你的意思,在大多数情况下人们会构建 Spring Data REST 存储库?并且 OP 明确表示他有休息控制器......
  • 我认为只有在使用 SpringDataRest 时它才会起作用。
【解决方案11】:

我对该线程中提到的弹簧特性的差异进行了一些研究。如果有人想知道,这是我的发现。

spring.data.rest.basePath 属性

spring.data.rest.basePath=/api

此属性专门用于 Spring Data Rest 项目。它不适用于通常的 Spring MVC 项目。

要更改 MVC 项目中的上下文路径,您可以使用下面提到的这两个属性。让我也提一下不同之处。

server.servlet.context-path 属性

server.servlet.context-path=/api

这个设置你的 web 服务小程序上的上下文路径。此属性在 spring mvc 和 spring data rest 项目中都可以正常工作。 但是, 不同之处在于请求 url 在到达 spring 拦截器之前会被过滤掉。因此,它会在错误请求时以 HTML 响应。未定义 Spring 或您自己的自定义 JSON 响应(在 @ResponseBodyAdvice 注释类中)。为了克服这个问题,您应该使用下面的这个属性。

spring.mvc.servlet.path 属性

spring.mvc.servlet.path=/api

这将过滤 spring mvc 拦截器中的请求 URL,并在您调用错误请求时响应默认/您的自定义 JSON 响应。

结论:

所以作为OP的问题,我建议他应该使用spring.mvc.servlet.path来改变上下文路径。

【讨论】:

    【解决方案12】:

    您可以使用@RequestMapping("rest") 注释创建一个基类,并使用此基类扩展所有其他类。

    @RequestMapping("rest")
    public abstract class BaseController {}
    

    现在可以通过rest/** 访问所有扩展此基类的类。

    【讨论】:

    【解决方案13】:

    使用 spring-boot 2.x 您可以在 application.properties 中进行配置:

    spring.mvc.servlet.path=/api
    

    【讨论】:

      【解决方案14】:

      对于那些使用 YAML 配置(application.yaml)的人。

      注意:这只适用于Spring Boot 2.x.x

      server:
        servlet:
          contextPath: /api
      
      

      如果你还在使用Spring Boot 1.x

      server:
        contextPath: /api
      

      【讨论】:

        【解决方案15】:

        server.servlet.context-path=/api 将是我猜的解决方案。我有同样的问题,这让我解决了。我使用了 server.context-path。但是,这似乎已被弃用,我发现 server.servlet.context-path 现在解决了这个问题。我发现的另一个解决方法是在我的前端 (H5) 页面中添加一个基本标签。我希望这对那里的人有所帮助。

        干杯

        【讨论】:

          【解决方案16】:

          您可以为控制器创建自定义注解:

          在控制器类上使用它而不是通常的 @RestController 并使用 @RequestMapping 注释方法。

          在 Spring 4.2 中运行良好!

          【讨论】:

            【解决方案17】:

            此解决方案适用于以下情况:

            1. 你想给RestController加前缀,而不是Controller
            2. 您没有使用 Spring Data Rest。

              @Configuration
              public class WebConfig extends WebMvcConfigurationSupport {
              
              @Override
              protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
                  return new ApiAwareRequestMappingHandlerMapping();
              }
              
              private static class ApiAwareRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
              
                  private static final String API_PATH_PREFIX = "api";
              
                  @Override
                  protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
                      Class<?> beanType = method.getDeclaringClass();
                      if (AnnotationUtils.findAnnotation(beanType, RestController.class) != null) {
                          PatternsRequestCondition apiPattern = new PatternsRequestCondition(API_PATH_PREFIX)
                                  .combine(mapping.getPatternsCondition());
              
                          mapping = new RequestMappingInfo(mapping.getName(), apiPattern, mapping.getMethodsCondition(),
                                  mapping.getParamsCondition(), mapping.getHeadersCondition(), mapping.getConsumesCondition(),
                                  mapping.getProducesCondition(), mapping.getCustomCondition());
                      }
                      super.registerHandlerMethod(handler, method, mapping);
                  }
              }
              

              }

            这与 mh-dev 发布的 solution 类似,但我认为这更简洁一些,应该在任何版本的 Spring Boot 1.4.0+ 上都支持,包括 2.0.0+。

            【讨论】:

            • 如果我在我的 RestControler 中使用 Pageable,api/something 会给我找不到接口 org.springframework.data.domain.Pageable 的主要或默认构造函数
            【解决方案18】:

            根据 Spring Data REST docs,如果使用 application.properties,请使用此属性设置基本路径:

            spring.data.rest.basePath=/api
            

            但请注意 Spring uses relaxed binding,所以可以使用这种变体:

            spring.data.rest.base-path=/api
            

            ...如果您愿意,也可以选择这个:

            spring.data.rest.base_path=/api
            

            如果使用 application.yml,您将使用冒号作为键分隔符:

            spring:
              data:
                rest:
                  basePath: /api
            

            (作为参考,2018 年 3 月创建了相关的 ticket 以澄清文档。)

            【讨论】:

              【解决方案19】:

              对于 Spring WebFlux,该方法类似于 Harald 的方法,但设置了明显的 WebFlux 配置:

              @Configuration
              public class WebFluxConfig implements WebFluxConfigurer  {
              
                 @Override
                 public void configurePathMatching(PathMatchConfigurer configurer) {
                     configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
                 }
              }
              

              对于 Kotlin,它是:

              @Configuration
              class WebFluxConfig : WebFluxConfigurer {
                  override fun configurePathMatching(configurer: PathMatchConfigurer) {
                     configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
              }
              

              【讨论】:

                【解决方案20】:

                工作 server.contextPath=/path

                【讨论】:

                  猜你喜欢
                  • 2018-04-25
                  • 2021-07-14
                  • 2015-06-30
                  • 1970-01-01
                  • 2020-05-17
                  • 1970-01-01
                  • 2017-03-07
                  • 2011-07-18
                  • 1970-01-01
                  相关资源
                  最近更新 更多