{"id":841,"date":"2012-04-14T16:07:20","date_gmt":"2012-04-14T14:07:20","guid":{"rendered":"http:\/\/doanduyhai.wordpress.com\/?p=841"},"modified":"2012-04-14T16:07:20","modified_gmt":"2012-04-14T14:07:20","slug":"spring-mvc-part-iii-thymeleaf-integration","status":"publish","type":"post","link":"https:\/\/www.doanduyhai.com\/blog\/?p=841","title":{"rendered":"Spring MVC part III: ThymeLeaf integration"},"content":{"rendered":"<p>Today we are going to look into <a href=\"http:\/\/www.thymeleaf.org\/\" title=\"http:\/\/www.thymeleaf.org\/\" target=\"_blank\">Thymeleaf<\/a>, a very innovative and full <strong>HTML5-oriented<\/strong> templating engine. <\/p>\n<p><strong>Thymeleaf<\/strong>, by definition, can be used as a standalone engine but when associated with Spring MVC, it gives the best of its essence.<\/p>\n<p>Once you start using <strong>Thymeleaf<\/strong>, it&#8217;s very hard to go back to the good old JSP. JSP is good, JSP served us well during a decade but now we&#8217;re in 2012 and HTML 5 is the future so it&#8217;s time to look ahead.<br \/>\n<!--more--><\/p>\n<blockquote><p>Please note that all the examples in this post can be found in a demo application on GitHub <a href=\"https:\/\/github.com\/doanduyhai\/ThymeLeafDemo\" title=\"ThymeLeaf Demo\" target=\"_blank\">https:\/\/github.com\/doanduyhai\/ThymeLeafDemo<\/a><\/p><\/blockquote>\n<h1>I Introduction<\/h1>\n<p> Unlike many Java templating engines of its kind, Thymeleaf is a full HTML engine, meaning that the template file itself is a HTML file that can be rendered by any Web browser. <\/p>\n<p>How can it be possible ? Well, Thymeleaf is an <strong>attribute-based<\/strong> template engine, in the sense that all the language syntax relies heavily on HTML tag attributes. For example (see <strong>example1<\/strong> in the tutorial code):<\/p>\n<pre class=\"brush: xml; highlight: [3,15,16,22,23]; title: ; notranslate\" title=\"\">\n&amp;lt;html lang=&amp;quot;en&amp;quot;\n\txmlns=&amp;quot;http:\/\/www.w3.org\/1999\/xhtml&amp;quot; \n\txmlns:th=&amp;quot;http:\/\/www.thymeleaf.org&amp;quot;&amp;gt;\n\t...\n\t...\n&amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;\n\t&amp;lt;br\/&amp;gt;\n\t&amp;lt;br\/&amp;gt;\n\t&amp;lt;br\/&amp;gt;\n\t&amp;lt;div class=&amp;quot;span4 offset4 row-fluid&amp;quot;&amp;gt;\n\t\t&amp;lt;div id=&amp;quot;userMain&amp;quot; class=&amp;quot;span1 table-bordered&amp;quot;&amp;gt;\n\t\t\t&amp;lt;a href=&amp;quot;#&amp;quot;&amp;gt;\n\t\t\t\t&amp;lt;img id=&amp;quot;picture&amp;quot; src=&amp;quot;http:\/\/www.gravatar.com\/avatar\/&amp;quot;\n\t\t\t\t\tdata-user=&amp;quot;duyhai&amp;quot;\n\t\t\t\t\tth:src=&amp;quot;${'http:\/\/www.gravatar.com\/avatar\/'+currentUser.gravatar+'?s=64'}&amp;quot;\n\t\t\t\t\tth:attr=&amp;quot;data-user=${currentUser.login}&amp;quot;&amp;gt;\n\t\t\t\t&amp;lt;\/img&amp;gt;\n\t\t\t&amp;lt;\/a&amp;gt;\n\t\t&amp;lt;\/div&amp;gt;\n\t\t&amp;lt;div class=&amp;quot;span3 table-bordered&amp;quot;&amp;gt;\n\t\t\t&amp;lt;h2&amp;gt;\n\t\t\t\t&amp;lt;span id=&amp;quot;firstName&amp;quot; th:text=&amp;quot;${currentUser.firstName}&amp;quot;&amp;gt;DuyHai&amp;lt;\/span&amp;gt; \n\t\t\t\t&amp;lt;span id=&amp;quot;lastName&amp;quot; th:text=&amp;quot;${currentUser.lastName}&amp;quot;&amp;gt;DOAN&amp;lt;\/span&amp;gt;\n\t\t\t&amp;lt;\/h2&amp;gt;\n\t\t&amp;lt;\/div&amp;gt;\n\t&amp;lt;\/div&amp;gt;\n&amp;lt;\/div&amp;gt;\n&amp;lt;\/html&amp;gt;\n<\/pre>\n<p> As we can see at lines <strong>15,16,22 &amp; 23<\/strong>, the template file is a mere HTML file with some special attribute prefixed by the Thymeleaf namespace <strong>th<\/strong>. A web browser will simply ignore these additional attributes whereas the template engine will process them.<\/p>\n<p>As fas as I know, the only other attribute-based template engine out there is <a href=\"http:\/\/en.wikipedia.org\/wiki\/Template_Attribute_Language\" title=\"http:\/\/en.wikipedia.org\/wiki\/Template_Attribute_Language\" target=\"_blank\">TAL<\/a> (Template Attribute Language) using Python language.<\/p>\n<p> The fact that the template itself can be displayed in a web browser is an important feature. Indeed while developing an Web page, people first start designing the static part of the GUI (css, color, layout) before focusing on the dynamic part (data injection, conditional rendering). With JSP you start creating an empty web page template before injecting all the <strong><\/strong> <em>tag soup<\/em> with the risk of altering the initial static design. With Thymeleaf there is no such headache, we do not need to add any new tag, just new attributes.<\/p>\n<p> Below is an example of a <strong>static page design<\/strong> (see <strong>example2<\/strong> in the tutorial code):<\/p>\n<p> <a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-poc.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-poc.png\" alt=\"thymeleaf-static-design\" title=\"thymeleaf-static-design\" width=\"630\" height=\"499\" class=\"aligncenter size-full wp-image-858\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-poc.png 782w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-poc-300x238.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p>As you can see, <strong>error<\/strong> and <strong>info<\/strong> message panels are all rendered at the same time and we also have some <strong>mocked<\/strong> search results.<\/p>\n<p>At runtime, we get something similar to:<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-runtime.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-runtime.png\" alt=\"thymeleaf-runtime-result\" title=\"thymeleaf-runtime-result\" width=\"630\" height=\"338\" class=\"aligncenter size-full wp-image-860\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-runtime.png 788w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-runtime-300x161.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p> All <strong>mocked<\/strong> lines have been removed, only true search results are displayed (we&#8217;ll see later in this post how mocks are removed).<br \/>\n&nbsp;<\/p>\n<h2>II How does it work<\/h2>\n<blockquote><p>All the examples in this chapter can be found in the demo application on GitHub <a href=\"https:\/\/github.com\/doanduyhai\/ThymeLeafDemo\" title=\"ThymeLeaf Demo\" target=\"_blank\">https:\/\/github.com\/doanduyhai\/ThymeLeafDemo<\/a>, as <strong>example1<\/strong>.<\/p><\/blockquote>\n<p> It&#8217;s time to see how Thymeleaf work under the hood. If we go back to the <strong>example 1<\/strong><\/p>\n<p> Below is the static rendering:<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple1-static.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple1-static.png\" alt=\"thymeleaf-exemple1-static\" title=\"thymeleaf-exemple1-static\" width=\"311\" height=\"74\" class=\"aligncenter size-full wp-image-871\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple1-static.png 311w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple1-static-300x71.png 300w\" sizes=\"(max-width: 311px) 100vw, 311px\" \/><\/a><\/p>\n<p>Now let&#8217;s focus in the template code:<\/p>\n<pre class=\"brush: xml; highlight: [4,5]; title: ; notranslate\" title=\"\">\n&amp;lt;img id=&amp;quot;picture&amp;quot; \n\tsrc=&amp;quot;http:\/\/www.gravatar.com\/avatar\/&amp;quot;\n\tdata-user=&amp;quot;duyhai&amp;quot;\n\tth:src=&amp;quot;${'http:\/\/www.gravatar.com\/avatar\/'+currentUser.gravatar+'?s=64'}&amp;quot;\n\tth:attr=&amp;quot;data-user=${currentUser.login}&amp;quot;&amp;gt;\n&amp;lt;\/img&amp;gt;\n<\/pre>\n<p> We can see there are 2 Thymeleaf attributes: <strong>th:src<\/strong> &amp; <strong>th:attr<\/strong>. What happens at runtime is that Thymeleaf will parse your HTML document, pick any <strong>th<\/strong> attributes and perform substitution. Above, the <em>src=&#8221;http:\/\/www.gravatar.com\/avatar\/&#8221;<\/em> attribute will be replaced by an URL evaluated against the variable <strong>currentUser.gravatar<\/strong> (we&#8217;ll see soon where the variable comes from).<\/p>\n<p> Similarly the <em>&lt;span id=&#8221;firstName&#8221; th:text=&#8221;${currentUser.firstName}&#8221;&gt;DuyHai&lt;\/span&gt;<\/em><br \/>\nwill be rendered as <em>&lt;span id=&#8221;firstName&#8221; &gt;REAL_FIRSTNAME&lt;\/span&gt;<\/em> at runtime, the existing <em>DuyHai<\/em> value is there only for the <strong>static preview<\/strong> of the template.<\/p>\n<p> At runtime, we&#8217;ll get something similar to:<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple1-dynamic.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple1-dynamic.png\" alt=\"thymeleaf-exemple1-dynamic\" title=\"thymeleaf-exemple1-dynamic\" width=\"308\" height=\"70\" class=\"aligncenter size-full wp-image-873\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple1-dynamic.png 308w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple1-dynamic-300x68.png 300w\" sizes=\"(max-width: 308px) 100vw, 308px\" \/><\/a><\/p>\n<p> The general rule is that all static content &amp; attributes will be replaced by dynamic one at runtime by the engine.<\/p>\n<p> At that time, you attentive reader should say: &#8220;<em>hey Dude, it means there should be as many Thymeleaf attributes as there are HTML 5 tag attributes!<\/em>&#8221; and you&#8217;re almost right, almost, because Thymeleaf also exposes additional attributes for flow control.<\/p>\n<p> Below is a list (not comprehensive) of some existing attributes:<\/p>\n<ul>\n<li><strong>th:form<\/strong><\/li>\n<li><strong>th:alt<\/strong><\/li>\n<li><strong>th:action<\/strong><\/li>\n<li><strong>th:href<\/strong><\/li>\n<li><strong>th:src<\/strong><\/li>\n<li><strong>th:title<\/strong><\/li>\n<li><strong>th:value<\/strong><\/li>\n<li><strong>&#8230;<\/strong><\/li>\n<\/ul>\n<p> Please report to the <a href=\"http:\/\/www.thymeleaf.org\/doc\/Tutorial%20-%20Using%20Thymeleaf%2020120401.pdf\" title=\"Official Thymeleaf documentation\" target=\"_blank\">official documentation<\/a> for a  full list of availables attributes.<\/p>\n<p> Last but not least, Thymeleaf can use several <strong>dialects<\/strong>. <em>A dialect is a set of rules and expressions used to parse and process a template file<\/em>. Thymeleaf is shipped by default with the Standard dialect only. If you use Thymeleaf as view engine for Spring then you should add an extra package to use Spring EL (<strong>SpEL<\/strong>) as default dialect.<br \/>\n&nbsp;<\/p>\n<h1>III Configuration in Spring MVC<\/h1>\n<p>To use Thymeleaf with Spring MVC, you should first add the following dependencies in the <strong>pom.xml<\/strong> file:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n  \t&amp;lt;dependency&amp;gt;\n  \t\t&amp;lt;groupId&amp;gt;org.thymeleaf&amp;lt;\/groupId&amp;gt;\n  \t\t&amp;lt;artifactId&amp;gt;thymeleaf&amp;lt;\/artifactId&amp;gt;\n  \t\t&amp;lt;version&amp;gt;2.0.5&amp;lt;\/version&amp;gt;\n  \t\t&amp;lt;scope&amp;gt;compile&amp;lt;\/scope&amp;gt;\n  \t&amp;lt;\/dependency&amp;gt;\n  \t&amp;lt;dependency&amp;gt;\n  \t\t&amp;lt;groupId&amp;gt;org.thymeleaf&amp;lt;\/groupId&amp;gt;\n  \t\t&amp;lt;artifactId&amp;gt;thymeleaf-spring3&amp;lt;\/artifactId&amp;gt;\n  \t\t&amp;lt;version&amp;gt;2.0.5&amp;lt;\/version&amp;gt;\n  \t\t&amp;lt;scope&amp;gt;compile&amp;lt;\/scope&amp;gt;\n  \t&amp;lt;\/dependency&amp;gt; \n<\/pre>\n<p>The second dependency is necessary to use Spring EL as default dialect.<\/p>\n<p>Below is the Spring XML configuration for Thymeleaf:<\/p>\n<pre class=\"brush: xml; highlight: [5]; title: ; notranslate\" title=\"\">\n&amp;lt;bean id=&amp;quot;templateResolver&amp;quot; class=&amp;quot;org.thymeleaf.templateresolver.ServletContextTemplateResolver&amp;quot;&amp;gt;\n\t&amp;lt;property name=&amp;quot;prefix&amp;quot; value=&amp;quot;\/&amp;quot; \/&amp;gt; \n\t&amp;lt;property name=&amp;quot;suffix&amp;quot; value=&amp;quot;.html&amp;quot; \/&amp;gt; \n\t&amp;lt;property name=&amp;quot;templateMode&amp;quot; value=&amp;quot;HTML5&amp;quot; \/&amp;gt; \n\t&amp;lt;property name=&amp;quot;cacheable&amp;quot; value=&amp;quot;false&amp;quot;\/&amp;gt;\n&amp;lt;\/bean&amp;gt;\n\t\n&amp;lt;bean id=&amp;quot;templateEngine&amp;quot; class=&amp;quot;org.thymeleaf.spring3.SpringTemplateEngine&amp;quot;&amp;gt; \n\t&amp;lt;property name=&amp;quot;templateResolver&amp;quot; ref=&amp;quot;templateResolver&amp;quot; \/&amp;gt; \n&amp;lt;\/bean&amp;gt;\n\t\t\n&amp;lt;bean class=&amp;quot;org.thymeleaf.spring3.view.ThymeleafViewResolver&amp;quot;&amp;gt; \n\t&amp;lt;property name=&amp;quot;templateEngine&amp;quot; ref=&amp;quot;templateEngine&amp;quot; \/&amp;gt; \n\t&amp;lt;property name=&amp;quot;characterEncoding&amp;quot; value=&amp;quot;UTF-8&amp;quot;\/&amp;gt;\n&amp;lt;\/bean&amp;gt;\n<\/pre>\n<p>And that&#8217;s all! Please note that for development cycle, I suggest to set the <strong>cacheable<\/strong> flag to false so you can see real time updates of your template modifications. Of course this flag should be set to <strong>true in production<\/strong>.<\/p>\n<p>The variables used in the template files (such as <strong>currentUser<\/strong> in the first example) are passed to Thymeleaf via the Model object in Spring MVC @RequestMapping methods:<\/p>\n<pre class=\"brush: java; highlight: [4]; title: ; notranslate\" title=\"\">\n@RequestMapping(value = &amp;quot;\/example1&amp;quot;, method = RequestMethod.GET)\npublic String example1(Model model)\n{\n\tmodel.addAttribute(&amp;quot;currentUser&amp;quot;, new User(&amp;quot;foobar&amp;quot;, &amp;quot;Foo&amp;quot;, &amp;quot;BAR&amp;quot;, &amp;quot;&amp;quot;));\n\treturn &amp;quot;\/pages\/example1&amp;quot;;\n}\n<\/pre>\n<p>&nbsp;<\/p>\n<h1>IV Commons attributes<\/h1>\n<blockquote><p>All the examples in this chapter can be found in the demo application on GitHub <a href=\"https:\/\/github.com\/doanduyhai\/ThymeLeafDemo\" title=\"ThymeLeaf Demo\" target=\"_blank\">https:\/\/github.com\/doanduyhai\/ThymeLeafDemo<\/a>, as <strong>example3<\/strong>.<\/p><\/blockquote>\n<p>In this chapter we&#8217;ll look into most commons attributes used in Thymeleaf.<br \/>\n&nbsp;<\/p>\n<h3>A) <strong>th:if<\/strong>\/<strong>th:unless<\/strong><\/h3>\n<p> These attributes are quite straightforward. They are the mirrors of <strong>&lt;c:if&gt;<\/strong> and <strong>&lt;c:otherwise&gt;<\/strong> from JSTL.<\/p>\n<pre class=\"brush: xml; highlight: [1,5]; title: ; notranslate\" title=\"\">\n&amp;lt;div class=&amp;quot;alert alert-error alert-block&amp;quot; th:if=&amp;quot;${error != null}&amp;quot;&amp;gt;\n\t&amp;lt;h4 class=&amp;quot;alert-heading&amp;quot;&amp;gt;Error!&amp;lt;\/h4&amp;gt;\n\t An unexpected error occurs, please contact the support team\n&amp;lt;\/div&amp;gt;\n&amp;lt;div class=&amp;quot;alert alert-success alert-block&amp;quot; th:unless=&amp;quot;${error != null}&amp;quot;&amp;gt;\n\t&amp;lt;h4 class=&amp;quot;alert-heading&amp;quot;&amp;gt;Success!&amp;lt;\/h4&amp;gt;\n\t There is no error\n&amp;lt;\/div&amp;gt;\t\t\n<\/pre>\n<h3>B) <strong>th:switch<\/strong>\/<strong>th:case<\/strong><\/h3>\n<pre class=\"brush: xml; highlight: [1]; title: ; notranslate\" title=\"\">\n&amp;lt;div th:switch=&amp;quot;${switchCase}&amp;quot;&amp;gt; \n\t&amp;lt;p th:case=&amp;quot;1&amp;quot;&amp;gt;Case 1&amp;lt;\/p&amp;gt; \n\t&amp;lt;p th:case=&amp;quot;2&amp;quot;&amp;gt;Case 2&amp;lt;\/p&amp;gt;\n\t&amp;lt;p th:case=&amp;quot;3&amp;quot;&amp;gt;Case 3&amp;lt;\/p&amp;gt;\n\t&amp;lt;p th:case=&amp;quot;4&amp;quot;&amp;gt;Case 4&amp;lt;\/p&amp;gt;\n&amp;lt;\/div&amp;gt;\n<\/pre>\n<p> Not much to say, quite straightforward.<\/p>\n<h3>C) <strong>th:text<\/strong><\/h3>\n<p> Thymeleaf replaces all the HTML content of the current tag by the value provided by <strong>th:text<\/strong><\/p>\n<pre class=\"brush: xml; highlight: [2]; title: ; notranslate\" title=\"\">\n...\n\t &amp;lt;span class=&amp;quot;alert alert-success&amp;quot; th:text=&amp;quot;${realText}&amp;quot;&amp;gt;This is an unescaped sample text&amp;lt;\/span&amp;gt;\n...\n<\/pre>\n<p>Please note that the text string provided by <strong>th:text<\/strong> will be escaped (HTML encoded) by Thymeleaf. If you want to include HTML tags in the text string, use the <strong>th:utext<\/strong> instead to avoid escaping.<\/p>\n<h3>D) <strong>th:attr<\/strong><\/h3>\n<p> This attribute purpose is to add generic HTML attributes to a tag. This proves to be usefull when used with HTML 5 <strong>data-*<\/strong> attributes for data storage &amp; binding.<\/p>\n<pre class=\"brush: xml; highlight: [4]; title: ; notranslate\" title=\"\">\n&amp;lt;a href=&amp;quot;#&amp;quot; \n\tdata-url=&amp;quot;http:\/\/www.google.com&amp;quot;\n\ttitle=&amp;quot;Link to Google&amp;quot;\n\tth:attr=&amp;quot;data-url=${dataUrl},title=${realTitle}&amp;quot;\n\tth:text=&amp;quot;${dataUrl}&amp;quot;&amp;gt;\n\thttp:\/\/www.google.com\n&amp;lt;\/a&amp;gt;\n<\/pre>\n<p> At <strong>line 4<\/strong> we define 2 attributes to be evaluated by the engine: <strong>data-url<\/strong> &amp; <strong>title<\/strong>. The Thymeleaf <strong>th:attr<\/strong> accepts a list of HTML attributes separated by a coma. Please note that for the <strong>title<\/strong> value we could have defined it with the dedicated <strong>th:title<\/strong> as well, the choice is yours.<\/p>\n<p> The result after rendering is:<\/p>\n<p><strong>&lt;a title=&#8221;Link to ThymeLeaf&#8221; href=&#8221;#&#8221; data-url=&#8221;http:\/\/www.thymeleaf.org&#8221;&gt;<\/strong><\/p>\n<p> Usually we use the <strong>th:attr<\/strong> to add special HTML 5 <strong>data-*<\/strong> attributes. For common HTML attributes we use the existing Thymeleaf dedicated one.<\/p>\n<p>&nbsp;<\/p>\n<h3>E) <strong>th:value<\/strong><\/h3>\n<p> The <strong>th:value<\/strong> attribute is reserved for HTML data input tags like &lt;input&gt;, &lt;option&gt; <\/p>\n<pre class=\"brush: xml; highlight: [4]; title: ; notranslate\" title=\"\">\n&amp;lt;input class=&amp;quot;input-medium&amp;quot;\n\ttype=&amp;quot;text&amp;quot;\n\tvalue=&amp;quot;Name input&amp;quot;\n\tth:value=&amp;quot;${nameInput}&amp;quot;&amp;gt;\n&amp;lt;\/input&amp;gt;\n<\/pre>\n<h3>F) <strong>th:each<\/strong><\/h3>\n<p> This is the most usefull tag when you need to iterate through a collection of data.<\/p>\n<pre class=\"brush: xml; highlight: [13]; title: ; notranslate\" title=\"\">\n&amp;lt;table class=&amp;quot;table table-bordered&amp;quot;&amp;gt;\n\t&amp;lt;thead&amp;gt;\n\t\t&amp;lt;tr class=&amp;quot;center middle&amp;quot;&amp;gt;\n\t\t\t&amp;lt;th&amp;gt;Name&amp;lt;\/th&amp;gt;\n\t\t\t&amp;lt;th&amp;gt;Row count&amp;lt;\/th&amp;gt;\n\t\t\t&amp;lt;th&amp;gt;Row index&amp;lt;\/th&amp;gt;\n\t\t\t&amp;lt;th&amp;gt;List size&amp;lt;\/th&amp;gt;\n\t\t\t&amp;lt;th&amp;gt;Even count&amp;lt;\/th&amp;gt;\n\t\t\t&amp;lt;th&amp;gt;Odd count&amp;lt;\/th&amp;gt;\n\t\t&amp;lt;\/tr&amp;gt;\n\t&amp;lt;\/thead&amp;gt;\n\t&amp;lt;tbody&amp;gt;\n\t\t&amp;lt;tr th:each=&amp;quot;artist,rowStat : ${listArtits}&amp;quot;&amp;gt;\n\t\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.name}&amp;quot;&amp;gt;John Woo&amp;lt;\/td&amp;gt;\n\t\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.count}&amp;quot;&amp;gt;1&amp;lt;\/td&amp;gt;\n\t\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.index}&amp;quot;&amp;gt;0&amp;lt;\/td&amp;gt;\n\t\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.size}&amp;quot;&amp;gt;1&amp;lt;\/td&amp;gt;\n\t\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.even}&amp;quot;&amp;gt;false&amp;lt;\/td&amp;gt;\n\t\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.odd}&amp;quot;&amp;gt;true&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;\/tr&amp;gt;\n\t&amp;lt;\/tbody&amp;gt;\n&amp;lt;\/table&amp;gt;\n<\/pre>\n<p> The result at runtime:<br \/>\n<a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple3-iteration1.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple3-iteration1.png\" alt=\"thymeleaf-exemple3-iteration\" title=\"thymeleaf-exemple3-iteration\" width=\"630\" height=\"116\" class=\"aligncenter size-full wp-image-883\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple3-iteration1.png 785w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple3-iteration1-300x55.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p> At <strong>line 13<\/strong>, we define the <strong>th:each<\/strong> attribute. The syntax is: <strong>rowVariable[,rowStatVariable] : ${collection}<\/strong><\/p>\n<p> The <em>rowStatVariable<\/em> is an optional variable to keep track of the iteration status. This variable exposes the following properties:<\/p>\n<ul>\n<li><strong>index<\/strong>: iteration index, starting at 0<\/li>\n<li><strong>count<\/strong>: iteration count, starting at 1<\/li>\n<li><strong>size<\/strong>: size of the list over which the iteration is done<\/li>\n<li><strong>current<\/strong>: current value of the iteration<\/li>\n<li><strong>even\/odd<\/strong>: boolean to indicate whether the current element in the iteration is even or odd<\/li>\n<li><strong>first\/last<\/strong>: boolean to indicate whether the current element is the first\/last element of the iteration<\/li>\n<\/ul>\n<p> We realize that we could also use the <strong>current<\/strong> property of the <em>rowStatVariable<\/em> variable to access the current value. Instead of <strong>th:text=&#8221;${artist.name}&#8221;<\/strong> we could use <strong>th:text=&#8221;${rowStat.current.name}&#8221;<\/strong><\/p>\n<p> Please note that in this example, <strong>artist<\/strong> is a <strong>local variable<\/strong> used for the iteration. Its scope is limited to the <strong>&lt;tr&gt;<\/strong> tag. Any attempt to access <strong>artist<\/strong> outside of its scope will result in error.<\/p>\n<p>&nbsp;<\/p>\n<h3>G) <strong>th:with<\/strong>\/<strong>th:object<\/strong><\/h3>\n<p> <strong>th:with<\/strong> defines a local variable for the current context (e.g. current HTML tag and its children).<\/p>\n<pre class=\"brush: xml; highlight: [1]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;div th:with=&amp;quot;currentArtist=${listArtits[1]}&amp;quot;&amp;gt;\n\t&amp;lt;span class=&amp;quot;label label-important&amp;quot; th:text=&amp;quot;${currentArtist.name}&amp;quot;&amp;gt;Michael Jackson&amp;lt;\/span&amp;gt;&amp;lt;br\/&amp;gt;\n\t&amp;lt;span class=&amp;quot;label label-info&amp;quot; th:text=&amp;quot;${currentArtist.bio}&amp;quot;&amp;gt;Michael Joseph Jackson (August 29, 1958 - June 25, 2009) was an American recording artist, entertainer, and businessman...&amp;lt;\/span&amp;gt;&amp;lt;br\/&amp;gt;\n\t&amp;lt;span class=&amp;quot;label label-inverse&amp;quot; th:text=&amp;quot;${currentArtist.discography}&amp;quot;&amp;gt;Got to Be There, B...&amp;lt;\/span&amp;gt;\n&amp;lt;\/div&amp;gt;\n<\/pre>\n<p> On the other hand <strong>th:object<\/strong> defines a selected object that can be accessed in the current context (e.g. current HTML tag and its children) by the special asterisk <strong>*{  }<\/strong> short-hand syntax.<\/p>\n<p> The meaning of this attribute is similar to the <em>With()<\/em> syntax in C# language. <\/p>\n<pre class=\"brush: xml; highlight: [1,2]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;div th:object=&amp;quot;${listArtits[0]}&amp;quot;&amp;gt;\n\t&amp;lt;span class=&amp;quot;label label-important&amp;quot; th:text=&amp;quot;*{name}&amp;quot;&amp;gt;Michael Jackson&amp;lt;\/span&amp;gt;&amp;lt;br\/&amp;gt;\n\t&amp;lt;span class=&amp;quot;label label-info&amp;quot; th:text=&amp;quot;*{bio}&amp;quot;&amp;gt;Michael Joseph Jackson (August 29, 1958 - June 25, 2009) was an American recording artist, entertainer, and businessman...&amp;lt;\/span&amp;gt;&amp;lt;br\/&amp;gt;\n\t&amp;lt;span class=&amp;quot;label label-inverse&amp;quot; th:text=&amp;quot;*{discography}&amp;quot;&amp;gt;Got to Be There, B...&amp;lt;\/span&amp;gt;\n&amp;lt;\/div&amp;gt;\n<\/pre>\n<p>The main difference between <strong>th:object<\/strong> and <strong>th:with<\/strong> is that <strong>th:object<\/strong> defines a <strong>selected object<\/strong> in the current context accessible by the special <strong>*{  }<\/strong> syntax. All property look-up inside a <strong>*{  }<\/strong> expression is done with regard to the <strong>selected object<\/strong>. Inside the same context the standard syntax with <strong>${ }<\/strong> can still be used though.<\/p>\n<p>On the other hand <strong>th:with<\/strong> will create a new temporary variable in the variable map (Spring <strong>Model<\/strong> object) whose scope is limited to the current context.<\/p>\n<p>&nbsp;<\/p>\n<h3>H) <strong>th:remove<\/strong><\/h3>\n<p> This attribute is usefull for template static preview. Let&#8217;s suppose that we have a template file with a table containing a list of artists. We will design the table using the <strong>th:each<\/strong> attribute as described previously to iterate through the result list.<\/p>\n<p> However our page will look very poor in a static display since it only has one row. We could remedy to this by adding extra <strong>mocked<\/strong> rows but they need to be removed at runtime. That&#8217;s the purpose of <strong>th:remove<\/strong><\/p>\n<pre class=\"brush: xml; highlight: [8,14]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;tbody&amp;gt;\n\t&amp;lt;tr th:each=&amp;quot;artist,rowStat : ${listArtits}&amp;quot;&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.count}&amp;quot;&amp;gt;1&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.name}&amp;quot;&amp;gt;Michael Jackson&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.discography}&amp;quot;&amp;gt;Got to Be There, Ben, Music &amp;amp;amp; Me, Forever Michael...&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.bio}&amp;quot;&amp;gt;Michael Joseph Jackson (August 29, 1958 - June 25, 2009) was an American recording artist, entertainer, and businessman...&amp;lt;\/td&amp;gt;\n\t&amp;lt;\/tr&amp;gt;\n\t&amp;lt;tr th:remove=&amp;quot;all&amp;quot;&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.count}&amp;quot;&amp;gt;2&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.name}&amp;quot;&amp;gt;Madonna&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.discography}&amp;quot;&amp;gt;Madonna, Like a Virgin, True Blue...&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.bio}&amp;quot;&amp;gt;Madonna (born Madonna Louise Ciccone August 16, 1958) is an American singer, songwriter, actress and entrepreneur...&amp;lt;\/td&amp;gt;\t\t\t\t\n\t&amp;lt;\/tr&amp;gt;\n\t&amp;lt;tr th:remove=&amp;quot;all&amp;quot;&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.count}&amp;quot;&amp;gt;3&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.name}&amp;quot;&amp;gt;Elton John&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.discography}&amp;quot;&amp;gt;Empty Sky, Elton John, Tumbleweed Connection...&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.bio}&amp;quot;&amp;gt;Sir Elton Hercules John, CBE (born Reginald Kenneth Dwight on 25 March 1947) is an English rock singer-songwriter, composer, pianist and occasional actor....&amp;lt;\/td&amp;gt;\t\t\t\t\n\t&amp;lt;\/tr&amp;gt;\t\t\t\t\n&amp;lt;\/tbody&amp;gt;\n<\/pre>\n<p> The second and third row (<strong>line 8 &amp; 14<\/strong>) will be removed at runtime by the engine. However if we have many <strong>mocked<\/strong> rows we should add the <strong>th:remove<\/strong> for each of them which is quite tedious.<\/p>\n<p> The solution is given again by <strong>th:remove<\/strong> with the value &#8220;<em>all-but-first<\/em>&#8221; instead of &#8220;<em>all<\/em>&#8220;. It tells the engine to remove all the children of the current tag except the first one. The above code can be modified to take advantage of this feature.<\/p>\n<pre class=\"brush: xml; highlight: [1]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;tbody th:remove=&amp;quot;all-but-first&amp;quot;&amp;gt;\n\t&amp;lt;tr th:each=&amp;quot;artist,rowStat : ${listArtits}&amp;quot;&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.count}&amp;quot;&amp;gt;1&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.name}&amp;quot;&amp;gt;Michael Jackson&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.discography}&amp;quot;&amp;gt;Got to Be There, Ben, Music &amp;amp;amp; Me, Forever Michael...&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.bio}&amp;quot;&amp;gt;Michael Joseph Jackson (August 29, 1958 - June 25, 2009) was an American recording artist, entertainer, and businessman...&amp;lt;\/td&amp;gt;\n\t&amp;lt;\/tr&amp;gt;\n\t&amp;lt;tr&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.count}&amp;quot;&amp;gt;2&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.name}&amp;quot;&amp;gt;Madonna&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.discography}&amp;quot;&amp;gt;Madonna, Like a Virgin, True Blue...&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.bio}&amp;quot;&amp;gt;Madonna (born Madonna Louise Ciccone August 16, 1958) is an American singer, songwriter, actress and entrepreneur...&amp;lt;\/td&amp;gt;\t\t\t\t\n\t&amp;lt;\/tr&amp;gt;\n\t&amp;lt;tr&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${rowStat.count}&amp;quot;&amp;gt;3&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.name}&amp;quot;&amp;gt;Elton John&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.discography}&amp;quot;&amp;gt;Empty Sky, Elton John, Tumbleweed Connection...&amp;lt;\/td&amp;gt;\n\t\t&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist.bio}&amp;quot;&amp;gt;Sir Elton Hercules John, CBE (born Reginald Kenneth Dwight on 25 March 1947) is an English rock singer-songwriter, composer, pianist and occasional actor....&amp;lt;\/td&amp;gt;\t\t\t\t\n\t&amp;lt;\/tr&amp;gt;\t\t\t\t\n&amp;lt;\/tbody&amp;gt;\n<\/pre>\n<p> The <strong>th:remove<\/strong> supports some more values, please refer to the documentation for the complete list.<\/p>\n<p>To be continued&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today we are going to look into Thymeleaf, a very innovative and full HTML5-oriented templating engine. Thymeleaf, by definition, can be used as a standalone engine but when associated with Spring MVC, it gives the best of its essence. Once&#8230;<br \/><a class=\"read-more-button\" href=\"https:\/\/www.doanduyhai.com\/blog\/?p=841\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[14,31,19],"tags":[],"_links":{"self":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/841"}],"collection":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=841"}],"version-history":[{"count":0,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/841\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=841"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=841"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=841"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}