Wie setze ich die Basis-URL für die Ruhe im Frühlingsstiefel?

118

Ich versuche, mvc zu mischen und mich in einem einzigen Spring-Boot-Projekt auszuruhen.

Ich möchte den Basispfad für alle Rest-Controller (z. B. example.com/api) an einem einzigen Ort festlegen (ich möchte nicht jeden Controller mit Anmerkungen versehen @RequestMapping('api/products') stattdessen nur@RequestMapping('/products') .

Mvc-Controller sollten über example.com/whatever zugänglich sein

Ist es möglich?

(Ich benutze keine Federdatenruhe, nur Feder-MVC)

Teimuraz
quelle
Werfen
Sie
server.servlet.contextPath = / api
Daniel T. Sobrosa
Spring Boot Version 2.1.4.RELEASE, spring.mvc.servlet.path = / api und server.servlet.context-path = / api, beide Werke
Prayag Sharma
Die Lösung server.servlet.context-path = / api ist für die ANWENDUNG vorgesehen, nicht nur für REST. Es gilt auch für SOAP-Dienste. Wenn Sie Ihren SOAP- und REST-Servicepfad wechseln möchten, sollten Sie @RequestMapping ('api / ...') ... medium.com/@bm.celalkartal/…
bmck

Antworten:

89

Mit Spring Boot 1.2+ (<2.0) ist lediglich eine einzige Eigenschaft in application.properties erforderlich:

spring.data.rest.basePath=/api

Referenzlink: https://docs.spring.io/spring-data/rest/docs/current/reference/html/#getting-started.changing-base-uri

Verwenden Sie für 2.x.

server.servlet.context-path=/api
Suroj
quelle
4
Dies ist die genaue Antwort, die Thorinkor gegeben hat.
Jean-François Beauchef
8
Danke, aber das funktioniert bei mir in Spring Boot Version v1.5.7.RELEASE nicht. Die andere Antwort server.contextPath = / api funktionierte
Jay
10
@Suroj Diese Lösung funktioniert nur mit RepositoryRestController annotierten Controllern, nicht mit RestController ...
Nano
jira.spring.io/browse/DATAREST-1211 In diesem Jira-Ticket wird erwähnt, dass es sich um "spring.data.rest.base-path for Spring Boot 2.0.0" handelt. Leider arbeiten beide nicht für mich.
Carsten Hagemann
6
für SB 2+ ist es server.servlet.context-path = / url
vicky
95

Ein bisschen spät, aber die gleiche Frage brachte mich hierher, bevor ich die Antwort erreichte, also poste ich sie hier. Erstellen Sie (falls Sie es noch nicht haben) eine application.properties und fügen Sie sie hinzu

server.contextPath=/api

Wenn Sie also im vorherigen Beispiel einen RestController dabei @RequestMapping("/test")haben, greifen Sie wie folgt darauf zulocalhost:8080/api/test/{your_rest_method}

Frage Quelle: Wie wähle ich die URL für meine Spring Boot Webapp

OriolBG
quelle
19
Wie erzwingen Sie dies, um nur mit RestControllern zu arbeiten und auf die normalen Controller ohne das "/ api"
zuzugreifen
@Stoan Ich habe eine Lösung gefunden, überprüfe meine Antwort :-)
Kravemir
Tu das nicht! Siehe die Antwort von Thorinkor.
Stefan
Die Antwort von Thorinkor bezieht sich speziell auf Spring Data REST.
8
server.contextPath ist jetzt veraltet. Verwenden Sie stattdessen server.servlet.context-path
DS.
46

Für Spring Boot Framework Version 2.0.4.RELEASE+. Fügen Sie diese Zeile hinzuapplication.properties

server.servlet.context-path=/api
Shellhub
quelle
1
Dies betrifft auch den öffentlichen Ordner :-(
Michel
5
Dies ist die richtige Antwort für Spring Boot 2+. spring.data.rest.basePathfunktioniert nicht für Spring Boot 2
Jackycflau
27

Da dies der erste Google-Treffer für das Problem ist und ich davon ausgehe, dass mehr Leute danach suchen werden. Seit Spring Boot '1.4.0' gibt es eine neue Option. Es ist jetzt möglich, ein benutzerdefiniertes RequestMappingHandlerMapping zu definieren, mit dem ein anderer Pfad für mit @RestController kommentierte Klassen definiert werden kann

Eine andere Version mit benutzerdefinierten Anmerkungen, die @RestController mit @RequestMapping kombiniert , finden Sie in diesem Blogbeitrag

@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);
                    }
                };
            }
        };
    }
}
mh-dev
quelle
2
Arbeiten Sie in Spring Boot 2.0.0+ die WebMvcRegistrations-Oberfläche direkt ab. WebMvcRegistrationsAdapter wurde entfernt, um der Schnittstelle Standardmethoden hinzuzufügen.
Der Gilbert Arenas Dolch
26

Ich konnte nicht glauben, wie kompliziert die Antwort auf diese scheinbar einfache Frage ist. Hier einige Referenzen:

Es gibt viele verschiedene Dinge zu beachten:

  1. Durch die Einstellung server.context-path=/apiin application.propertiesSie können ein Präfix für konfigurieren alles . (Sein server.context-Pfad nicht server.contextPath!)
  2. Mit @RepositoryRestController kommentierte Spring Data Controller, die ein Repository als Restendpunkt verfügbar machen, verwenden die Umgebungsvariable spring.data.rest.base-pathin application.properties. Aber einfach @RestControllerwird dies nicht berücksichtigt. Laut der Dokumentation der Federdatenreste gibt es eine Anmerkung @BasePathAwareController, die Sie dafür verwenden können. Ich habe jedoch Probleme mit der Spring-Sicherheit, wenn ich versuche, einen solchen Controller zu sichern. Es wird nicht mehr gefunden.

Eine weitere Problemumgehung ist ein einfacher Trick. Sie können einer Annotation keinen statischen String voranstellen, aber Sie können Ausdrücke wie diesen verwenden:

@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\"}";
  }
}
Robert
quelle
Wie würden Sie in Annotation einfügen?
Teimuraz
2
meh, dann müssen Sie immer daran denken, dieses Präfix jedes Mal hinzuzufügen, wenn Sie einen neuen Controller erstellen
The Gilbert Arenas Dagger
13

Für Boot 2.0.0+ funktioniert dies für mich: server.servlet.context-path = / api

Juan Carlos Vergara Santos
quelle
4
Das hat anscheinend alles unter / api gestellt, nicht nur @ RestController-Mapper. Danke trotzdem. Ihre Informationen sind immer noch nützlich.
Eigil
9

Ich habe eine saubere Lösung gefunden, die nur Rest-Controller betrifft.

@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 registriert zwei Dispatcher-Servlets - Standard dispatcherServletfür Controller und restApiDispatcher für @RestControllersdefiniert in 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 [/]

Das Beispiel 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>

Sie sind jedoch nicht beschränkt auf :

  • Verwenden XmlWebApplicationContextSie, können Sie einen anderen verfügbaren Kontexttyp verwenden, z. AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • definieren jsonMessageConverter, messageConvertersBeans im Ruhekontext, sie können im übergeordneten Kontext definiert werden
Kravemir
quelle
Ist dies programmgesteuert ohne Verwendung der XML möglich?
Arian
@ArianHosseinzadeh Ja. Es ist möglich, dies programmgesteuert zu tun. Es gibt viele Möglichkeiten, den Frühlingskontext einzurichten. Im Beispiel habe ich gezeigt, wie ein untergeordneter Kontext für die Behandlung der REST-API erstellt wird. Lernen Sie einfach, wie Sie den Kontext in Java einrichten, und kombinieren Sie dieses Wissen mit dem Wissen in dieser Antwort. Das nennt man Programmierung.
Kravemir
7

Sie können eine benutzerdefinierte Anmerkung für Ihre Controller erstellen:

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

Verwenden Sie es anstelle des üblichen @RestControllers für Ihre Controller-Klassen und kommentieren Sie Methoden mit @RequestMapping.

Gerade getestet - funktioniert im Frühjahr 4.2!

Ilya Novoseltsev
quelle
Danke dir. Ich habe es versucht. Aber jetzt muss ich jede Methode mit @RequestMapping ("/ products"), @RequestMapping ("/ products / {id}") kommentieren. Stattdessen muss ich Controller mit @RequestMapping ("/ products") und Methoden mit @RequestMapping, @RequestMapping ("/: id") mit Anmerkungen versehen. Und der Produkt-Controller sollte über API / Produkte erreichbar sein (z. B. API-Präfix an einer einzigen Stelle festlegen)
Teimuraz,
2
In diesem Fall gibt es keine sofort einsatzbereite Lösung, AFAIK. Sie können versuchen, Ihre eigenen zu implementieren RequestMappingHandlerMapping. Spring Data REST verfügt über einen Mapper, der Ihren Anforderungen entspricht BasePathAwareHandlerMapping.
Ilya Novoseltsev
@moreo, hast du eine richtige Lösung gefunden? Ich würde mich freuen, wenn Sie es als Antwort posten könnten. Ich habe hier die gleiche Anforderung.
Fischermatte
@fischermatte, Nein, ich habe nicht genau das gefunden, was ich wollte. Ich platziere @RequestMapping ("/ api / products") oder @RequestMapping ("/ api / users") vor jeder Controller-Klasse und dann vor der Methode nur ein weiteres @ RequestMapping ("/ {id}"). Aber ich denke nicht, dass dies ein großes Problem ist. Wenn ich "api" in etwas ändern möchte, werde ich es einfach zu Beginn jeder Klasse ändern.
Teimuraz
@ IlyaNovoseltsev Es gibt eine Lösung, siehe meine Antwort :-)
Kravemir
7

Ich könnte etwas spät dran sein, ABER ... Ich glaube, es ist die beste Lösung. Richten Sie es in Ihrer application.yml (oder einer analogen Konfigurationsdatei) ein:

spring:
    data:
        rest:
            basePath: /api

Soweit ich mich erinnern kann, werden alle Ihre Repositorys unter dieser URI angezeigt.

Thorinkor
quelle
Können Sie dies ein wenig erklären oder auf eine relevante Dokumentation verweisen?
Dmitry Serdiuk
1
Relevante Dokumente finden Sie unter docs.spring.io/spring-data/rest/docs/current/reference/html/… .
Bruce Szalwinski
11
Die Umgebungsvariable spring.data.rest.base-path wirkt sich nur auf Spring-Data-Rest und Spring-Hateoas aus. Plain @RestController wird immer noch an der Wurzel sitzen!
Robert
4
@thorinkor basierend auf dem, was Sie sagen, dass in den meisten Fällen Spring Data REST-Repositorys erstellt werden? Und das OP sagt eindeutig, dass er
Restkontrolleure
1
Ich denke, es wird nur funktionieren, wenn Sie SpringDataRest verwenden.
Jaumzera
6

Versuchen Sie es mit einem PathMatchConfigurer (Spring Boot 2.x):

@Configuration
public class WebMvcConfig implements WebMvcConfigurer  {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix("api", HandlerTypePredicate.forAnnotation(RestController.class));
    }
}
Harald Wendel
quelle
1
Danke, genau das habe ich gesucht! Auf diese Weise können Sie ein Kontextpfadelement für alle über diese WebMvcConfig konfigurierten RestController festlegen, ähnlich wie dies bei spring.data.rest.base-path der Fall ist.
Buurman
Ihre Antwort ist genau richtig für @HaraldWendel: +1: Sie könnten sie noch weiter verbessern, indem Sie sie ein wenig erweitern, indem Sie beispielsweise erklären, was Ihr Code genau tut (wie ich es in meinem Kommentar versucht habe) und / oder auf einen Link verweisen Javadoc oder Dokumentation, die diese Verwendung beschreibt.
Buurman
Dies ist die einzige Lösung, die für mich funktioniert hat, da ich Controller-Schnittstellen verwende
Anatoly Yakimchuk
4

Sie können eine Basisklasse mit @RequestMapping("rest")Anmerkungen erstellen und alle anderen Klassen mit dieser Basisklasse erweitern.

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

Jetzt sind alle Klassen zugänglich, die diese Basisklasse erweitern rest/**.

Saket Mehta
quelle
3
Dies ist keine korrekte Antwort. Der Benutzer bezieht sich auf die Controller-Anmerkung. Wenn Sie eine abstrakte Klasse mit einer RequestMapping-Annotation erweitern und die neue Klasse auch über eine RequestMapping-Annotation verfügt, überschreibt diese letzte die erste und verkettet die beiden nicht.
Massimo
Ist Ihnen bekannt, dass Annotationen nicht in Java vererbt werden, es sei denn, es hat Meta-Annotationen geerbt? Überprüfen Sie dies: stackoverflow.com/a/21409651 . Und @RequestMapping scheint das nicht zu haben: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
Mashrur
2

Für diejenigen, die die YAML-Konfiguration verwenden (application.yaml).

Hinweis : Dies funktioniert nur fürSpring Boot 2.x.x

server:
  servlet:
    contextPath: /api

Wenn Sie noch verwenden Spring Boot 1.x

server:
  contextPath: /api
Prasanth Rajendran
quelle
1

Mit Spring-Boot 2.x können Sie in application.properties Folgendes konfigurieren:

spring.mvc.servlet.path=/api
Bulgar Sadykov
quelle
1

server.servlet.context-path=/apiwäre die Lösung, denke ich. Ich hatte das gleiche Problem und das hat mich gelöst. Ich habe server.context-path verwendet. Das schien jedoch veraltet zu sein und ich fand, dass server.servlet.context-pathdas Problem jetzt gelöst ist. Eine weitere Problemumgehung war das Hinzufügen eines Basis-Tags zu meinen Front-End-Seiten (H5). Ich hoffe das hilft jemandem da draußen.

Prost

Rahul Talreja
quelle
0

Diese Lösung gilt, wenn:

  1. Sie möchten ein Präfix setzen, RestControlleraber nicht Controller.
  2. Sie verwenden Spring Data Rest nicht.

    @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);
        }
    }

    }}

Dies ähnelt der von mh-dev veröffentlichten Lösung , aber ich denke, dies ist ein wenig sauberer und sollte auf jeder Version von Spring Boot 1.4.0+, einschließlich 2.0.0+, unterstützt werden.

Der Gilbert Arenas Dolch
quelle
Wenn ich Pageable in meinem RestControler verwende, gibt mir API / etwas keinen primären oder Standardkonstruktor für die Schnittstelle org.springframework.data.domain.Pageable gefunden
K. Ayoub
0

Verwenden Sie in Spring Data REST- Dokumenten , wenn Sie application.properties verwenden, diese Eigenschaft, um Ihren Basispfad festzulegen:

spring.data.rest.basePath=/api

Beachten Sie jedoch, dass Spring eine entspannte Bindung verwendet , sodass diese Variante verwendet werden kann:

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

... oder dieses, wenn Sie es vorziehen:

spring.data.rest.base_path=/api

Wenn Sie application.yml verwenden , würden Sie Doppelpunkte für Schlüsseltrennzeichen verwenden:

spring:
  data:
    rest:
      basePath: /api

(Als Referenz wurde im März 2018 ein entsprechendes Ticket erstellt, um die Dokumente zu verdeutlichen.)

J Waldmurmeltier
quelle
0

arbeitete server.contextPath = / path

Pravin
quelle
0

Sie können eine benutzerdefinierte Anmerkung für Ihre Controller erstellen:

Verwenden Sie es anstelle des üblichen @RestControllers für Ihre Controller-Klassen und kommentieren Sie Methoden mit @RequestMapping.

Funktioniert gut im Frühjahr 4.2!

Prerit Neema
quelle