Bringing Thymeleaf and Natural Templates to the Spring PetClinic
Note: The Spring PetClinic application received a major update from SpringSource in March 2013, and the thymeleafexamples-petclinic application has been updated consequently, along with this article.
The Spring PetClinic application
PetClinic is one of the example applications created by SpringSource for the Spring Framework. It is designed to display and manage information related to pets and veterinarians in a pet clinic. The original SpringSource version lives in GitHub here, and the thymeleaf-enabled version lives also in GitHub here.
Pet Clinic originally includes a view layer created with JSP, which we will replace using Thymeleaf:
- Modifications will be focused on the view layer: the JSP files will be replaced and the application will be reconfigured. All Java code will be left untouched.
- The original markup will be cleaned, but all the application's interface will have to display exactly the same as the original.
- Thymeleaf template files should display OK when opened statically on a browser (Natural templates).
All the code of the PetClinic+Thymeleaf application can be obtained at the Thymeleaf Project's Documentation page. Note that the original JSP files and JSP tags have not been removed from the source tree but rather moved to the doc/old_viewlayer folder at the source tree, so that you can still access them in order to compare with the new templates.
The version of the PetClinic application used as a base is the state of its master branch at Github as of 17 March 2013.
The original JSP view layer
The original JSP view layer has a number of problems we will try to fix when converting the view layer to Thymeleaf:
- JSPs include tags from JSTL, Spring Tag Libs and other external libraries. None of these are understandable by browsers, so there is no way for them to display the pages statically (no static prototyping possible).
- JSTL tags use the JSP EL (Expression Language), whereas the tags from the JSP Spring taglibs use Spring EL. Two different expression languages are therefore mixed in the same pages.
- The original JSP templates are not well-formed HTML documents. For example,
the "ownersList" page:
- Does not contain a head tag, adding instead one from another JSP using a JSP include (=> not understandable by browsers).
- Header and footer contents have been replaced by JSP include tags (=> not understandable by browsers) so the pages can't be displayed statically including their header and footer. And anyway, even if those contents were in the page, as pages contain JSP and JSTL tags, we wouldn't be able to see a real prototype.
Basic project configuration
Some basic configuration steps will be needed:
- The pom.xml file will be modified in order to add the Thymeleaf dependencies to it and remove the JSP-related ones.
- The web.xml file will be modified in order to remove JSP-related servlets and filters.
Our next configuration step will be to add three required beans at the Spring beans configuration file, mvc-view-config.xml:
- The Thymeleaf template resolver that will be in charge of reading the template files to be processed. For this application we will use a ServletContextTemplateResolver.
- The Thymeleaf template engine instance, of class SpringTemplateEngine.
- The Thymeleaf view resolver, a ThymeleafViewResolver instance implementing Spring's org.springframework.web.servlet.ViewResolver interface. This bean will substitute the original InternalResourceViewResolver bean which enabled JSP support in the original application.
Note that, as a difference from the original application, our templates will live at the /WEB-INF/thymeleaf folder instead of the original /WEB-INF/jsp.
From JSP to Thymeleaf
PetClinic includes more than 10 JSP templates, and we will rewrite all of them using Thymeleaf. However, for the sake of brevity, we will focus on owners/ownerslist.jsp, which we will convert into owners/ownersList.html.
Remember you can see all the templates at the source code, downloadable from the documentation page, and also that you can review the original JSP files at the doc/old_viewlayer folder.
The owners/ownersList page looks like this:
In order to convert this page to Thymeleaf, we will:
- Rename ownersList.jsp to ownersList.html.
- Remove all <%@ taglib %> directives as we do not need any JSP tag libraries
- Replace the jsp:include tags which add head, header and footer to the page with tags containing the thymeleaf attributes th:substituteby or th:include. Those page fragments have been kept in the fragments folder and converted to thymeleaf as well
Note how our ownersList.html contains more code at its head, header and footer sections than the original JSP file. Doing it this way is merely optional, and its only aim is to allow the ownersList.html Thymeleaf-enabled template to display statically as a prototype (something nearly impossible with JSP).
Is this additional code worth it? If you need or want to use design prototypes, indeed! You will see clearly how much a difference this is at the last section of this article. And anyway... remember this prototyping code is optional!
- Change the page body. The original code looks like this:
Which we will replace with:
- In the code above you can see how we used HTML code instead of a collection of JSP tags from an external library. Not only this makes our code much clearer and more readable, but also more standard and understandable by browsers, which will allow us to use this template as a static prototype. Again, we will see the advantages of this in the next section.
And what about the Natural Templates thing?
Before we started this migration, we set a goal that our new Thymeleaf templates would be able to display correctly when open statically in a browser (without starting the application server) thanks to the Natural Templating capabilities of Thymeleaf.
Well, let's have a look at how the original owners/ownersList.jsp template looks like when seen statically:
...and now let's have a look at our new Thymeleaf-powered owners/ownersList.html:
There we are. Data is not valid, because it is a prototype. But it looks good!