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

Tei*_*raz 93 java rest spring spring-mvc spring-boot

我想在一个弹簧启动项目中混合使用mvc和rest.

我想在一个地方为所有其他控制器(例如example.com/api)设置基本路径(我不希望@RequestMapping('api/products')仅为每个控制器添加注释@RequestMapping('/products').

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

可能吗?

(我不使用spring数据休息,只是spring mvc)

Ori*_*lBG 94

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

server.contextPath=/api
Run Code Online (Sandbox Code Playgroud)

所以在前面的例子中,如果你有一个RestController,@RequestMapping("/test")你会像访问它一样localhost:8080/api/test/{your_rest_method}

问题来源:我如何为我的春季启动webapp选择网址

  • 你如何强制执行此操作只能使用RestControllers并访问没有"/ api"的普通控制器 (18认同)
  • 现在不推荐使用server.contextPath,而是使用server.servlet.context-path (6认同)

Sur*_*roj 55

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

spring.data.rest.basePath=/api
Run Code Online (Sandbox Code Playgroud)

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

  • @Suroj该解决方案仅适用于RepositoryRestController注释控制器,而不适用于RestController ... (8认同)
  • 谢谢,但这对我的Spring Boot版本v1.5.7.RELEASE不起作用.另一个答案server.contextPath =/api工作 (7认同)
  • 对于SB 2+,它是server.servlet.context-path =/url (6认同)
  • 这是thorinkor给出的确切答案. (4认同)
  • 我不明白这个答案是如何被接受或得到这么多赞成票的。正如其他几条评论所提到的,这个答案不起作用(对于 @RestController),并且相当于 6 个月前给出的另一个答案。 (3认同)
  • `server.servlet.context-path=/api` 设置所有请求的基本路径。如果您想从“/”提供静态文件(HTML、CSS Javascript),而所有 REST API 端点都应位于“/api”,则这是行不通的,因为静态 HTML 和其他文件也将从“/”提供API`。请参阅下面的其他回复! (2认同)

she*_*hub 40

对于spring boot框架版本2.0.4.RELEASE+.添加此行application.properties

server.servlet.context-path=/api
Run Code Online (Sandbox Code Playgroud)

  • 这是Spring boot 2+的正确答案.`spring.data.rest.basePath`不适用于Spring boot 2 (5认同)
  • 这也会影响公用文件夹:-( (2认同)

mh-*_*dev 26

由于这是针对该问题的第一个谷歌搜索,我认为会有更多人搜索此问题.自Spring Boot'1.4.0'以来有一个新选项.现在可以定义一个自定义RequestMappingHandlerMapping,它允许为使用@RestController注释的类定义不同的路径

可以在此博客文章中找到包含@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);
                    }
                };
            }
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 在Spring Boot 2.0.0+中,直接关闭WebMvcRegistrations接口。删除了WebMvcRegistrationsAdapter,以便向接口添加默认方法。 (2认同)

Rob*_*ert 24

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

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

  1. 通过设置server.context-path=/api,application.properties您可以为所有内容配置前缀.(其server.context-path不是server.contextPath!)
  2. 春季数据控制与@RepositoryRestController注释,揭露出一个仓库作为休息端点将使用环境变量spring.data.rest.base-pathapplication.properties.但普通@RestController不会考虑到这一点.根据spring data rest文档@BasePathAwareController,您可以使用一个注释.但是当我尝试保护这样一个控制器时,我确实遇到了与Spring-security有关的问题.它不再被发现.

另一个解决方法是一个简单的技巧.您不能在注释中为静态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\"}";
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 嗯,那么你每次创建新控制器时都要记得添加这个前缀 (4认同)

小智 18

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

@Configuration
public class WebMvcConfig implements WebMvcConfigurer  {

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

  • 谢谢,这正是我正在寻找的!这允许您为通过此 WebMvcConfig 配置的所有 RestController 设置上下文路径元素,类似于 spring.data.rest.base-path 的作用。 (3认同)

小智 16

我对这篇文章中提到的弹簧特性的差异做了一些研究。如果有人想知道的话,这是我的发现。

spring.data.rest.basePath 属性

spring.data.rest.basePath=/api
Run Code Online (Sandbox Code Playgroud)

该属性专门用于Spring Data Rest项目。它在通常的 Spring MVC 项目中不起作用。

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

server.servlet.context-path 属性

server.servlet.context-path=/api
Run Code Online (Sandbox Code Playgroud)

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

spring.mvc.servlet.path 属性

spring.mvc.servlet.path=/api
Run Code Online (Sandbox Code Playgroud)

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

结论:

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


Jua*_*tos 12

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

  • 这一切似乎都放在/ api下,而不仅仅是@RestController映射器。但是还是谢谢你。您的信息仍然有用。 (3认同)

kra*_*mir 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Spring引导将注册两个调度程序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 [/]
Run Code Online (Sandbox Code Playgroud)

例子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>
Run Code Online (Sandbox Code Playgroud)

但是,你不仅限于:

  • 使用XmlWebApplicationContext,您可以使用任何其他可用的上下文类型,即.AnnotationConfigWebApplicationContext,GenericWebApplicationContext,GroovyWebApplicationContext,...
  • 限定jsonMessageConverter,messageConverters在其余情况下豆,它们可以在父上下文中定义


tho*_*kor 7

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

spring:
    data:
        rest:
            basePath: /api
Run Code Online (Sandbox Code Playgroud)

我记得就是这样 - 所有的存储库都会暴露在这个URI下面.

  • environemnt变量`spring.data.rest.base-path`只影响spring-data-rest和spring-hateoas.普通的@RestController仍将坐在根部! (10认同)
  • @thorinkor基于你在说什么,在大多数情况下,人们将构建Spring Data REST存储库?OP清楚地说他有休息控制器...... (4认同)

Ily*_*sev 6

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

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

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

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

  • 在那种情况下,不,没有开箱即用的解决方案,AFAIK.您可以尝试实现自己的`RequestMappingHandlerMapping`.Spring Data REST有一个类似于你需要的映射器 - "BasePathAwareHandlerMapping". (2认同)

Sak*_*hta 5

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

@RequestMapping("rest")
public abstract class BaseController {}
Run Code Online (Sandbox Code Playgroud)

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

  • 这不是正确的答案,用户指的是控制器注释。如果您使用 RequestMapping 注释扩展一个抽象类,并且新类也有一个 RequestMapping,则最后一个将覆盖第一个,它不会连接两个。 (4认同)