Jak ustawić podstawowy adres URL do odpoczynku w wiosennym rozruchu?


118

Próbuję połączyć mvc i resztę w jednym projekcie buta sprężynowego.

Chcę ustawić ścieżkę bazową dla wszystkich pozostałych kontrolerów (np. Example.com/api) w jednym miejscu (nie chcę @RequestMapping('api/products')zamiast tego przypisywać do każdego kontrolera adnotacji po prostu @RequestMapping('/products').

Dostęp do kontrolerów MVC powinien być możliwy pod adresem example.com/cokolwiek

Czy to możliwe?

(Nie używam sprężynowej podpórki danych, tylko sprężynowe MVC)


spójrz na tę dokumentację. spring.io/spring-framework/docs/current/…
— leeor

server.servlet.contextPath = / api
— Daniel T. Sobrosa

Spring boot w wersji 2.1.4.RELEASE, spring.mvc.servlet.path = / api i server.servlet.context-path = / api, obie działają
— Prayag Sharma

server.servlet.context-path = / api rozwiązanie jest przeznaczone dla APLIKACJI, a nie tylko dla REST. Dotyczy to również usług SOAP. Jeśli chcesz podzielić swoją ścieżkę usług SOAP i REST, powinieneś użyć @RequestMapping ('api / ...') ... medium.com/@bm.celalkartal/
— bmck

Odpowiedzi:


89

W przypadku Spring Boot 1.2+ (<2.0) wystarczy jedna właściwość w application.properties:

spring.data.rest.basePath=/api

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

W przypadku wersji 2.x użyj

server.servlet.context-path=/api

4
To jest dokładna odpowiedź, której udzielił Thorinkor.
— Jean-François Beauchef

8
Dzięki, ale to nie działa dla mnie w wersji Spring Boot 1.5.7.RELEASE. Druga odpowiedź server.contextPath = / api działała
— Jay

10
@Suroj To rozwiązanie działa tylko z kontrolerami z adnotacjami RepositoryRestController, a nie z RestController ...
— Nano

jira.spring.io/browse/DATAREST-1211 W tym pakiecie Jira Ticket wspomniano, że jest to „spring.data.rest.base-path dla Spring Boot 2.0.0”. Niestety oba nie działają dla mnie.
— Carsten Hagemann

6
dla SB 2+ jest to server.servlet.context-path = / url
— vicky

96

Trochę późno, ale to samo pytanie przywiodło mnie tutaj, zanim dotarłem do odpowiedzi, więc zamieszczam je tutaj. Utwórz (jeśli nadal go nie masz) plik application.properties i dodaj

server.contextPath=/api

Więc w poprzednim przykładzie, jeśli masz RestController, @RequestMapping("/test")uzyskasz do niego dostęp jaklocalhost:8080/api/test/{your_rest_method}

źródło pytania: jak wybrać adres URL mojej aplikacji webowej rozruchowej wiosny


19
Jak wymusić to, aby działało tylko z RestControllers i uzyskać dostęp do zwykłych kontrolerów bez „/ api”
— Siya Sosibo

@Stoan znalazłem rozwiązanie, sprawdź moją odpowiedź :-)
— kravemir

Nie rób tego! Zobacz odpowiedź Thorinkora.
— Stefan,

Odpowiedź Thorinkora dotyczy specjalnie Spring Data REST.

8
server.contextPath jest teraz przestarzała, użyj zamiast tego server.servlet.context-path
— DS.

46

Do wersji szkieletowej do butów sprężynowych 2.0.4.RELEASE+. Dodaj tę linię doapplication.properties

server.servlet.context-path=/api

1
Ma to również wpływ na folder publiczny :-(
— Michel

5
to jest poprawna odpowiedź dla Spring boot 2+. spring.data.rest.basePathnie działa dla Spring boot 2
— jackycflau

27

Ponieważ jest to pierwsze trafienie Google dotyczące problemu i zakładam, że więcej osób będzie tego szukało. Pojawiła się nowa opcja od wersji Spring Boot „1.4.0”. Można teraz zdefiniować niestandardowy RequestMappingHandlerMapping, który pozwala zdefiniować inną ścieżkę dla klas z adnotacją @RestController

Inną wersję z niestandardowymi adnotacjami, która łączy @RestController z @RequestMapping, można znaleźć w tym poście na blogu

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

2
W Spring Boot 2.0.0+ możesz pracować bezpośrednio z interfejsu WebMvcRegistrations. WebMvcRegistrationsAdapter został usunięty na rzecz dodania domyślnych metod do interfejsu.
— The Gilbert Arenas Dagger

27

Nie mogłem uwierzyć, jak skomplikowana jest odpowiedź na to pozornie proste pytanie. Oto kilka odniesień:

Należy wziąć pod uwagę wiele różnych kwestii:

  1. Ustawiając server.context-path=/apiw application.properties, możesz skonfigurować prefiks dla wszystkiego (jego server.context-path, a nie server.contextPath!)
  2. Kontrolery Spring Data z adnotacją @RepositoryRestController, które ujawniają repozytorium jako punkt końcowy reszty, będą używać zmiennej środowiskowej spring.data.rest.base-pathw application.properties. Ale zwykły @RestControllernie weźmie tego pod uwagę. Zgodnie z dokumentacją danych sprężynowych istnieje adnotacja @BasePathAwareController, której można użyć do tego. Ale mam problemy w związku z zabezpieczeniami Springa, kiedy próbuję zabezpieczyć taki kontroler. Już go nie znaleziono.

Innym obejściem jest prosta sztuczka. Nie możesz poprzedzić statycznego ciągu znaków w adnotacji, ale możesz użyć takich wyrażeń:

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

Jak byś włączył adnotację?
— Teimuraz,

2
Eee, to zawsze musisz pamiętać o dodawaniu tego przedrostka za każdym razem, gdy tworzysz nowy kontroler
— The Gilbert Arenas Dagger

13

W przypadku Boot 2.0.0+ działa to dla mnie: server.servlet.context-path = / api


4
Wydaje się, że to wszystko umieściło pod / api, nie tylko mappers @RestController. Ale i tak dzięki. Twoje informacje są nadal przydatne.
— eigil

9

Znalazłem czyste rozwiązanie, które dotyczy tylko odpoczynku kontrolerów.

@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 zarejestruje dwa serwlety dyspozytorskie - domyślnie dispatcherServletdla kontrolerów i restApidyspozytora dla @RestControllerszdefiniowanych w 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 [/]

Przykład 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>

Ale nie jesteś ograniczony do :

  • użyj XmlWebApplicationContext, możesz użyć dowolnego innego dostępnego typu kontekstu, tj. AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • define jsonMessageConverter, messageConvertersfasola w kontekście spoczynku, mogą być zdefiniowane w kontekście nadrzędnym

Czy można to zrobić programowo bez użycia XML?
— Arian

@ArianHosseinzadeh Yes. Można to zrobić programowo. Istnieje wiele sposobów konfigurowania kontekstu sprężyny. W tym przykładzie pokazałem, jak stworzyć kontekst potomny do obsługi REST API. Po prostu naucz się konfigurować kontekst w Javie, a następnie połącz tę wiedzę z wiedzą w tej odpowiedzi. To się nazywa programowanie.
— kravemir

7

Możesz utworzyć niestandardową adnotację dla swoich kontrolerów:

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

Użyj go zamiast zwykłego @RestController w klasach kontrolera i dodaj adnotacje za pomocą @RequestMapping.

Właśnie przetestowane - działa w Spring 4.2!


Dziękuję Ci. Próbowałem tego. Ale teraz muszę dodać adnotację do każdej metody za pomocą @RequestMapping ("/ products"), @RequestMapping ("/ products / {id}"). Zamiast tego potrzebuję adnotacji kontrolera z @RequestMapping ("/ products") i metod z @RequestMapping, @RequestMapping ("/: id"). A kontroler produktów powinien być dostępny w api / products (np. Ustaw prefiks api w jednym miejscu)
— Teimuraz

2
W takim razie nie, nie ma rozwiązania po wyjęciu z pudełka, AFAIK. Możesz spróbować zaimplementować własne RequestMappingHandlerMapping. Spring Data REST ma mapper podobny do tego, czego potrzebujesz - BasePathAwareHandlerMapping.
— Ilya Novoseltsev

@moreo, czy znalazłeś odpowiednie rozwiązanie? Byłbym szczęśliwy, gdybyś mógł wysłać to jako odpowiedź. mam tutaj te same wymagania.
— fischermatte

@fischermatte, Nie, nie znalazłem dokładnie tego, czego szukałem, umieszczam @RequestMapping ("/ api / products") lub @RequestMapping ("/ api / users") przed każdą klasą kontrolera, a przed metodą po prostu kolejny @ RequestMapping („/ {id}”). Ale nie sądzę, żeby to był duży problem, jeśli chcę zmienić „api” na coś, po prostu zmienię to na początku każdej klasy.
— Teimuraz

@IlyaNovoseltsev Jest rozwiązanie, zobacz moją odpowiedź :-)
— kravemir

7

Mogę się trochę spóźnić, ALE ... Uważam, że to najlepsze rozwiązanie. Ustaw to w pliku application.yml (lub analogicznym pliku konfiguracyjnym):

spring:
    data:
        rest:
            basePath: /api

O ile pamiętam, to wszystko - wszystkie twoje repozytoria zostaną ujawnione pod tym identyfikatorem URI.


Czy możesz to trochę wyjaśnić lub wskazać ważną dokumentację?
— Dmitry Serdiuk

1
Odpowiednie dokumenty są dostępne pod adresem docs.spring.io/spring-data/rest/docs/current/reference/html/… .
— bruce szalwinski

11
zmienna środowiskowa spring.data.rest.base-path ma wpływ tylko na odpoczynek danych wiosennych i nienawiść wiosennych. Zwykły @RestController nadal będzie siedział w katalogu głównym!
— Robert,

4
@thorinkor na podstawie tego, co mówisz, że w większości przypadków ludzie będą budować repozytoria Spring Data REST? A OP wyraźnie mówi, że ma kontrolerów odpoczynku ...
— Jean-François Beauchef

1
Myślę, że zadziała tylko wtedy, gdy używasz SpringDataRest.
— Jaumzera

6

Spróbuj użyć PathMatchConfigurer (Spring Boot 2.x):

@Configuration
public class WebMvcConfig implements WebMvcConfigurer  {

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

1
Dzięki, właśnie tego szukałem! Pozwala to ustawić element ścieżki kontekstu dla wszystkich RestControllerów skonfigurowanych za pomocą tego WebMvcConfig, podobnie jak w przypadku spring.data.rest.base-path.
— Buurman,

Twoja odpowiedź jest na miejscu @HaraldWendel: +1: Możesz ją trochę ulepszyć, rozszerzając ją nieco, na przykład wyjaśniając dokładnie, co robi twój kod (tak jak próbowałem zrobić w moim komentarzu) i / lub może link do trochę javadoc lub dokumentacja opisująca to użycie.
— Buurman

To jedyne rozwiązanie, które zadziałało, ponieważ używam interfejsów kontrolera
— Anatoly Yakimchuk

4

Możesz utworzyć klasę bazową z @RequestMapping("rest")adnotacjami i rozszerzyć wszystkie inne klasy o tę klasę bazową.

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

Teraz wszystkie klasy, które rozszerzają tę klasę bazową, będą dostępne pod adresem rest/**.


3
To nie jest poprawna odpowiedź, użytkownik odwołuje się do adnotacji kontrolera. Jeśli rozszerzysz klasę abstrakcyjną za pomocą adnotacji RequestMapping, a nowa klasa ma również RequestMapping, ta ostatnia zastąpi pierwszą, nie połączy dwóch.
— Massimo

Czy wiesz, że adnotacje nie są dziedziczone w Javie, chyba że odziedziczyła ona meta adnotację? Sprawdź to: stackoverflow.com/a/21409651 . Wydaje się, że @RequestMapping tego nie ma: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
— Mashrur

3

Dla tych, którzy używają konfiguracji YAML (application.yaml).

Uwaga : to działa tylko dlaSpring Boot 2.x.x

server:
  servlet:
    contextPath: /api

Jeśli nadal używasz Spring Boot 1.x

server:
  contextPath: /api

1

W przypadku spring-boot 2.x możesz skonfigurować w application.properties:

spring.mvc.servlet.path=/api

1

server.servlet.context-path=/apibyłoby rozwiązaniem, jak sądzę. Miałem ten sam problem i to mnie rozwiązało. Użyłem server.context-path. Wydawało się jednak, że jest to przestarzałe i stwierdziłem, że server.servlet.context-pathteraz rozwiązuje problem. Innym rozwiązaniem, które znalazłem, było dodanie tagu podstawowego do moich stron w interfejsie (H5). Mam nadzieję, że to komuś pomoże.

Twoje zdrowie


0

To rozwiązanie ma zastosowanie, jeśli:

  1. Chcesz przedrostek, RestControllerale nie Controller.
  2. Nie używasz 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);
        }
    }

    }

Jest to podobne do rozwiązania opublikowanego przez mh-dev, ale myślę, że jest trochę czystsze i powinno być obsługiwane w każdej wersji Spring Boot 1.4.0+, w tym 2.0.0+.


Jeśli używam Pageable w moim RestControler, api / coś nie daje mi żadnego podstawowego ani domyślnego konstruktora dla interfejsu org.springframework.data.domain.Pageable
— K. Ayoub

0

Zgodnie z dokumentami REST Spring Data , jeśli używasz application.properties , użyj tej właściwości, aby ustawić ścieżkę podstawową:

spring.data.rest.basePath=/api

Pamiętaj jednak, że Spring używa luźnego wiązania , więc można użyć tej odmiany:

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

... lub ten, jeśli wolisz:

spring.data.rest.base_path=/api

Jeśli używasz application.yml , użyjesz dwukropków jako separatorów kluczy:

spring:
  data:
    rest:
      basePath: /api

(Dla porównania, powiązany bilet został utworzony w marcu 2018 r., Aby wyjaśnić dokumenty.)



0

Możesz utworzyć niestandardową adnotację dla swoich kontrolerów:

Użyj go zamiast zwykłego @RestController w klasach kontrolera i dodaj adnotacje za pomocą @RequestMapping.

Działa dobrze na wiosnę 4.2!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.