Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Embedded Jetty: Pick up existing Spring MVC controllers

Context

I work on a web-app (using Play Framework) and I'm trying to migrate to traditional Servlet model with Spring MVC. I'd like to run in an embedded Jetty container alongs an already existing one (netty).

Problem

I'm trying to re-use a created Spring context (that contains all application beans, including newly-added Spring MVC controllers), but the request mappings aren't picked up.

I debugged Spring's Dispatcher Servlet and there were no mappings registered indeed (so it could handle no path).

Attempted solution

Here's the manual Jetty setup code:

@RequiredArgsConstructor
public class EmbeddedJetty {

    private final int port;
    private final AnnotationConfigWebApplicationContext existingContext;

    @SneakyThrows
    public void start() {
        Assert.notNull(existingContext.getBean(UserController.class));

        val server = new Server(port);
        ServletContextHandler handler = new ServletContextHandler();
        ServletHolder servlet = new ServletHolder(new DispatcherServlet(existingContext));
        handler.addServlet(servlet, "/");
        handler.addEventListener(new ContextLoaderListener(existingContext));
        server.setHandler(handler);

        server.start();
        log.info("Server started at port {}", port);
    }

}

And here's the controller being ignored:

@Controller
public class UserController {

    @GetMapping("/users/{userId}")
    public ResponseEntity<?> getUser(@PathVariable("userId") long userId) {
        return ResponseEntity.ok("I work");
    }

}

Question

What do I needed to do to make my embedded jetty setup pick up the existing controller beans and serve the mappings?

like image 583
Xorty Avatar asked Jul 13 '17 15:07

Xorty


1 Answers

I believe you are missing the MVC Java Config that handles request to @RequestMapping inside your Controller.

So basically what you would need to add is a WebMVC config class like:

package my.spring.config;
//necessary imported packages avoided for shortening the example
@EnableWebMvc 
@Configuration
@ComponentScan({ "my.jetty.test" })
public class SpringWebConfig extends WebMvcConfigurerAdapter {

}

Then you would need to indicate to your AnnotationConfigWebApplicationContextwhere the config is located, add to your startmethod this:

webAppContext.setConfigLocation("my.spring.config");

And voila, the below (very simple) Controller serves request on my localhost:

package my.jetty.test;
//necessary imported packages avoided for shortening the example
@Controller
public class HelloController {

    @GetMapping(value = "/")
    @ResponseBody
    public String printWelcome(HttpServletRequest request) {
        return "hello";
    }

    @GetMapping(value = "/hello/{name:.+}")
    @ResponseBody
    public String hello(@PathVariable("name") String name) {
        return "hello " + name;
    }
}

If needed, I can give the full example. Several links that helped me:

  • The official documentation of jetty
  • This example from mkyong
  • The documentation of Spring MVC
  • This example on Github
  • This answer on SO

Edit: The repo with my code working

like image 179
Adonis Avatar answered Sep 30 '22 11:09

Adonis