¿Cómo configurar la URL base para descansar en Spring Boot?

118

Estoy tratando de mezclar mvc y descansar en un solo proyecto de arranque de primavera.

Quiero establecer la ruta base para todos los controladores de descanso (por ejemplo, example.com/api) en un solo lugar (no quiero anotar cada controlador con @RequestMapping('api/products'), en su lugar, solo @RequestMapping('/products').

Se debe poder acceder a los controladores MVC mediante example.com/whatever

¿Es posible?

(No uso el descanso de datos de primavera, solo mvc de primavera)

Teimuraz
fuente
server.servlet.contextPath = / api
Daniel T. Sobrosa
Spring boot versión 2.1.4.RELEASE, spring.mvc.servlet.path = / api y server.servlet.context-path = / api, ambos funcionan
Prayag Sharma
server.servlet.context-path = / api solution es para APLICACIÓN, no solo para REST. También es válido para servicios SOAP. Si desea especificar su ruta de servicios SOAP y REST, debe usar @RequestMapping ('api / ...') ... medium.com/@bm.celalkartal/…
bmck

Respuestas:

89

Con Spring Boot 1.2+ (<2.0), todo lo que se necesita es una propiedad única en application.properties:

spring.data.rest.basePath=/api

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

Para 2.x, utilice

server.servlet.context-path=/api
Suroj
fuente
4
Esta es la respuesta exacta que dio Thorinkor.
Jean-François Beauchef
8
Gracias, pero esto no me funciona en Spring Boot versión v1.5.7.RELEASE. La otra respuesta server.contextPath = / api funcionó
Jay
10
@Suroj Esa solución funciona solo con controladores anotados RepositoryRestController, no con RestController ...
Nano
jira.spring.io/browse/DATAREST-1211 Este Ticket de Jira menciona que es "spring.data.rest.base-path for Spring Boot 2.0.0". Lamentablemente, ambos no funcionan para mí.
Carsten Hagemann
6
para SB 2+ es server.servlet.context-path = / url
vicky
96

Un poco tarde, pero la misma pregunta me trajo aquí antes de llegar a la respuesta, así que la publico aquí. Crea (si aún no lo tienes) un application.properties y agrega

server.contextPath=/api

Entonces, en el ejemplo anterior, si tiene un RestController @RequestMapping("/test"), accederá a él comolocalhost:8080/api/test/{your_rest_method}

fuente de la pregunta: ¿cómo elijo la URL para mi aplicación web de arranque de primavera?

OriolBG
fuente
19
¿Cómo se hace cumplir esto para que solo funcione con RestControllers y acceda a los controladores normales sin el "/ api"?
Siya Sosibo
@Stoan encontré una solución, verifique mi respuesta :-)
Kravemir
¡No hagas esto! Vea la respuesta de Thorinkor.
Stefan
La respuesta de Thorinkor es específicamente para Spring Data REST.
8
server.contextPath ahora está en desuso, use server.servlet.context-path en su lugar
DS.
46

Para la versión de marco de arranque de primavera 2.0.4.RELEASE+. Agregar esta línea aapplication.properties

server.servlet.context-path=/api
shellhub
fuente
1
Esto también afecta a la carpeta pública :-(
Michel
5
esta es la respuesta correcta para Spring boot 2+. spring.data.rest.basePathno funciona para Spring Boot 2
jackycflau
27

Dado que este es el primer resultado de Google para el problema, supongo que más personas buscarán esto. Hay una nueva opción desde Spring Boot '1.4.0'. Ahora es posible definir un RequestMappingHandlerMapping personalizado que permite definir una ruta diferente para las clases anotadas con @RestController

En esta publicación del blog se puede encontrar una versión diferente con anotaciones personalizadas que combina @RestController con @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);
                    }
                };
            }
        };
    }
}
mh-dev
fuente
2
En Spring Boot 2.0.0+, trabaje directamente desde la interfaz WebMvcRegistrations. WebMvcRegistrationsAdapter se eliminó en favor de agregar métodos predeterminados a la interfaz.
La daga de Gilbert Arenas
27

No podía creer lo complicada que es la respuesta a esta pregunta aparentemente simple. A continuación se muestran algunas referencias:

Hay muchas cosas diferentes a considerar:

  1. Al establecer server.context-path=/apien el application.propertiesque puede configurar un prefijo para todo . (Su-server.context camino no server.contextPath!)
  2. Los controladores de Spring Data anotados con @RepositoryRestController que exponen un repositorio como punto final de descanso usarán la variable de entorno spring.data.rest.base-pathen application.properties. Pero plain @RestControllerno tendrá esto en cuenta. De acuerdo con la documentación del resto de datos de primavera, hay una anotación @BasePathAwareControllerque puede usar para eso. Pero tengo problemas en relación con Spring-security cuando trato de asegurar dicho controlador. Ya no se encuentra.

Otra solución es un truco simple. No puede prefijar una cadena estática en una anotación, pero puede usar expresiones como esta:

@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
fuente
¿Cómo lo incluirías en Annotation?
Teimuraz
2
meh, entonces siempre debes recordar agregar este prefijo cada vez que crees un nuevo controlador
The Gilbert Arenas Dagger
13

Para Boot 2.0.0+ esto me funciona: server.servlet.context-path = / api

Juan Carlos Vergara Santos
fuente
4
Eso puso todo bajo / api, no solo los mapeadores de @RestController. Pero gracias de todos modos. Tu información sigue siendo útil.
eigil
9

Encontré una solución limpia, que afecta solo a los controladores de reposo.

@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 registrará dos servlets de despachador - predeterminado dispatcherServletpara controladores y restApidespachador para @RestControllersdefinido en 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 [/]

El ejemplo 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>

Pero no estás limitado a :

  • utilizar XmlWebApplicationContext, puede utilizar cualquier otro tipo de contexto disponible, es decir. AnnotationConfigWebApplicationContext, GenericWebApplicationContext, GroovyWebApplicationContext, ...
  • definir jsonMessageConverter, messageConvertersfrijoles en contexto de reposo, se pueden definir en contexto padre
Kravemir
fuente
¿Es posible hacer esto programáticamente sin usar el xml?
Arian
@ArianHosseinzadeh Sí. Es posible hacerlo mediante programación. Hay muchas formas de configurar el contexto de primavera. En el ejemplo, he mostrado cómo crear un contexto secundario para el manejo de la API REST. Simplemente aprenda a configurar el contexto dentro de Java y luego combine ese conocimiento con el conocimiento en esta respuesta. Eso se llama programación.
Kravemir
7

Puede crear una anotación personalizada para sus controladores:

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

Úselo en lugar del @RestController habitual en sus clases de controlador y anote métodos con @RequestMapping.

Recién probado, ¡funciona en Spring 4.2!

Ilya Novoseltsev
fuente
Gracias. He probado esto. Pero ahora tengo que anotar cada método con @RequestMapping ("/ products"), @RequestMapping ("/ products / {id}"). En su lugar, necesito anotar el controlador con @RequestMapping ("/ productos") y los métodos con @RequestMapping, @RequestMapping ("/: id"). Y el controlador de productos debe ser accesible en api / products (por ejemplo, establezca el prefijo api en un solo lugar)
Teimuraz
2
En ese caso, no, no hay una solución lista para usar, AFAIK. Puede intentar implementar el suyo propio RequestMappingHandlerMapping. Primavera de datos REST tiene un mapeador similar a lo que necesita - BasePathAwareHandlerMapping.
Ilya Novoseltsev
@moreo, ¿encontraste una solución adecuada? Estaría feliz si pudiera publicarlo como respuesta. tengo el mismo requisito aquí.
fischermatte
@fischermatte, No, no encontré exactamente lo que quería, coloco @RequestMapping ("/ api / products") o @RequestMapping ("/ api / users") antes de cada clase de controlador y luego, antes del método, solo otro @ RequestMapping ("/ {id}"). Pero no creo que esto sea un gran problema, si quiero cambiar "api" a algo, simplemente lo cambiaré al comienzo de cada clase.
Teimuraz
@IlyaNovoseltsev Hay una solución, vea mi respuesta :-)
Kravemir
7

Puede que llegue un poco tarde, PERO ... creo que es la mejor solución. Configúrelo en su application.yml (o archivo de configuración analógica):

spring:
    data:
        rest:
            basePath: /api

Como puedo recordar, eso es todo: todos sus repositorios estarán expuestos debajo de este URI.

Thorinkor
fuente
¿Puede explicar esto un poco o señalar una documentación relevante?
Dmitry Serdiuk
1
Los documentos pertinentes se encuentran en docs.spring.io/spring-data/rest/docs/current/reference/html/… .
bruce szalwinski
11
la variable environemnt spring.data.rest.base-path solo afecta a spring-data-rest y spring-hateoas. ¡El @RestController simple seguirá sentado en la raíz!
Robert
4
@thorinkor basado en lo que está diciendo que en la mayoría de los casos la gente construirá repositorios REST de Spring Data? Y el OP está diciendo claramente que tiene controladores de descanso ...
Jean-François Beauchef
1
Creo que solo funcionará si está utilizando SpringDataRest.
Jaumzera
6

Intente utilizar 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
fuente
1
¡Gracias, esto era exactamente lo que estaba buscando! Esto le permite establecer un elemento de ruta de contexto para todos los RestControllers configurados a través de este WebMvcConfig, similar a lo que hace spring.data.rest.base-path.
Buurman
Su respuesta es acertada en @HaraldWendel: +1: podría mejorarlo un poco más expandiéndolo un poco, como explicar qué hace exactamente su código (como he intentado hacer en mi comentario) y / o tal vez vincularlo algún javadoc o documentación que describa este uso.
Buurman
Esta es la única solución que funcionó para mí ya que estoy usando interfaces de controlador
Anatoly Yakimchuk
4

Puede crear una clase base con @RequestMapping("rest")anotaciones y ampliar todas las demás clases con esta clase base.

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

Ahora se podrá acceder a todas las clases que amplíen esta clase base en rest/**.

Saket Mehta
fuente
3
Esta no es la respuesta correcta, el usuario se refiere a la anotación del controlador. Si extiende una clase abstracta con una anotación RequestMapping, y la nueva clase también tiene un RequestMapping, esta última anulará la primera, no concatenará las dos.
Massimo
¿Sabe que las anotaciones no se heredan en java a menos que haya heredado la meta anotación? Compruebe esto: stackoverflow.com/a/21409651 . Y @RequestMapping no parece tener eso: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
Mashrur
3

Para aquellos que usan la configuración YAML (application.yaml).

Nota : esto solo funciona paraSpring Boot 2.x.x

server:
  servlet:
    contextPath: /api

Si todavía está usando Spring Boot 1.x

server:
  contextPath: /api
Prasanth Rajendran
fuente
1

Con spring-boot 2.x puede configurar en application.properties:

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

server.servlet.context-path=/apisería la solución, supongo. Tuve el mismo problema y esto me resolvió. Usé server.context-path. Sin embargo, eso parecía estar desaprobado y descubrí que server.servlet.context-pathahora resuelve el problema. Otra solución que encontré fue agregar una etiqueta base a mis páginas frontales (H5). Espero que esto ayude a alguien.

Salud

Rahul Talreja
fuente
0

Esta solución se aplica si:

  1. Quiere prefijar RestControllerpero no Controller.
  2. No está utilizando 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);
        }
    }

    }

Esto es similar a la solución publicada por mh-dev, pero creo que es un poco más limpia y debería ser compatible con cualquier versión de Spring Boot 1.4.0+, incluida la 2.0.0+.

La daga de Gilbert Arenas
fuente
Si estoy usando Pageable en mi RestControler, api / something me da No se encontró un constructor primario o predeterminado para la interfaz org.springframework.data.domain.Pageable
K. Ayoub
0

Según los documentos REST de Spring Data , si usa application.properties , use esta propiedad para establecer su ruta base:

spring.data.rest.basePath=/api

Pero tenga en cuenta que Spring usa un enlace relajado , por lo que esta variación se puede usar:

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

... o este si lo prefieres:

spring.data.rest.base_path=/api

Si usa application.yml , usaría dos puntos para los separadores de clave:

spring:
  data:
    rest:
      basePath: /api

(Como referencia, se creó un ticket relacionado en marzo de 2018 para aclarar los documentos).

J Marmota
fuente
0

funcionó server.contextPath = / ruta

Pravin
fuente
0

Puede crear una anotación personalizada para sus controladores:

Úselo en lugar del @RestController habitual en sus clases de controlador y anote métodos con @RequestMapping.

¡Funciona bien en Spring 4.2!

Prerit Neema
fuente