Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot with Two MVC Configurations

Tags:

I have a Spring Boot app with a REST API, using Jackson for the JSON view configuration. It works great and I can get all the Spring Boot goodness.

However, I need to add an additional REST API that is similar but with different settings. For example, among other things, it needs a different Jackson object mapper configuration because the JSON will look quite a bit different (e.g. no JSON arrays). That is just one example but there are quite a few differences. Each API has a different context (e.g. /api/current and /api/legacy).

Ideally I'd like two MVC configs mapped to these different contexts, and not have to give up any of the automatic wiring of things in boot.

So far all I've been able to get close on is using two dispatcher servlets each with its own MVC config, but that results in Boot dropping a whole bunch of things I get automatically and basically defeats the reason for using boot.

I cannot break the app up into multiple apps.

The answer "you cannot do this with Boot and still get all its magic" is an acceptable answer. Seems like it should be able to handle this though.

like image 254
SingleShot Avatar asked Jan 11 '16 18:01

SingleShot


People also ask

What is @configuration in spring boot?

Spring @Configuration annotation is part of the spring core framework. Spring Configuration annotation indicates that the class has @Bean definition methods. So Spring container can process the class and generate Spring Beans to be used in the application.

What is WebMvcConfigurer spring boot?

public interface WebMvcConfigurer. Defines callback methods to customize the Java-based configuration for Spring MVC enabled via @EnableWebMvc . @EnableWebMvc -annotated configuration classes may implement this interface to be called back and given a chance to customize the default configuration.

How do I enable Webmvc in spring boot?

To enable Spring MVC support through a Java configuration class, we just add the @EnableWebMvc annotation: @EnableWebMvc @Configuration public class WebConfig { /// ... }

Why use Spring Boot for MVC?

Out of the box, Spring Boot provides default configurations for Spring MVC. And when you bring a template engine into the project, you will also get all the view resolvers needed in order to move from standard JSP programming to modern template engines.

How to create multi-module project with Spring Boot?

Multi-Module Project With Spring Boot 1 Overview. In this quick tutorial, we'll show how to create a multi-module project with Spring Boot. ... 2 Setup. We'll create two directories inside our project that will divide the application module from the library jar module. 3 Library Jar. ... 4 Application Project. ... 5 Conclusion. ...

How do I configure multiple databases in Spring Boot?

Multiple Database Configurations in Spring Boot Following is the application.properties file that contains configurations for multiple databases. You can notice that properties starting from spring.user.datasource has user database configuration and properties starting from spring.booking.datasource has booking datasource configurations.

How do I run a JSP file in Spring Boot?

2. Using the configuration file Select the Project –>Run As –> Run Configuration –>Maven –> New. In the Main tab, key in the Goals as “spring-boot:run” and click on Run. Don’t forget to add “tomcat-embed-jasper” jar as dependency, this enables the Spring Boot application to render JSP files.


2 Answers

There's several ways to achieve this. Based on your requirement , Id say this is a case of managing REST API versions. There's several ways to version the REST API, some the popular ones being version urls and other techniques mentioned in the links of the comments. The URL Based approach is more driven towards having multiple versions of the address:

For example For V1 :

/path/v1/resource 

and V2 :

/path/v2/resource 

These will resolve to 2 different methods in the Spring MVC Controller bean, to which the calls get delegated.

The other option to resolve the versions of the API is to use the headers, this way there is only URL, multiple methods based on the version. For example:

/path/resource 

HEADER:

X-API-Version: 1.0 

HEADER:

X-API-Version: 2.0 

This will also resolve in two separate operations on the controller.

Now these are the strategies based on which multiple rest versions can be handled.

The above approaches are explained well in the following: git example

Note: The above is a spring boot application.

The commonality in both these approaches is that there will need to be different POJOS based on which Jackson JSON library to automatically marshal instances of the specified type into JSON.

I.e. Assuming that the code uses the @RestController [org.springframework.web.bind.annotation.RestController]

Now if your requirement is to have different JSON Mapper i.e. different JSON mapper configurations, then irrespective of the Spring contexts you'll need a different strategy for the serialization/De-Serialization.

In this case, you will need to implement a Custom De-Serializer {CustomDeSerializer} that will extend JsonDeserializer<T> [com.fasterxml.jackson.databind.JsonDeserializer] and in the deserialize() implement your custom startegy.

Use the @JsonDeserialize(using = CustomDeSerializer.class) annotation on the target POJO.

This way multiple JSON schemes can be managed with different De-Serializers.

By Combining Rest Versioning + Custom Serialization Strategy , each API can be managed in it's own context without having to wire multiple dispatcher Servlet configurations.

like image 95
Ashoka Avatar answered Jan 01 '23 21:01

Ashoka


Expanding on my comment of yesterday and @Ashoka Header idea i would propose to register 2 MessageConverters (legacy and current) for custom media types. You can do this like that:

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

Pay attention to the custom media-type for one of the converters.

If you like , you can use an Interceptor to rewrite the Version-Headers proposed by @Ashoka to a custom Media-Type like so:

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");             }        .....     } } 

This might not be the exact answer you were looking for, but maybe it can provide some inspiration. An interceptor is registered like so.

like image 33
Hendrik Jander Avatar answered Jan 01 '23 22:01

Hendrik Jander