SpringMVC with Embedded Jetty and Thymeleaf

As mentioned in my previous post on using embedded Jetty with SpringMVC, I was going to look at simplifying the application by using Thymeleaf instead of JSPs as a view technology.

Well, it turns out that it is much more straightforward.

First we can remove the JSPC plugin from our pom.xml. Second we can completely remove the web.xml file.

Bootstrapping Jetty is much simpler now. We do not have to hook into the Jetty startup process with a lifecycle listener, instead we can directly create the dispatcher servlet and add it to a ServletContextHandler like we would any other servlet:

From JettyConfiguration.java:


@Bean
public ServletHolder dispatcherServlet() {
AnnotationConfigWebApplicationContext ctx =
new AnnotationConfigWebApplicationContext();
ctx.setParent(applicationContext);
ctx.register(MvcConfiguration.class);
DispatcherServlet servlet = new DispatcherServlet(ctx);
ServletHolder holder = new ServletHolder("dispatcher-servlet", servlet);
holder.setInitOrder(1);
return holder;
}

@Bean
public ServletContextHandler servletContext() throws IOException {
ServletContextHandler handler = new ServletContextHandler();
handler.setContextPath("/");
handler.setResourceBase(
new ClassPathResource("webapp").getURI().toString());
handler.addServlet(AdminServlet.class, "/metrics/*");
handler.addServlet(dispatcherServlet(), "/");
return handler;
}

@Bean(initMethod = "start", destroyMethod = "stop")
public Server jettyServer() throws IOException {
Server server = new Server();
server.setHandler(servletContext());
server.setConnectors(jettyConnectors());
return server;
}

This is much more straightforward, everything wired up with Spring without any lifecycle callback hooks.

The setup for Spring to render the Thymeleaf views, is a little more complex, but not fussy. What we do is replace:


@Bean
public InternalResourceViewResolver configureInternalResourceViewResolver() {
InternalResourceViewResolver resolver =
new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}

with


@Bean
public ServletContextTemplateResolver thymeleafTemplateResolver() {
ServletContextTemplateResolver resolver =
new ServletContextTemplateResolver();
resolver.setPrefix("/WEB-INF/thymeleaf/");
resolver.setSuffix(".html");
resolver.setTemplateMode("HTML5");
resolver.setCacheable(true);
return resolver;
}

@Bean
public SpringTemplateEngine thymeleafTemplateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(thymeleafTemplateResolver());
return engine;
}

@Bean
public ThymeleafViewResolver thymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(thymeleafTemplateEngine());
return resolver;
}

in MvcConfiguration.java.

Our templates now look a lot more like plain HTML, and will render better when loaded directly in a browser:


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Home</title>
</head>
<body>
<h1>Hello World!</h1>

<p>Server time: <span th:text="${serverTime}"></span></p>

<p>Here are some items:</p>
<ul>
<li th:each="item : ${someItems}" th:text="${item}"></li>
</ul>

<p>Do we have a message from the dummy service:</p>

<div th:if="${dummyService == null}">
<p>No, dummy service is null.</p>
</div>
<div th:if="${dummyService != null}">
<p>Yes: <span th:text="${dummyService.getMessage()}"></span></p>
</div>

<p><a href="resources/static.txt">A static file.</a></p>

<p><a href="metrics">Yammer Metrics</a></p>

</body>
</html>

With the build process being simple (no dependence on maven plugins) we can switch to a much less verbose Gradle build file:


apply plugin:'java'
apply plugin:'application'

version = '0.0.1-SNAPSHOT'

mainClassName = "ca.unx.template.Main"
applicationName = "jetty-springmvc-thymeleaf-template"

repositories {
mavenCentral()
}

dependencies {
compile("org.springframework:spring-webmvc:3.1.3.RELEASE") {
// Commons-logging excluded in favour of SLF4j.
exclude module: 'commons-logging'
}

compile "cglib:cglib:2.2.2"
compile "org.thymeleaf:thymeleaf-spring3:2.0.14"
compile "org.eclipse.jetty:jetty-webapp:8.1.8.v20121106"
compile "com.yammer.metrics:metrics-servlet:2.2.0"

/* Logging. */
def slf4jVersion = "1.7.1"
compile "ch.qos.logback:logback-classic:1.0.9"
compile "org.slf4j:slf4j-api:$slf4jVersion"
compile "org.slf4j:jcl-over-slf4j:$slf4jVersion"
compile "org.codehaus.groovy:groovy:1.8.6"
}

A complete template project can be found here. Note that this links to tag which is the state of the code at the time of this writing.

Advertisements

2 thoughts on “SpringMVC with Embedded Jetty and Thymeleaf

  1. great tutorial thanks for that, really helpful. when calling from the command line, mvn exec:java, is there a way to start it up in debug mode so it can be stepped through in eclipse? haven’t been able to figure it out.

  2. Thanks, I’m glad you found it useful.Sorry, I can’t help you much with Eclipse. I haven’t been using Eclipse much these days, or Spring MVC for that matter.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s