The Personal Blog of Todd Sharp

Spark Java Views Using Thymeleaf - Layouts

Posted By: Todd Sharp on 4/5/2017 9:30 UTC
Tagged: Groovy, Java, Spark Java, Thymeleaf

In the last post we looked at plugging in Thymeleaf into a Spark Java application for view rendering.  The concept was pretty simple: using the Thymeleaf engine, render a view with a map of variables to use as the model.  But in reality, our applications need a bit more complexity.  They need reusable layouts.  In this post we'll take a look at how to handle that with Thymeleaf.  

Reusable layouts include things like headers, footers, scripts and other things like nav menus that are common across the application.  Thymeleaf accommodates these by using what they call "fragments" - reusable blocks of code defined by the th:fragment attribute that can be called from your templates using the th:replace, th:insert or th:include attributes.  You can read all about it in their docs, but let's take a look at a practical example below.

To illustrate, let's create three separate fragments, one called head.html, one called nav.html and the final one called foot.html.  I've saved these in /src/main/groovy/resources/templates/fragments.  To make it more realistic, I've dropped in Bootstrap since that's what I'd usually do.  Here is the simple code for each:

Now back in our Bootstrap class, in the main() method, I've created a Groovy closure to grab any 'common' model bits:

Then I modified the route for /thymeleaf to include the commonModel in the model I'm using to render that view:

And now it's just a matter of using the th:replace attribute in my view wherever I'd like the fragments rendered:

Note that since my fragments were not in the /templates directory, but a subdirectory called 'fragments', I had to pass the path from /templates in the th:replace attribute.  Also notice that you can pass model variables to your fragment as I did on line 10.  This is crucial for any layout system as layout bits are rarely purely static.  

Compared to Sitemesh (which is what I'm used to in Grails) I think I'm a fan of the way Thymeleaf handles this.  Something about Sitemesh always felt a little "backwards" (the layout includes the view) so I'm happy to see Thymeleaf approach it in a more "forward" manner (the view includes the layout bits).