mvc form spring spring-mvc spring-boot

form - spring mvc tags



Spring Boot con dos configuraciones de MVC (4)

Ampliando mi comentario de ayer y la idea de @Ashoka Header propongo registrar 2 MessageConverters (heredados y actuales) para tipos de medios personalizados. Puedes hacer esto así:

@Bean MappingJackson2HttpMessageConverter currentMappingJackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); // set features jsonConverter.setObjectMapper(objectMapper); jsonConverter.setSupportedMediaTypes(Arrays.asList(new MediaType("json", "v2"))); return jsonConverter; } @Bean MappingJackson2HttpMessageConverter legacyMappingJackson2HttpMessageConverter() { MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); ObjectMapper objectMapper = new ObjectMapper(); // set features jsonConverter.setObjectMapper(objectMapper); return jsonConverter; }

Preste atención al tipo de medio personalizado para uno de los convertidores.

Si lo desea, puede usar un interceptor para reescribir los encabezados de versión propuestos por @Ashoka a un tipo de medio personalizado como ese:

public class ApiVersionMediaTypeMappingInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try { if(request.getHeader("X-API-Version") == "2") { request.setAttribute("Accept:","json/v2"); } ..... } }

Puede que esta no sea la respuesta exacta que estabas buscando, pero tal vez te sirva de inspiración. Un interceptor está registrado como tal .

Tengo una aplicación Spring Boot con una API REST, usando Jackson para la configuración de vista JSON. Funciona muy bien y puedo obtener toda la bondad de Spring Boot.

Sin embargo, necesito agregar una API REST adicional que sea similar pero con configuraciones diferentes. Por ejemplo, entre otras cosas, necesita una configuración de asignador de objetos Jackson diferente porque el JSON se verá bastante diferente (por ejemplo, no hay matrices JSON). Ese es solo un ejemplo, pero hay bastantes diferencias. Cada API tiene un contexto diferente (por ejemplo, / api / current y / api / legacy).

Idealmente, me gustaría que dos configuraciones de MVC se asignaran a estos contextos diferentes, y no tuviera que renunciar al cableado automático de las cosas en el arranque.

Hasta ahora todo lo que he podido acercarme es usar dos servlets de despachador cada uno con su propia configuración de MVC, pero eso da como resultado que Boot deje caer un montón de cosas que obtengo de manera automática y, básicamente, anula el motivo por el que usas boot.

No puedo dividir la aplicación en varias aplicaciones.

La respuesta "no puedes hacer esto con Boot y aún así obtener toda su magia" es una respuesta aceptable. Parece que debería ser capaz de manejar esto sin embargo.


En Spring-boot ypu puede usar diferentes perfiles (como dev y test ).

Inicie la aplicación con -Dspring.profiles.active=dev o -Dspring.profiles.active=test y use diferentes archivos de propiedades llamados application-dev.properties o application-test.properties dentro de su directorio de properties . Eso podría hacer el problema.


Hay varias formas de lograr esto. En función de su requerimiento, diría que este es un caso de administración de versiones de REST API. Hay varias formas de versionar la API REST, algunas de las cuales son urls de versión y otras técnicas mencionadas en los enlaces de los comentarios. El enfoque basado en URL es más impulsado a tener múltiples versiones de la dirección:

Por ejemplo para V1 :

/path/v1/resource

y V2 :

/path/v2/resource

Esto resolverá dos métodos diferentes en el bean Spring MVC Controller, al que se delegan las llamadas.

La otra opción para resolver las versiones de la API es usar los encabezados, de esta manera solo hay URL, múltiples métodos basados ​​en la versión. Por ejemplo:

/path/resource

ENCABEZAMIENTO:

X-API-Version: 1.0

ENCABEZAMIENTO:

X-API-Version: 2.0

Esto también se resolverá en dos operaciones separadas en el controlador.

Ahora estas son las estrategias basadas en las múltiples versiones de descanso que pueden manejarse.

Los enfoques anteriores se explican bien en lo siguiente: git example

Nota: Lo anterior es una aplicación de arranque de primavera.

Lo común en estos dos enfoques es que tendrá que haber diferentes POJOS basados ​​en la biblioteca Jackson JSON para ordenar automáticamente las instancias del tipo especificado en JSON.

Es decir, suponiendo que el código usa @RestController [org.springframework.web.bind.annotation.RestController]

Ahora bien, si su requisito es tener diferentes JSON Mapper, es decir, diferentes configuraciones de mapeadores JSON, entonces, independientemente de los contextos de Spring, necesitará una estrategia diferente para la serialización / des-serialización.

En este caso, deberá implementar un De-Serializador personalizado {CustomDeSerializer} que extenderá JsonDeserializer<T> [com.fasterxml.jackson.databind.JsonDeserializer] y en deserialize() implementará su estrategia personalizada.

Utilice la @JsonDeserialize(using = CustomDeSerializer.class) en el POJO de destino.

De esta forma, se pueden gestionar múltiples esquemas JSON con diferentes De-Serializers.

Al combinar Resting Versioning + Custom Serialization Strategy, cada API puede administrarse en su propio contexto sin tener que conectar múltiples configuraciones de Servlet de despachador.


Si puede vivir con un puerto diferente para cada contexto, solo tiene que sobrescribir los beans DispatcherServletAutoConfiguration . Todo el resto de la magia funciona, varias partes, Jackson, etc. Puede configurar Servlet y Jackson / Multipart etc. para cada contexto secundario por separado e inyectar bean del contexto padre.

package test; import static org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME; import static org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.embedded.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration @EnableAutoConfiguration(exclude = { Application.Context1.class, Application.Context2.class }) public class Application extends WebMvcConfigurerAdapter { @Bean public TestBean testBean() { return new TestBean(); } public static void main(String[] args) { final SpringApplicationBuilder builder = new SpringApplicationBuilder().parent(Application.class); builder.child(Context1.class).run(); builder.child(Context2.class).run(); } public static class TestBean { } @Configuration @EnableAutoConfiguration(exclude = {Application.class, Context2.class}) @PropertySource("classpath:context1.properties") public static class Context1 { @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) DispatcherServlet dispatcherServlet() { DispatcherServlet dispatcherServlet = new DispatcherServlet(); // custom config here return dispatcherServlet; } @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME) ServletRegistrationBean dispatcherServletRegistration() { ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet(), "/test1"); registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME); // custom config here return registration; } @Bean Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder(TestBean testBean) { System.out.println(testBean); Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); // custom config here return builder; } } @Configuration @EnableAutoConfiguration(exclude = {Application.class, Context1.class}) @PropertySource("classpath:context2.properties") public static class Context2 { @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) DispatcherServlet dispatcherServlet() { DispatcherServlet dispatcherServlet = new DispatcherServlet(); // custom config here return dispatcherServlet; } @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME) ServletRegistrationBean dispatcherServletRegistration() { ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet(), "/test2"); registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME); // custom config here return registration; } @Bean Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder(TestBean testBean) { System.out.println(testBean); Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); // custom config here return builder; } } }

Los archivos context1/2.properties actualmente solo contienen un server.port=8080/8081 pero puede establecer todas las otras propiedades de primavera para los contextos secundarios allí.