Come impostare l'URL di base per il riposo durante l'avvio primaverile?


118

Sto cercando di mescolare mvc e rest in un unico progetto di avvio a molla.

Voglio impostare il percorso di base per tutti i controller rest (es. Example.com/api) in un unico posto (non voglio annotare ogni controller con @RequestMapping('api/products'), invece, solo @RequestMapping('/products').

I controller Mvc dovrebbero essere accessibili da example.com/wunque

È possibile?

(Non uso il resto dei dati della molla, solo il mvc della molla)



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

spring boot versione 2.1.4.RELEASE, spring.mvc.servlet.path = / api e server.servlet.context-path = / api, entrambi funzionano
Prayag Sharma

server.servlet.context-path = / api soluzione è per APPLICAZIONE, non solo per REST. È valido anche per i servizi SOAP. Se vuoi separare il tuo percorso dei servizi SOAP e REST, dovresti usare @RequestMapping ('api / ...') ... medium.com/@bm.celalkartal/…
bmck

Risposte:


89

Con Spring Boot 1.2+ (<2.0) tutto ciò che serve è una singola proprietà in application.properties:

spring.data.rest.basePath=/api

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

Per 2.x, usa

server.servlet.context-path=/api

4
Questa è la risposta esatta che ha dato il thorinkor.
Jean-François Beauchef

8
Grazie, ma questo non funziona per me nella versione Spring Boot v1.5.7.RELEASE. L'altra risposta server.contextPath = / api ha funzionato
Jay

10
@Suroj Quella soluzione funziona solo con i controller annotati RepositoryRestController, non con RestController ...
Nano

jira.spring.io/browse/DATAREST-1211 Questo Jira Ticket lo menziona come "spring.data.rest.base-path for Spring Boot 2.0.0". Purtroppo, entrambi non funzionano per me.
Carsten Hagemann

6
per SB 2+ è server.servlet.context-path = / url
vicky

96

Un po 'tardi ma la stessa domanda mi ha portato qui prima di arrivare alla risposta, quindi la posto qui. Crea (se ancora non ce l'hai) un application.properties e aggiungi

server.contextPath=/api

Quindi nell'esempio precedente, se hai un RestController con, @RequestMapping("/test")lo accederai comelocalhost:8080/api/test/{your_rest_method}

fonte della domanda: come faccio a scegliere l'URL per la mia webapp di avvio primaverile


19
Come si fa a imporre questo per lavorare solo con RestController e accedere ai normali controller senza "/ api"
Siya Sosibo

@Stoan ho trovato la soluzione, controlla la mia risposta :-)
kravemir

Non farlo! Vedi la risposta di Thorinkor.
Stefan

La risposta di Thorinkor è specifica per Spring Data REST.

8
server.contextPath è ora obsoleto, utilizza invece server.servlet.context-path
DS.

46

Per la versione del framework di avvio a molla 2.0.4.RELEASE+. Aggiungi questa riga aapplication.properties

server.servlet.context-path=/api

1
Ciò influisce anche sulla cartella pubblica :-(
Michel

5
questa è la risposta corretta per Spring Boot 2+. spring.data.rest.basePathnon funziona per lo Spring Boot 2
jackycflau

27

Poiché questo è il primo risultato di Google per il problema e presumo che più persone lo cercheranno. C'è una nuova opzione da Spring Boot "1.4.0". È ora possibile definire un RequestMappingHandlerMapping personalizzato che consente di definire un percorso diverso per le classi annotate con @RestController

Una versione diversa con annotazioni personalizzate che combina @RestController con @RequestMapping può essere trovata in questo post del blog

@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
In Spring Boot 2.0.0+, lavora direttamente dall'interfaccia WebMvcRegistrations. WebMvcRegistrationsAdapter è stato rimosso a favore dell'aggiunta di metodi predefiniti all'interfaccia.
The Gilbert Arenas Dagger

27

Non potevo credere quanto fosse complicata la risposta a questa domanda apparentemente semplice. Ecco alcuni riferimenti:

Ci sono molte cose diverse da considerare:

  1. Impostando server.context-path=/apiin application.propertiespuoi configurare un prefisso per tutto (il suo percorso server.context non server.contextPath!)
  2. I controller Spring Data annotati con @RepositoryRestController che espongono un repository come endpoint rest utilizzeranno la variabile di ambiente spring.data.rest.base-pathin application.properties. Ma plain @RestControllernon ne terrà conto. Secondo la documentazione relativa ai dati di primavera, esiste un'annotazione @BasePathAwareControllerche puoi utilizzare per questo. Ma ho problemi con Spring-security quando cerco di proteggere un controller di questo tipo. Non si trova più.

Un'altra soluzione alternativa è un semplice trucco. Non è possibile aggiungere un prefisso a una stringa statica in un'annotazione, ma è possibile utilizzare espressioni come questa:

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

Come inseriresti in Annotation?
Teimuraz

2
meh, allora devi sempre ricordarti di aggiungere questo prefisso ogni volta che crei un nuovo controller
The Gilbert Arenas Dagger

13

Per Boot 2.0.0+ questo funziona per me: server.servlet.context-path = / api


4
Sembra che metta tutto sotto / api, non solo i mappatori @RestController. Ma grazie comunque. Le tue informazioni sono ancora utili.
eigil

9

Ho trovato una soluzione pulita, che riguarda solo i controller di riposo.

@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 registrerà due servlet del dispatcher: predefinito dispatcherServletper i controller e restApidispatcher per @RestControllersdefinito 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 [/]

L'esempio 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>

Ma non sei limitato a :

  • use XmlWebApplicationContext, puoi utilizzare qualsiasi altro tipo di contesto disponibile, ad es. AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • definire jsonMessageConverter, i messageConvertersfagioli nel contesto di riposo, possono essere definiti nel contesto genitore

È possibile eseguire questa operazione a livello di codice senza utilizzare xml?
Arian

@ArianHosseinzadeh Sì. È possibile farlo in modo programmatico. Ci sono molti modi per impostare il contesto primaverile. Nell'esempio, ho mostrato come creare un contesto figlio per la gestione dell'API REST. Impara solo come impostare il contesto all'interno di Java, quindi combina tale conoscenza con la conoscenza in questa risposta. Si chiama programmazione.
kravemir

7

Puoi creare un'annotazione personalizzata per i tuoi controller:

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

Usalo invece del solito @RestController sulle classi del tuo controller e annota i metodi con @RequestMapping.

Appena testato - funziona nella primavera 4.2!


Grazie. L'ho provato. Ma ora devo annotare ogni metodo con @RequestMapping ("/ products"), @RequestMapping ("/ products / {id}"). Invece ho bisogno di annotare Controller con @RequestMapping ("/ products") e metodi con @RequestMapping, @RequestMapping ("/: id"). E il controller dei prodotti dovrebbe essere accessibile da api / products (ad esempio, impostare il prefisso api in un unico posto)
Teimuraz

2
In tal caso, no, non esiste una soluzione pronta all'uso, AFAIK. Puoi provare a implementare il tuo RequestMappingHandlerMapping. Spring Data REST ha un mappatore simile a quello che ti serve - BasePathAwareHandlerMapping.
Ilya Novoseltsev

@moreo, hai trovato una soluzione adeguata? Sarei felice se potessi pubblicarlo come risposta. ho lo stesso requisito qui.
fischermatte

@fischermatte, No, non ho trovato esattamente quello che volevo, ho inserito @RequestMapping ("/ api / products") o @RequestMapping ("/ api / users") prima di ogni classe controller e poi, prima del metodo solo un altro @ RequestMapping ( "/ {id}"). Ma non penso che questo sia un grosso problema, se voglio cambiare "api" in qualcosa, lo cambierò all'inizio di ogni lezione.
Teimuraz

@IlyaNovoseltsev C'è una soluzione, vedi la mia risposta :-)
kravemir

7

Potrei essere un po 'in ritardo, MA ... credo che sia la soluzione migliore. Impostalo nel tuo application.yml (o file di configurazione analogico):

spring:
    data:
        rest:
            basePath: /api

Come posso ricordare, è tutto: tutti i tuoi repository saranno esposti sotto questo URI.


Puoi spiegarlo un po 'o indicare una documentazione pertinente?
Dmitry Serdiuk,


11
la variabile ambientale spring.data.rest.base-path interessa solo spring-data-rest e spring-hateoas. Plain @RestController rimarrà ancora alla radice!
Robert

4
@thorinkor in base a cosa stai dicendo che nella maggior parte dei casi le persone costruiranno repository REST di Spring Data? E l'OP sta chiaramente dicendo che ha controllori di riposo ...
Jean-François Beauchef

1
Penso che funzionerà solo se stai usando SpringDataRest.
Jaumzera

6

Prova a utilizzare 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
Grazie, questo era esattamente quello che stavo cercando! Ciò consente di impostare un elemento del percorso di contesto per tutti i RestController configurati tramite questo WebMvcConfig, simile a quello che fa spring.data.rest.base-path.
Buurman

La tua risposta è perfetta su @HaraldWendel: +1: potresti migliorarla ulteriormente espandendola un po ', come spiegare cosa fa esattamente il tuo codice (come ho provato a fare nel mio commento) e / o magari collegarti a alcuni javadoc o documentazione che descrive questo utilizzo.
Buurman

Questa è l'unica soluzione che ha funzionato per me poiché sto usando le interfacce del controller
Anatoly Yakimchuk

4

Puoi creare una classe base con @RequestMapping("rest")annotazioni ed estendere tutte le altre classi con questa classe base.

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

Ora tutte le classi che estendono questa classe base saranno accessibili in rest/**.


3
Questa non è la risposta corretta, l'utente si riferisce all'annotazione del controller. Se estendi una classe astratta con un'annotazione RequestMapping e anche la nuova classe ha una RequestMapping, quest'ultima sovrascriverà la prima, non concatenerà le due.
Massimo

Sei consapevole che le annotazioni non vengono ereditate in java a meno che non abbia ereditato la meta annotazione? Controlla questo: stackoverflow.com/a/21409651 . E @RequestMapping non sembra averlo: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
Mashrur

3

Per coloro che utilizzano la configurazione YAML (application.yaml).

Nota : funziona solo perSpring Boot 2.x.x

server:
  servlet:
    contextPath: /api

Se stai ancora utilizzando Spring Boot 1.x

server:
  contextPath: /api

1

Con spring-boot 2.x puoi configurare in application.properties:

spring.mvc.servlet.path=/api

1

server.servlet.context-path=/apisarebbe la soluzione immagino. Ho avuto lo stesso problema e questo mi ha risolto. Ho usato server.context-path. Tuttavia, sembrava essere deprecato e ho scoperto che server.servlet.context-pathora risolve il problema. Un'altra soluzione alternativa che ho trovato è stata l'aggiunta di un tag di base alle mie pagine front-end (H5). Spero che questo aiuti qualcuno là fuori.

Saluti


0

Questa soluzione si applica se:

  1. Vuoi aggiungere un prefisso RestControllerma non Controller.
  2. Non stai utilizzando 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);
        }
    }

    }

È simile alla soluzione pubblicata da mh-dev, ma penso che sia un po 'più pulita e dovrebbe essere supportata su qualsiasi versione di Spring Boot 1.4.0+, inclusa la 2.0.0+.


Se sto usando Pageable nel mio RestControler, api / something non mi dà alcun costruttore principale o predefinito trovato per l'interfaccia org.springframework.data.domain.Pageable
K. Ayoub

0

Secondo i documenti REST di Spring Data , se si utilizza application.properties , utilizzare questa proprietà per impostare il percorso di base:

spring.data.rest.basePath=/api

Ma nota che Spring utilizza legature rilassate , quindi questa variazione può essere utilizzata:

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

... o questo se preferisci:

spring.data.rest.base_path=/api

Se usi application.yml , dovresti usare i due punti per i separatori di chiavi:

spring:
  data:
    rest:
      basePath: /api

(Per riferimento, un ticket correlato è stato creato nel marzo 2018 per chiarire i documenti.)


0

ha funzionato server.contextPath = / percorso


0

Puoi creare un'annotazione personalizzata per i tuoi controller:

Usalo invece del solito @RestController sulle classi del tuo controller e annota i metodi con @RequestMapping.

Funziona bene nella primavera 4.2!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.