java - ejemplo - ¿Cómo configurar la URL base para descansar en el arranque de primavera?
spring rest json (14)
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 cambio, solo
@RequestMapping(''/products'')
.
Los controladores de Mvc deben ser accesibles mediante example.com/whatever
¿Es posible?
(No uso el resto de datos de primavera, solo mvc de primavera)
Con Spring Boot 1.2+, todo lo que se necesita es una sola propiedad 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
Con spring-boot 2.x puede configurar en application.properties:
spring.mvc.servlet.path=/api
Dado que este es el primer hit de Google para el problema y 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 permita definir una ruta diferente para las clases anotadas con @RestController
En esta publicación de 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);
}
};
}
};
}
}
Encontré una solución limpia, que afecta solo a los controladores de descanso.
@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: el
dispatcherServlet
predeterminado
restApi
para controladores y el despachador
@RestControllers
para
@RestControllers
definidos 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 :
-
use
XmlWebApplicationContext
, puede usar cualquier otro tipo de contexto disponible, es decir.AnnotationConfigWebApplicationContext
,GenericWebApplicationContext
,GroovyWebApplicationContext
, ... -
definir
jsonMessageConverter
, beans beans dejsonMessageConverter
en contexto de reposo, pueden definirse en contexto primario
Esta solución se aplica si:
-
Desea prefijar
RestController
pero noController
. -
No estás 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 solution publicada por mh-dev, pero creo que esto es un poco más limpio y debería ser compatible con cualquier versión de Spring Boot 1.4.0+, incluida 2.0.0+.
No podía creer lo complicada que es la respuesta a esta pregunta aparentemente simple. Aquí hay algunas referencias:
- Boleto Spring JIRA
- Otra pregunta SO
- Sin embargo, otra pregunta SO
- Muy bonito GitRepository que muestra el problema
Hay muchas cosas diferentes a considerar:
-
Al configurar
server.context-path=/api
enapplication.properties
, puede configurar un prefijo para todo (¡su server.context-path no server.contextPath!) -
Los controladores Spring Data anotados con @RepositoryRestController que exponen un repositorio como punto final de descanso utilizarán la variable de entorno
spring.data.rest.base-path
enapplication.properties
. Pero el simple@RestController
no tendrá esto en cuenta. De acuerdo con la documentación del resto de datos de Spring, hay una anotación@BasePathAwareController
que puede usar para eso. Pero sí tengo problemas en conexión con Spring-security cuando intento asegurar dicho controlador. Ya no se encuentra.
Otra solución es un simple truco. No puede anteponer 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/"}";
}
}
Para Boot 2.0.0+, esto funciona para mí: server.servlet.context-path = / api
Para Spring Boot Framework versión
2.0.4.RELEASE+
.
Agregue esta línea a
application.properties
server.servlet.context-path=/api
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 habitual @RestController en sus clases de controlador y anote métodos con @RequestMapping.
Recién probado - ¡funciona en Spring 4.2!
Puede crear una clase base con anotaciones
@RequestMapping("rest")
y extender todas las demás clases con esta clase base.
@RequestMapping("rest")
public abstract class BaseController {}
Ahora todas las clases que extiendan esta clase base estarán accesibles en
rest/**
.
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ógico):
spring:
data:
rest:
basePath: /api
Como puedo recordar, eso es todo: todos sus repositorios estarán expuestos debajo de este URI.
Según los https://docs.spring.io/spring-data/rest/docs/current/reference/html/#getting-started.changing-base-uri 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 uses un enlace relajado , por lo que esta variación se puede usar:
spring.data.rest.base-path=/api
... o este si 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 jira.spring.io/browse/DATAREST-1211 relacionado en marzo de 2018 para aclarar los documentos).
Un poco tarde, pero la misma pregunta me trajo aquí antes de llegar a la respuesta, así que la publico aquí. Cree (si aún no lo tiene) una aplicación.propiedades y agregue
server.contextPath=/api
Entonces, en el ejemplo anterior, si tiene un RestController con
@RequestMapping("/test")
accederá como
localhost:8080/api/test/{your_rest_method}
fuente de preguntas: ¿cómo elijo la url para mi aplicación web de arranque de primavera?
servidor trabajado.contextPath = / ruta