如何在春季启动时设置基本网址?

时间:2015-10-03 22:02:51

标签: java spring rest spring-mvc

我试图在一个春季启动项目中混合使用mvc和rest。

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

可以通过example.com/whatever

访问Mvc控制器

有可能吗?

(我不使用弹簧数据休息,只需使用spring mvc)

19 个答案:

答案 0 :(得分:89)

有点晚了,但同样的问题在到达答案之前就把我带到了这里,所以我在这里发布。 创建(如果您还没有)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

答案 1 :(得分:40)

使用Spring Boot 1.2+,它只需要application.properties中的一个属性:

spring.data.rest.basePath=/api

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

答案 2 :(得分:31)

对于Spring Boot Framework版本2.0.4.RELEASE+。将此行添加到application.properties

server.servlet.context-path=/api

答案 3 :(得分:23)

由于这是针对此问题的第一个谷歌搜索,我认为会有更多人搜索此问题。自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);
                    }
                };
            }
        };
    }
}

答案 4 :(得分:21)

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

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

  1. 通过在server.context-path=/api中设置application.properties,您可以为所有内容配置前缀。(其server.context-path不是server.contextPath!)
  2. 使用@RepositoryRestController注释的Spring Data Controller将存储库公开为rest端点,将使用spring.data.rest.base-path中的环境变量application.properties。但简单@RestController不会考虑到这一点。根据{{​​3}},您可以使用注释@BasePathAwareController。但是当我尝试保护这样的控制器时,我确实遇到了与Spring-security有关的问题。它已经不存在了。
  3. 另一种解决方法是一个简单的技巧。您不能在注释中为静态String添加前缀,但可以使用如下表达式:

    @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\"}";
      }
    }
    

答案 5 :(得分:10)

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

答案 6 :(得分: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 - 控制器默认为dispatcherServletrestApi中定义的@RestControllers调度程序为rest.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,您可以使用任何其他可用的上下文类型,即。 AnnotationConfigWebApplicationContextGenericWebApplicationContextGroovyWebApplicationContext,...
  • 在休息上下文中定义jsonMessageConvertermessageConverters bean,它们可以在父上下文中定义

答案 7 :(得分:7)

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

spring:
    data:
        rest:
            basePath: /api

我记得很清楚 - 你的所有存储库都会暴露在这个URI之下。

答案 8 :(得分:6)

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

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

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

刚刚测试过 - 在Spring 4.2中运行!

答案 9 :(得分:5)

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

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

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

答案 10 :(得分:3)

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

@Configuration
public class WebMvcConfig implements WebMvcConfigurer  {

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

答案 11 :(得分:2)

适用于使用YAML配置(application.yaml)的用户。

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

server:
  servlet:
    contextPath: /api

如果您仍在使用Spring Boot 1.x

server:
  contextPath: /api

答案 12 :(得分:1)

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

欢呼

答案 13 :(得分:1)

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

spring.mvc.servlet.path=/api

答案 14 :(得分:0)

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

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 来更改上下文路径。

答案 15 :(得分:0)

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

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

在Spring 4.2中工作正常!

答案 16 :(得分:0)

有效的server.contextPath = / path

答案 17 :(得分:0)

每个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来澄清文档。)

答案 18 :(得分:0)

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

  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+)都应支持。 / p>