My first step with Thymeleaf (migrating JSPX generated by Spring Roo)

(this is the first half of a two-part exercise, the second can be read here)

1         Before starting

1.1       Why all this?

I was never a great fan of Spring. Not a hater either, it just happened it came more often than not into my ways. On the other hand, I got to really appreciate Spring Roo for its scaffolding feature and thus the possibility to jumpstart a demo application in minutes.

I always used Roo together with JSF mostly for my previous experience with JSF and their great component library Primefaces. But also because I came to resent anything related to JSP and the abused temptation to do Java coding in JSP.  Roo when creating a Spring MVC project will use Apache Tiles and… JSPX. I know JSPX is not plain ole’ JSP but… so when I found out about Thymeleaf as view alternative I said hey why not using that.

Roo doesn’t offer unfortunately Thymeleaf scaffolding, neither the gvNIX distribution seems to care about it. This means I postponed and postponed my proof of concept until I got the courage and time to jump into the cold waters.

1.2       Prerequisites and initial reading

I used for this project Spring Tool Suite, Tomcat and of course Java. How to get them working together is not part of this article.

Start with reading „Using Thymeleaf”. Although this introduction will be about Spring, leave other readings for a later time.

http://www.thymeleaf.org/documentation.html

I know it’s a bit long and will take you a few hours, but you don’t have to do the practical coding mentioned there. Read it with a critical view to get an idea of all features Thymeleaf has to offer and to ask yourself questions. For example, I wondered why all the expression utilities? Some are ok, but some are just orthogonal to the idea of a TEMPLATE engine. Template is not business logic, so why offering a function to sum all the values in a table? Coding in the view, is this JSP again??? Anyway, let’s go on.

2         Laying the basics

2.1       Roo project

So, let’s create a Roo project to start with. It’s going to be based on Spring MVC and have the usual front end.

The operation will create the project and open a Roo console which will predictably hang there saying “Please stand by until the Roo shell is completely loaded”. I never ever was able to see that  working properly but it’s not an issue – just close the “thymetest” shell and open it again. All fine for the next steps:

2.2       Persistence

jpa setup --provider HIBERNATE --database MYSQL
repository jpa --interface ~.repository.PersonRepository --entity ~.domain.Person
service --interface ~.service.PersonService --entity ~.domain.Person
web mvc setup
web mvc all --package ~.web

Note: I preferred a local MySql installation because I wanted to monitor what’s happening in the database – if you don’t care about that just use HSQLDB. Just remember to edit (as the Roo console rightfully says) your database.properties accordingly. I preferred a separate database for the project, so make sure you create by hand the “thymetest” database in your MySql Workbench.

database.driverClassName=com.mysql.jdbc.Driver
database.url=jdbc\:mysql\://localhost\:3306/thymetest
database.username=root
database.password=whateverpasswordyoumighthave

Note: you might as well set in persistence.xml the property hibernate.hbm2ddl.auto on “update” if you want to also keep your data for future use.

2.3       What exactly to persist

entity jpa --class ~.domain.Person --activeRecord false --testAutomatically
field string fullName --sizeMax 128 --sizeMin 1
field string email --sizeMax 128 --sizeMin 5 --class ~.domain.Person --regexp ^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})
field string socialId --sizeMax 256 –unique
repository jpa --interface ~.repository.PersonRepository --entity ~.domain.Person
service --interface ~.service.PersonService --entity ~.domain.Person

Notice the regex used to check the email entry. I wanted it in order to see that more complex validation still works. I used the service/repository based approach instead of the active record but it obviously doesn’t matter here.

2.4       The rest: MVC

web mvc setup
web mvc all --package ~.web

Ok so now you have the nice CRUD web application, based on Apache Tiles, Dojo and with a bunch of JSPX files you’ll want to replace. Start it and try it to make sure all is set for the real work.

2.5       Final tinkering

Did it work? If you used MySql, of course not 😉 Have a look at the Tomcat console, it will tell you it failed to create the “person”  table because the max key length is 1000 bytes.

Well, thing is that our String named “socialId” will be 4-byte Unicode varchar, which makes it longer than the 1k limit for indexes (remember, we said “unique”). Just go to the Person.java, give its size max 128, save and restart. Go to http://localhost:8080/thymetest and you’ll see it:

thyme1

3         Enter Thymeleaf

3.1       Configure it first

You certainly noticed on the Thymeleaf documentation page the interesting document “Thymeleaf + Spring 3”. Do you want to read it now? Nothing against it, but it’s overkill right now when you don’t even know what’s Thymeleaf about.

To jumpstart you’ll want to add Thymeleaf to your project’s generated pom.xml Add to the properties area its version:

<thymeleaf-spring3.version>2.0.16</thymeleaf-spring3.version>

Then  add the Maven dependency to the Thymeleaf-Spring3 library. Why this one? Because they say so, so let’s stick to it. Maybe you should take the time now to read the Thymeleaf-Spring integration document on the whys.

<dependency> 	 	
    <groupId>org.thymeleaf</groupId>	
    <artifactId>thymeleaf-spring3</artifactId>
    <version>${thymeleaf-spring3.version}</version>
</dependency>

You can use also Eclipse’s (well, STS) pom editor to add the above via its wizards.

Now there’s only needed to enable the Thymeleaf views – configure the view and template resolver as the many blogs and documents already said, in webmvc-config.xml:

<bean id="templateResolver">	 	
  <property name="prefix" value="/WEB-INF/thymeleaf/" />	 	 
  <property name="suffix" value=".html" />	 	 
  <property name="templateMode" value="HTML5" />	 	 
  <!-- Template cache is true by default. Set to false if you want --> 	 	 
  <!-- templates to be automatically updated when modified.
  <property name="cacheable" value="false" />	 	 
</bean>	 	 
<bean id="templateEngine">	 	 
  <property name="templateResolver" ref="templateResolver" />	 	 
</bean>	 	 
<bean>	 	 
  <property name="templateEngine" ref="templateEngine" />	 	 
</bean>

Of course, take care to disable Tiles as well (you noticed the two beans in webmvc-config.xml, right?). You’re all set! Start your server again and go to http://localhost:8080/thymetest

3.2       Adding the first page

Did it work? Kind of – you got an empty page and this error in the console:

org.thymeleaf.exceptions.TemplateInputException: Error resolving template "index", template 
might not exist or might not be accessible by any of the configured Template Resolvers

Quite understandable – we kicked Tiles out and their JSPX inclusive, but didn’t build anything instead. That was wishful thinking… so let’s get the sleeves rolled up and start building the index page. Did you notice before where the template resolver is looking for your files? It was in the configuration code: in /WEB-INF/thymeleaf/ Let’s create that directory and an empty index.html in it. The .html suffix will be magically removed (see configuration above) and you’ll basically address your templates always by name.

You did read the “Using Thymeleaf” document didn’t you? If not, go back now and do it please. If yes, just place some bogus HTML page like this one and start again your application:

<!DOCTYPE html>	 	 
<html>	 	 
<head>	 	 
<title>Za index</title>	 	 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />	 	
<title>Za index</title>
<link rel="stylesheet" href="../../styles/standard.css" />	 	 
</head>	 	 
<body>
</pre>
<div id="container">
<table>
<tbody>
    <div id="container"> 	 	 
        <table>	 	 
            <tbody>	 	 
                <tr>	 	  
                    <td>	 	 
                        <h2>Welcome dear</h2>	                    </td>	 	 
                </tr>	 	 
            </tbody>	 	 
        </table>	 	 
    </div>	 	 
</td>
</tr>
</tbody>
</body>	 	
</html>

Ok you’ll say, this was static, but you just noticed your Thymeleaf found it and served it to you. So far so good, so adding a few dynamic elements should find you prepared:

<!DOCTYPE html>	 	 
<html xmlns:th="http://www.thymeleaf.org">	 	 
<head>	 	 
<title th:text="#{application_name}">Za index</title>	 	 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />	 	 
<link rel="stylesheet" href="../../styles/standard.css" th:href="@{/styles/standard.css}" />	 	
<title>Za index</title>
</head>	 	 
<body>	 	
<div id="container">
<table>
<tbody>
    <div id="container"> 	 	 
        <table>	 	 
            <tbody>	 	 
                <tr>	 	 
                    <td>	 	 
                        <h2 th:text="#{welcome_titlepane}">Welcome dear</h2>	 	 
                    </td>	 	 
                </tr>	 	 
            </tbody>	 	 
        </table>	 	 
    </div>	 	 
<tr>
<td>
<h2>Welcome dear</h2>
</td>
</tr>
</tbody>
</body>	 	
</html>

See? Basically just by adding the Thymeleaf namespace to the html definition you were able to read two text resources (the # marked ones) and a link (the @ one to the CSS resource). Congratulations, you got it running! And you don’t even have to restart the server between editing, because you told the template resolver in the webmvc-config.xml above that the views shouldn’t be cached (not ideal for production environment but hey we’re far from there).

But what is that message “Welcome to {0}” in the middle of your browser? Isn’t there missing something? Well, it actually is. That resource was parameterized (see your messages.properties) and we didn’t specify any. Go to your index.html and use this line instead:

<h2 th:text="#{welcome_titlepane(#{application_name})}">Welcome dear</h2>

thyme2
Finally, there’s the look of a true Hello World application.

3.3       Using fragments

You will say now “but the Tiles application had a nice logo and stuff!” and you’ll be right. Let’s address this issue.

If I say templates I think about reusing blocks of layout. How is this going to work? Well, very easy. Create a new blocks.html in the already known directory and place in it the following: a header! A neat one, of course.

<!DOCTYPE html>	 	 
<html xmlns:th="http://www.thymeleaf.org">	 	 
<head>	 	 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />	 	 
<link rel="stylesheet" href="../../styles/standard.css" th:href="@{/styles/standard.css}" />	 	 
</head>	 	 
<body>	 	 
    <div th:fragment="header">

        <a href="/thymetest" th:href="@{/}"> <img src="../../images/banner-graphic.png" alt="Home" 	 	        <a href="/thymetest"> <img alt="Home" src="../../images/banner-graphic.png" />
            th:src="@{/images/banner-graphic.png}" th:alt="#{button_home}" />	 	 
        </a>	 	 
    </div>	 	 
</body>	 	 
</html>

The style sheet is there if I’ll need to edit fancier HTML later. The important part is the fragment definition which allows me to refer this block of code in the index.html like this:

<body>
    <div th:include="blocks :: header"></div>
    <div id="container">

Hey, we have the logo back, and clicking it is even taking us to the application home page!
thyme3

(continued here…)

Advertisements

12 thoughts on “My first step with Thymeleaf (migrating JSPX generated by Spring Roo)

  1. Pingback: My second step with Thymeleaf (migrating JSPX generated by Spring Roo) | Trying things

  2. Pingback: Thymeleaf and Roo AND Twitter Bootstrap | Trying things

  3. Well, an interesting endeavor for sure, but hard to follow some details like the section in 3.2 “Adding the first page” after the text “adding a few dynamic elements should find you prepared:” the quoted excerpt is the same as the previous one.

    Also in 3.3 “Using fragments” after the text ” A neat one, of course.” there seem to be something missing and the linked image isn’t available.

    Reply
    • You’re right – either WordPress or the theme provider fumbled something and now all (like in ALL) quotes are fup. Like who wants to quote XML tags and why should we test for these, right? Ok let me see what can be rescued… better now?

      Reply
      • All visible, thank you! How long would it take to make a proper CMS with Spring Framework & Tiles/Thymeleaf & jQuery? Open sourced of course.

  4. Well, that’s a rhetorical question of course. I really find Thymeleaf inspiring, unlike jsp in general and jspx in particular. I don’t find the mvc scaffolding save me much time beyond proof of concept projects (Might be Gvnix could at least work with administrator pages). If I find the time I’d like to contribute a Thymeleaf Roo plugin, but it really have to be a group effort as my knowledge in the subject is shallow. I wonder where the best place to start such a project would be.

    Reply
    • I never used the scaffolding output directly in a real project either, honestly said. I found it however many times invaluable for being able to demonstrate some ideas to the customer, and some concepts to coworkers.

      Reply
    • There are already some java-based CMS with Spring, I’m thinking at Magnolia for instance (which however uses Freemarker for templating). The effort… is probably measured in man-years if you want to have something actually useful 🙂

      Reply
  5. Magnolia is too big to be useful IMHO. I want something simple similar what is available en masse on other platforms, like PHP. To build specific CMS’s actually doesn’t take that long. It’s the general ones that take time.

    Reply
      • A specific CMS is simply a web site focused on supporting in great detail what an organisation, business or otherwise, do and that supplies administration functions, which handles the specific needed content for the web site. I build these things for a living.

        It’s still a lot of work as professional web site development can mean, but not considerably more than adapting an existing CMS solution Also businesses appreciates something specifically built for what they do and what their customers need.

  6. Anyway, to get back to what I was talking about what I’m after is not a “specific CMS”, but rather a very simple, yet useful, open source CMS project based on Spring and other nice technologies with natural templating like what Thymeleaf can provide and make that available on the JVM. I want something that embraces tools like Sass, makes CSS3 central and doesn’t spew out bad HTML code from the 90’s or even the early century. Look at the Ruby world and how they work there and you’ll see what I mean.

    Reply

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