recursive.codes

recursive.codes

recursive.codes


The Personal Blog of Todd Sharp

Spark Java Views Using Thymeleaf - SiteMesh Like Layouts

Posted By: Todd Sharp on 4/6/2017 9:52 GMT
Tagged: Groovy, Java, Spark Java, Thymeleaf

In the last post we looked at how Thymeleaf handles reusable layouts.  A reddit user enlightened me about an open source 'dialect' for Thymeleaf that makes it behave in a similar manner to SiteMesh.  It's documented pretty well, but...

Yeah, documentation can be boring sometimes, so I thought I'd put together a quick post on how that would look in the Spark Java application I've been working with.  It works well, but it suffers from an inability to pass model variables to the layout template.  That's something that SiteMesh can handle (although in a less-than-elegant manner in my opinion) and in my view it is almost deal breaker.  Something as simple as a nav menu that is common across all pages will ultimately require some dynamic data, and if we're going to need to th:insert the fragment on every page, then what are we really gaining by using this style of layout template?  I'll add how I'd think this could be handled at the end of this post, but first let's look at how to implement this dialect in the project.

The first step is to include the dialect, so in build.gradle, under dependencies, add:

compile group: 'nz.net.ultraq.thymeleaf', name: 'thymeleaf-layout-dialect', version: '2.2.1'
Now modify your Bootstrap.groovy in the main() method to add the dialect.  The rest of the Bootstrap class looks the same as our last post (with the exception of a new/modified route that I've created for this feature called /thymeleaf-layout):

Now create the layout itself - similar to how you'd do in SiteMesh:

A few items to note in the layout:

  1. Line 3 - The addition of a layout namespace.  The dialect uses it's own namespace instead of the Thymeleaf th namespace.
  2. When adding content in the <head> element of the 'child' page, by default the 'layout' page <head> content will be merged.  This is configurable.  Any child <title> elements will replace the layout <title> element, but you can tweak that behavior too.
  3. On line 51 we have a <div layout:fragment="content"></div>.  This is where what we define in the child layout will end up.  Very SiteMesh-like.
The child page looks like this:

As mentioned above, the <div layout:fragment="content"> starting on line 10 will be what ends up getting populated in the layout template.  But as I mentioned above, there's no easy way to pass menu content from the child to the layout (that I've found).  Technically, this works in the layout:

But that depends on the 'menu' variable to be in the model on every single page.  I'd normally make sure it was, but something about that approach just feels dirty to me.  I'd much rather pass the variable from the child to the layout in some manner (here is how SiteMesh handles it).  Even that approach feels a little wonky to me, which is why I think I prefer the approach used in my last post, but perhaps I'm missing a feature of this dialect.

Image by mbll from Pixabay



Related Posts

Querying Autonomous Database from an Oracle Function (The Quick, Easy & Completely Secure Way)

Querying Autonomous Database from an Oracle Function (The Quick, Easy & Completely Secure Way)

I've written many blog posts about connecting to an Autonomous DB instance in the past. Best practices evolve as tools, services, and frameworks become...

Sending Email With OCI Email Delivery From Micronaut

Sending Email With OCI Email Delivery From Micronaut

Email delivery is a critical function of most web applications in the world today. I've managed an email server in the past - and trust me - it's not fun...

Brain to the Cloud - Part III - Examining the Relationship Between Brain Activity and Video Game Performance

Brain to the Cloud - Part III - Examining the Relationship Between Brain Activity and Video Game Performance

In my last post, we looked at the technical aspects of my Brain to the Cloud project including much of the code that was used to collect and analyze the...

Note: Comments are currently closed on this blog. Disqus is simply too bloated to justify its use with the low volume of comments on this blog. Please visit my contact page if you have something to say!