Is Spring Boot + Spring MVC + Ratpack possible?

We are the Spring download store and rely heavily on Spring MVC for our REST endpoints. We use Boot and the built-in Tomcat to create a self-service JAR. Is it possible to replace Tomcat Ratback while retaining all my Spring MVC code? I'm afraid that Spring MVC is somehow tied to the servlet specification and will not work without a servlet container. I know that dsyer / spring-boot-ratpack works, but after anti-aliasing, the code was unable to decide whether Spring MVC would play using the bridge. Does anyone know of any work that will allow us to save our investment in Spring MVC and have Spring Boot use Ratpack to control HTTP traffic?

+7
spring-boot spring-mvc ratpack
source share
2 answers

The Spring MVC programming model is not very dependent on the Servlet APIs, but is not supported in any other containers (i.e. not Ratpack). There are some asynchronous things there, and Servlet 3.1 improves it even more, so if the Ratpack part that appeals to you, maybe just using this would be a better approach. However, you still will not get reactive and non-blocking IO.

+2
source share

I suspect that the essence of your question may be redone: "Can we put our Spring controllers on top of the non-blocking HTTP level of Ratpack?" and the simplest answer to this question is no, because the MVC programming model doesn’t fit very well in the reactive / NIO model.

However, if your application has implemented some common model-view-controller- (and service) templates, then your controllers should really just do data binding and parsing and delegation to the service level. If so, then most likely the code in your controller is no longer blocked, and you can easily translate it into Ratpack code.

As an example, consider the following @RestController in a Spring Boot application:

 @RestController @RequestMapping("/user") class UserController { @Autowired UserService userService @RequestMapping(method = RequestMethod.POST) Long create(@RequestBody @Valid User user) { User savedUser = userService.save(user) return savedUser.id } } 

The spring aspect of data binding is the calculation process (i.e. not related to I / O), so we can easily translate it into the Ratpack handler:

 import app.SpringConfig import app.User import app.UserService import org.springframework.boot.SpringApplication import org.springframework.context.ApplicationContext import ratpack.jackson.JacksonModule import static ratpack.groovy.Groovy.ratpack import static ratpack.jackson.Jackson.fromJson import static ratpack.jackson.Jackson.json import static ratpack.spring.Spring.spring ratpack { bindings { add(new JacksonModule()) bindInstance(ApplicationContext, SpringApplication.run(SpringConfig)) } handlers { ApplicationContext ctx -> register(spring(ctx)) prefix("user") { handler { UserService userService -> byMethod { post { def user = parse(fromJson(User)) blocking { userService.save(user) } then { User savedUser -> render(json(savedUser)) } } } } } } } 

Where SpringConfig looks like this:

 package app import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration class SpringConfig { @Bean UserService userService() { new UserService() } } 

And here is a functional test to prove it:

 package app import com.fasterxml.jackson.databind.ObjectMapper import ratpack.groovy.test.GroovyRatpackMainApplicationUnderTest import ratpack.test.ApplicationUnderTest import ratpack.test.http.TestHttpClient import spock.lang.Shared import spock.lang.Specification import static groovy.json.JsonOutput.toJson class FuncSpec extends Specification { @Shared ApplicationUnderTest aut = new GroovyRatpackMainApplicationUnderTest() @Shared ObjectMapper mapper = new ObjectMapper() @Delegate TestHttpClient client = aut.httpClient def "should parse and save user"() { given: def user = new User(username: "dan", email: " danielpwoods@gmail.com ") when: requestSpec { spec -> spec.body { b -> b.type("application/json") b.text(toJson(user)) } } post('user') then: def savedUser = mapper.readValue(response.body.text, User) and: savedUser.id } } 

Hope this helps!

+11
source share

All Articles