{"id":895,"date":"2012-04-14T22:22:25","date_gmt":"2012-04-14T20:22:25","guid":{"rendered":"http:\/\/doanduyhai.wordpress.com\/?p=895"},"modified":"2012-04-14T22:22:25","modified_gmt":"2012-04-14T20:22:25","slug":"spring-mvc-part-iv-thymeleaf-advanced-usage","status":"publish","type":"post","link":"https:\/\/www.doanduyhai.com\/blog\/?p=895","title":{"rendered":"Spring MVC part IV: ThymeLeaf advanced usage"},"content":{"rendered":"<p>This post follows on from the previous post on <a title=\"http:\/\/doanduyhai.wordpress.com\/2012\/04\/14\/spring-mvc-part-iii-thymeleaf-integration\/\" href=\"http:\/\/doanduyhai.wordpress.com\/2012\/04\/14\/spring-mvc-part-iii-thymeleaf-integration\/\">Thymeleaf integration with Spring MVC<\/a>.<\/p>\n<p>Today we&#8217;ll look at some advanced features of Thymeleaf<\/p>\n<p><!--more--><\/p>\n<blockquote><p>Please note that all the examples in this post can be found in a demo application on GitHub <a title=\"ThymeLeaf Demo\" href=\"https:\/\/github.com\/doanduyhai\/ThymeLeafDemo\" target=\"_blank\">https:\/\/github.com\/doanduyhai\/ThymeLeafDemo<\/a><\/p><\/blockquote>\n<h1>I Fragments inclusion<\/h1>\n<blockquote><p>All the examples in this chapter can be found in the demo application on GitHub <a title=\"ThymeLeaf Demo\" href=\"https:\/\/github.com\/doanduyhai\/ThymeLeafDemo\" target=\"_blank\">https:\/\/github.com\/doanduyhai\/ThymeLeafDemo<\/a>, as <strong>example4<\/strong>.<\/p><\/blockquote>\n<h3>A) General usage<\/h3>\n<p>A notheworthy templating engine has to provide a fragment system to avoid duplicating code. Fortunately Thymeleaf is shipped with a fragment inclusion system we&#8217;ll see shortly.<\/p>\n<p>The main entry point for fragment inclusion is the <strong>th:include<\/strong> attribute. The syntax is: <em>th:include=&#8221;<strong>fragment_file<\/strong> :: <strong>fragment_name|[DOM_selector]<\/strong>&#8220;<\/em>.<\/p>\n<p>The <strong>fragment_name<\/strong> or <strong>DOM_selector<\/strong> will be used to select the DOM object in the <strong>fragment_file<\/strong> file and inject it in the current document. <strong>The expression parsing and variable resolution will be performed after the fragment injection, not before<\/strong>. <strong>Please note that the DOM_selector needs to be put in square brackets<\/strong>. The DOM_selector uses a subset of XPath syntax, more details <a title=\"DOMSelector API\" href=\"http:\/\/www.thymeleaf.org\/apidocs\/thymeleaf\/2.0.5\/\" target=\"_blank\">here<\/a>.<\/p>\n<p>Let&#8217;s define a template file <strong>common.html<\/strong> used as fragment container:<\/p>\n<pre class=\"brush: xml; highlight: [3]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;html xmlns=&amp;quot;http:\/\/www.w3.org\/1999\/xhtml&amp;quot;\n\txmlns:th=&amp;quot;http:\/\/www.thymeleaf.org&amp;quot;&amp;gt;\n&amp;lt;head id=&amp;quot;headerFragment&amp;quot; th:fragment=&amp;quot;headerFragment&amp;quot;&amp;gt;\n\t&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;..\/assets\/css\/bootstrap.css&amp;quot; th:href=&amp;quot;@{\/assets\/css\/bootstrap.css}&amp;quot; \/&amp;gt;\n\t&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;..\/assets\/css\/thymeleaf-demo.css&amp;quot; th:href=&amp;quot;@{\/assets\/css\/thymeleaf-demo.css}&amp;quot; \/&amp;gt;\n&amp;lt;\/head&amp;gt;\n&amp;lt;body&amp;gt;\n\t&amp;lt;div class=&amp;quot;container&amp;quot;&amp;gt;\n\t&amp;lt;\/div&amp;gt;\n&amp;lt;\/body&amp;gt;\n&amp;lt;\/html&amp;gt;\n<\/pre>\n<p>Please notice the usage of <strong>th:fragment<\/strong> to define the <strong>fragment_name<\/strong>.<\/p>\n<p>Now let&#8217;s write an <strong>example4.html<\/strong> page to test it:<\/p>\n<pre class=\"brush: xml; highlight: [1]; title: ; notranslate\" title=\"\">\n&amp;lt;head th:include=&amp;quot;fragment\/common :: headerFragment&amp;quot; \/&amp;gt;\n&amp;lt;body&amp;gt;\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;hero-unit&amp;quot;&amp;gt;\n\t    &amp;lt;h1&amp;gt;ThymeLeaf is awesome !&amp;lt;\/h1&amp;gt;\n\t    &amp;lt;p&amp;gt;This is a simple hero-unit layout to demonstrate the fragment inclusion system&amp;lt;\/p&amp;gt;\n\t    &amp;lt;p&amp;gt;\n\t    \t&amp;lt;a class=&amp;quot;btn btn-primary btn-large&amp;quot; href=&amp;quot;http:\/\/www.thymeleaf.org&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;\n\t    \tLearn more about ThymeLeaf ...\n\t    \t&amp;lt;\/a&amp;gt;\n\t    &amp;lt;\/p&amp;gt;\n    &amp;lt;\/div&amp;gt;\n&amp;lt;\/div&amp;gt;\n&amp;lt;\/body&amp;gt;\n<\/pre>\n<p><em>headerFragment<\/em> indicates the <strong>fragment_name<\/strong> defined in the <strong>common.html<\/strong> file previously.<\/p>\n<p>If we wish to use <strong>DOM_Selector<\/strong> instead of <strong>fragment_name<\/strong>, the <strong>example4.html<\/strong> page should be modified as follow:<\/p>\n<pre class=\"brush: xml; highlight: [1]; title: ; notranslate\" title=\"\">\n&amp;lt;head th:include=&amp;quot;fragment\/common :: [\/\/head]&amp;quot; \/&amp;gt;\n...\n<\/pre>\n<p>In this case there is no need to define the <strong>fragment_name<\/strong> with <strong>th:fragment<\/strong> in the <strong>common.html<\/strong> file.<br \/>\n&nbsp;<\/p>\n<h3>B) Fragment container<\/h3>\n<p>With the powerfull selection mechanism for fragment, we can define several fragments in a same container file and include them in any of our page.<\/p>\n<p>Let&#8217;s define a footer fragment in <strong>common.html<\/strong><\/p>\n<pre class=\"brush: xml; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;footer id=&amp;quot;center-footer&amp;quot;&amp;gt;\n\t&amp;lt;div id=&amp;quot;footerText&amp;quot; class=&amp;quot;span12&amp;quot; &amp;gt;Copyright 2012 &amp;lt;a href=&amp;quot;http:\/\/doanduyhai.wordpress.com&amp;quot;&amp;gt;doanduyhai&amp;lt;\/a&amp;gt; |\n       \t \t&amp;lt;a href=&amp;quot;https:\/\/github.com\/doanduyhai\/ThymeLeafDemo&amp;quot;&amp;gt;Fork ThymeLeaf Demo on Github&amp;lt;\/a&amp;gt; |\n        \t&amp;lt;a href=&amp;quot;https:\/\/twitter.com\/#!\/doanduyhai&amp;quot;&amp;gt;Follow @doanduyhai on Twitter&amp;lt;\/a&amp;gt;\n\t&amp;lt;\/div&amp;gt;\n&amp;lt;\/footer&amp;gt;\n<\/pre>\n<p>And then include it in our <strong>example4.html<\/strong> page:<\/p>\n<pre class=\"brush: xml; highlight: [2]; title: ; notranslate\" title=\"\">\n...\n&amp;lt;div th:include=&amp;quot;fragment\/common :: [\/\/footer[@id='center-footer']]&amp;quot;&amp;gt;&amp;lt;\/div&amp;gt;\n...\n<\/pre>\n<p>Please note the quite verbose DOM selector expression to select the footer element. A simpler expression like &#8220;<em>[\/\/footer]<\/em>&#8221; would be sufficient but I let it as is for the tutorial purpose.<br \/>\n&nbsp;<\/p>\n<h3>C) Static preview and fragment inclusion<\/h3>\n<p>There is one problem with our fragment inclusion, it does not work at all for static page preview.<\/p>\n<p>Below is the static display of the previous example:<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple4-static-fragment-preview.png\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-899\" title=\"thymeleaf-exemple4-static-fragment-preview\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple4-static-fragment-preview.png\" alt=\"thymeleaf-exemple4-static-fragment-preview\" width=\"514\" height=\"136\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple4-static-fragment-preview.png 514w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple4-static-fragment-preview-300x79.png 300w\" sizes=\"(max-width: 514px) 100vw, 514px\" \/><\/a><\/p>\n<p>The rendering at runtime is:<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple4-runtime-fragment-render.png\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-900\" title=\"thymeleaf-exemple4-runtime-fragment-render\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple4-runtime-fragment-render.png\" alt=\"thymeleaf-exemple4-runtime-fragment-render\" width=\"630\" height=\"203\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple4-runtime-fragment-render.png 825w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple4-runtime-fragment-render-300x97.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p>The reason of this discrepancy is that in the static version the CSS styles are not available since there is no fragment inclusion.<\/p>\n<p><del datetime=\"2012-04-18T20:02:51+00:00\">To fix this, we simply add the stylesheet &lt;rel&gt; tags in the header of the static page. All this will be removed anyway at runtime by the fragment inclusion.<\/del><\/p>\n<p> <em>Edit: I&#8217;ve been informed by <a href=\"https:\/\/twitter.com\/#!\/thymeleaf\" title=\"Daniel\">Daniel Fern\u00e1ndez<\/a> and <a href=\"https:\/\/twitter.com\/#!\/heydevgeek\" title=\"Brian Keeter\" target=\"_blank\">Brian Keeter<\/a> about <a href=\"http:\/\/sourceforge.net\/u\/jjbenson\/wiki\/thymol\/\" title=\"Thymol\" target=\"_blank\">Thymol<\/a>,a javascript-base solution to perform fragment inclusion for static template preview. So there is no restriction anymore for static fragment inclusion.<\/em><\/p>\n<p>&nbsp;<\/p>\n<h1>II Thymeleaf and Spring EL (SpEL)<\/h1>\n<blockquote><p>All the examples in this chapter can be found in the demo application on GitHub <a title=\"ThymeLeaf Demo\" href=\"https:\/\/github.com\/doanduyhai\/ThymeLeafDemo\" target=\"_blank\">https:\/\/github.com\/doanduyhai\/ThymeLeafDemo<\/a>, as <strong>example5<\/strong>.<\/p><\/blockquote>\n<p>When used in conjunction with Spring MVC, the default dialect used in the template files is Spring EL. It leverages Thymeleaf  and offers a tremendous flexibility to manipulate data directly in the view.<br \/>\n&nbsp;<\/p>\n<h3>A) Bean references &amp; method invocation<\/h3>\n<p>Thymeleaf exposes a special object, <strong>beans<\/strong>, to let you access all Spring beans in the current application context.<\/p>\n<p>Let&#8217;s define a <strong>dateFormatter<\/strong> bean as follow:<\/p>\n<pre class=\"brush: xml; highlight: [2]; title: ; notranslate\" title=\"\">\n...\n&amp;lt;bean id=&amp;quot;dateFormatter&amp;quot; class=&amp;quot;doan.thymeleaf.demo.util.DateFormatter&amp;quot;\/&amp;gt;\n...\n<\/pre>\n<p>The source code of the bean is quite straightforward:<\/p>\n<pre class=\"brush: java; highlight: [5]; title: ; notranslate\" title=\"\">\npublic class DateFormatter\n{\n\tprivate static final String DATE_FORMAT = &amp;quot;yyyy-MM-dd HH:mm:ss&amp;quot;;\n\n\tpublic String getCurrentDate()\n\t{\n\t\treturn new DateTime(new Date()).toString(DATE_FORMAT);\n\t}\n}\n<\/pre>\n<p>This bean defines a public <em>getCurrentDate()<\/em> method we&#8217;ll use in our page.<\/p>\n<pre class=\"brush: xml; highlight: [2]; title: ; wrap-lines: false; notranslate\" title=\"\">\n...\n&amp;lt;span th:text=&amp;quot;${'Current date is : '+beans.dateFormatter.getCurrentDate()}&amp;quot;&amp;gt;Current date is : 2012-04-14 17:30:00&amp;lt;\/span&amp;gt;\n...\n<\/pre>\n<p>To access our bean named &#8220;<strong>dateFormatter<\/strong>&#8220;, we have to use the helper object &#8220;<strong>beans<\/strong>&#8221; provided by Thymeleaf. Under the hood <strong>beans<\/strong> is simply a Map which contains all references to the beans registered in the Spring context. There is really no magic here.<br \/>\n&nbsp;<\/p>\n<h3>B) Static fields &amp; methods<\/h3>\n<p>Spring EL provides the <strong>T( )<\/strong> operator to access a class level(static) field or method.<\/p>\n<pre class=\"brush: xml; highlight: [2]; title: ; wrap-lines: false; notranslate\" title=\"\">\n...\n&amp;lt;span th:text=&amp;quot;${'The application name is : '+T(doan.thymeleaf.demo.util.Constants).APPLICATION_NAME}&amp;quot;&amp;gt;The application name is : Test&amp;lt;\/span&amp;gt;\n...\n<\/pre>\n<p>This can be usefull to access some constants defined in the classpath without having to add the constant in the Model map.<br \/>\n&nbsp;<\/p>\n<h3>C) Projection &amp; selection on collection<\/h3>\n<p>Projection and selection are vocabulary from the relational world (<strong>SQL<\/strong>). <strong>Selection<\/strong> corresponds to <strong>row filtering<\/strong> (with WHERE clause) and <strong>projection<\/strong> corresponds to <strong>column restriction<\/strong> (the SELECT clause).<\/p>\n<p>When applied to a collection of elements in Java:<\/p>\n<ul>\n<\/ul>\n<ul>\n<li><strong>selection<\/strong> means filtering each element of the collection using its properties. The result of such an operation is a <strong>subset of the initial collection<\/strong>, only matching elements are retained<\/li>\n<\/ul>\n<p>.<\/p>\n<ul>\n<li><strong>projection<\/strong> means filtering the property of each element in the collection. The result of a projection operation is a a <strong>new collection<\/strong>, <strong>with the same number of elements than the original one<\/strong>, <strong>but containing only the filtered property of the elements<\/strong>, not the whole element object itself<\/li>\n<\/ul>\n<p>The syntax of the selection operator is : <em>collection<strong>.?<\/strong>[property == value]<\/em><br \/>\nThe syntax of the projection operator is : <em>collection<strong>.!<\/strong>[property]<\/em><\/p>\n<p>Of course, for selection we can combine several conditions with logical operators (and, or, not) to filter on different properties. Similarly, with the projection, it is possible to fetch several properties by concatenating them.<\/p>\n<p>An example is better than words, let&#8217;s see those in action:<\/p>\n<pre class=\"brush: xml; highlight: [1]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;tr th:each=&amp;quot;artist,rowStat : ${listArtits.?[alive == true]}&amp;quot;&amp;gt;\n\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&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&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&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&amp;lt;\/tr&amp;gt;\n<\/pre>\n<p>Above we only select alive artists.<\/p>\n<p>If we want to display only the firstname and lastname of the artist, we can &#8220;project&#8221; on both properties:<\/p>\n<pre class=\"brush: xml; highlight: [1]; title: ; notranslate\" title=\"\">\n&amp;lt;tr th:each=&amp;quot;artist,rowStat : ${listArtits.![firstname+' '+lastname]}&amp;quot;&amp;gt;\n\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&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist}&amp;quot;&amp;gt;Michael Jackson&amp;lt;\/td&amp;gt;\n&amp;lt;\/tr&amp;gt;\n<\/pre>\n<p>Of course it is possible to combine selection and projection:<\/p>\n<pre class=\"brush: xml; highlight: [1]; title: ; notranslate\" title=\"\">\n&amp;lt;tr th:each=&amp;quot;artist,rowStat : ${listArtits.?[alive == true].![firstname+' '+lastname]}&amp;quot;&amp;gt;\n\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&amp;lt;td class=&amp;quot;center middle&amp;quot; th:text=&amp;quot;${artist}&amp;quot;&amp;gt;Michael Jackson&amp;lt;\/td&amp;gt;\n&amp;lt;\/tr&amp;gt;\n<\/pre>\n<p>Please note that the order between projection and selection is important. If you &#8220;project&#8221; on a property before doing selection, the latter can only filter on this same property.<\/p>\n<p>&nbsp;<\/p>\n<h1>III Inlining &amp; Javascript tricks<\/h1>\n<blockquote><p>All the examples in this chapter can be found in the demo application on GitHub <a title=\"ThymeLeaf Demo\" href=\"https:\/\/github.com\/doanduyhai\/ThymeLeafDemo\" target=\"_blank\">https:\/\/github.com\/doanduyhai\/ThymeLeafDemo<\/a>, as <strong>example6<\/strong>.<\/p><\/blockquote>\n<h3>A) Text inlining<\/h3>\n<p>Text inlining means that instead of being evaluated in the <strong>th:text<\/strong> attribute, the tag body is parsed by the engine and evaluated.<\/p>\n<p>To do text inlining, we use the <strong>th:inline<\/strong> attribute with <strong>th:inline=&#8221;text&#8221;<\/strong>. The expression to be evaluated should be enclosed in double square brackets <strong>[[ ]]<\/strong><\/p>\n<pre class=\"brush: xml; highlight: [2]; title: ; notranslate\" title=\"\">\n...\n&amp;lt;span th:inline=&amp;quot;text&amp;quot;&amp;gt;[[${'Current date is : '+beans.dateFormatter.getCurrentDate()}]]&amp;lt;\/span&amp;gt;\n...\n<\/pre>\n<p>The drawback of text inlining is the static page preview. What is displayed is the inlined expression itself:<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-example6-text-inlining.png\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-908\" title=\"thymeleaf-example6-text-inlining\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-example6-text-inlining.png\" alt=\"thymeleaf-example6-text-inlining\" width=\"373\" height=\"25\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-example6-text-inlining.png 373w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-example6-text-inlining-300x20.png 300w\" sizes=\"(max-width: 373px) 100vw, 373px\" \/><\/a><\/p>\n<h3>B) Script inlining and variables propagation<\/h3>\n<p>With Thymeleaf it is also possible to evaluate SpEL expression inside a script tag. For the moment only Javascript and Google Dart are supported as script languages. To inline script, the value of <strong>th:inline<\/strong> should be set to <em>&#8220;script&#8221;<\/em>. The script code should also be enclosed between <strong>\/*&lt;![CDATA[*\/<\/strong> and <strong>\/*]]&gt;*\/<\/strong>. Each SpEL expression inside the script body should be enclosed in <strong>\/*[[ ]]*\/<\/strong><\/p>\n<pre class=\"brush: xml; highlight: [9]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;div&amp;gt;\n\t&amp;lt;button id=&amp;quot;actionButton&amp;quot; type=&amp;quot;button&amp;quot; onclick=&amp;quot;displayApplicationName();&amp;quot;&amp;gt;Get Application name&amp;lt;\/button&amp;gt;\n\t&amp;lt;br\/&amp;gt;&amp;lt;br\/&amp;gt;\n\t&amp;lt;span id=&amp;quot;displaySpan&amp;quot;&amp;gt;Application name : &amp;lt;\/span&amp;gt;\n&amp;lt;\/div&amp;gt;\n&amp;lt;script th:inline=&amp;quot;javascript&amp;quot;&amp;gt;\n\/*&amp;lt;![CDATA[*\/\n\n\tvar applicationName = \/*[[${T(doan.thymeleaf.demo.util.Constants).APPLICATION_NAME}]]*\/ &amp;quot;Test&amp;quot;;\n\n\tfunction displayApplicationName()\n\t{\n\t\tdocument.getElementById('displaySpan').innerHTML='Application name : '+applicationName;\n\t}\n\/*]]&amp;gt;*\/\n&amp;lt;\/script&amp;gt;\n<\/pre>\n<p>One important thing to notice with script inlining is that it still works for static preview. Indeed the Javascript variable <strong>applicationName<\/strong> is declared with an inline expression followed by a default value: &#8220;<strong>Test<\/strong>&#8220;.<\/p>\n<p>When displayed in a browser, the inlined expression between <strong>\/*[[ ]]*\/<\/strong> will be ignored (considered as a comment) so the default value applies. A browser will see the variable declaration as:<\/p>\n<p><em><strong>var applicationName = &#8220;Test&#8221;;<\/strong><\/em><\/p>\n<p>At runtime, Thymeleaf will evaluate the inlined expression and everything that follows this expression will be stripped out. Thymeleaf will see the variable declaration as:<\/p>\n<p><em><strong>var applicationName = ${T(doan.thymeleaf.demo.util.Constants).APPLICATION_NAME}<\/strong><\/em><\/p>\n<p>Thus script inlining offers us a way to <strong>propagate variables defined in the server up to the Javascript layer<\/strong>. But what is it for ?<\/p>\n<p><strong>The idea behind the variables propagation is to define a variable value at only one place, on the server side<\/strong>. If they are defined at many places, changing them required code modification everywhere, with the risk of code discrepancy.<br \/>\n&nbsp;<\/p>\n<h1>IV Helper objects awesomeness<\/h1>\n<blockquote><p>All the examples in this chapter can be found in the demo application on GitHub <a title=\"ThymeLeaf Demo\" href=\"https:\/\/github.com\/doanduyhai\/ThymeLeafDemo\" target=\"_blank\">https:\/\/github.com\/doanduyhai\/ThymeLeafDemo<\/a>, as <strong>example2<\/strong>.<\/p><\/blockquote>\n<p>Thymeleaf was designed with productivity in mind. It comes with numerous helper objects to simplify developers&#8217; life. Below is the complete list of available helper objects and their function:<\/p>\n<ul>\n<li><strong>dates<\/strong> : utility methods for java.util.Date objects: formatting, component extraction, etc.<\/li>\n<li><strong>calendars<\/strong> : analogous to #dates, but for java.util.Calendar objects.<\/li>\n<li><strong>numbers<\/strong> : utility methods for formatting numeric objects.<\/li>\n<li><strong>strings<\/strong> : utility methods for String objects: contains, startsWith, prepending\/appending, etc.<\/li>\n<li><strong>objects<\/strong> : utility methods for objects in general.<\/li>\n<li><strong>bools<\/strong> : utility methods for boolean evaluation.<\/li>\n<li><strong>arrays<\/strong> : utility methods for arrays.<\/li>\n<li><strong>lists<\/strong> : utility methods for lists.<\/li>\n<li><strong>sets<\/strong> : utility methods for sets.<\/li>\n<li><strong>maps<\/strong> : utility methods for maps.<\/li>\n<li><strong>aggregates<\/strong> : utility methods for creating aggregates on arrays or collections.<\/li>\n<li><strong>messages<\/strong> : utility methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{&#8230;} syntax.<\/li>\n<\/ul>\n<p>It will take hours to go through all of them so we&#8217;ll only focus on the most usefull utility functions.<\/p>\n<ul>\n<li><strong>date formatting<\/strong>: ${#dates.format(date, &#8216;dd\/MMM\/yyyy HH:mm&#8217;)}<\/li>\n<li><strong>current time<\/strong>: ${#dates.createNow()}<\/li>\n<li><strong>empty or null string check<\/strong>: ${#strings.isEmpty(name)}<\/li>\n<li><strong>string operations<\/strong>: #strings.indexOf, #strings.substring, #strings.replace, #strings.prepend, #strings.append, #strings.toUpperCase, #strings.toLowerCase, #strings.trim, #strings.length, #strings.abbreviate<\/li>\n<li><strong>string collection manipulation<\/strong>: #strings.listJoin, #strings.arrayJoin, #strings.setJoin, strings.listSplit, strings.arraySplit, strings.setSplit<\/li>\n<li><strong>object null safe<\/strong>: ${#objects.nullSafe(obj,default)}<\/li>\n<li><strong>list manipulation<\/strong>: ${#lists.size(list)}, ${#lists.isEmpty(list)}, ${#lists.contains(list, element)}<\/li>\n<li><strong>message retrieval<\/strong>: ${#messages.msg(&#8216;msgKey&#8217;)}, ${#messages.msg(&#8216;msgKey&#8217;, param1, param2)}<\/li>\n<\/ul>\n<p>Let&#8217;s put them in action in an example:<\/p>\n<pre class=\"brush: xml; highlight: [2,8,21,22]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;div class=&amp;quot;alert&amp;quot;\n\tth:if=&amp;quot;${results != null and #lists.isEmpty(results) and searchAction != null}&amp;quot;&amp;gt;\n    \t&amp;lt;strong&amp;gt;No result found!&amp;lt;\/strong&amp;gt; Please retry with different search filter(s).\n&amp;lt;\/div&amp;gt;\n&amp;lt;section id=&amp;quot;searchResult&amp;quot;&amp;gt;\n\t&amp;lt;table id=&amp;quot;resultTable&amp;quot;\n\t\tclass=&amp;quot;table table-bordered&amp;quot;\n\t\tth:if=&amp;quot;${results != null and not #lists.isEmpty(results)}&amp;quot;&amp;gt;\n\t\t&amp;lt;thead&amp;gt;\n\t\t\t&amp;lt;tr class=&amp;quot;center middle&amp;quot;&amp;gt;\n\t\t\t\t&amp;lt;th&amp;gt;#&amp;lt;\/th&amp;gt;\n\t\t\t\t&amp;lt;th&amp;gt;Name&amp;lt;\/th&amp;gt;\n\t\t\t\t&amp;lt;th&amp;gt;Discography&amp;lt;\/th&amp;gt;\n\t\t\t\t&amp;lt;th&amp;gt;Bio&amp;lt;\/th&amp;gt;\n\t\t\t&amp;lt;\/tr&amp;gt;\n\t\t&amp;lt;\/thead&amp;gt;\n\t\t&amp;lt;tbody&amp;gt;\n\t\t\t&amp;lt;tr th:each=&amp;quot;artist,rowStat : ${results}&amp;quot;&amp;gt;\n\t\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\t&amp;lt;td th:text=&amp;quot;${artist.name}&amp;quot;&amp;gt;Mariah Carey&amp;lt;\/td&amp;gt;\n\t\t\t\t&amp;lt;td th:text=&amp;quot;${#strings.abbreviate(#strings.listJoin(artist.discography,', '),30)}&amp;quot;&amp;gt;Mariah Carey, Emotions, Music Box, Merry Christmas, DayDream, Butter...&amp;lt;\/td&amp;gt;\n\t\t\t\t&amp;lt;td th:text=&amp;quot;${#strings.abbreviate(artist.bio,100)}&amp;quot;&amp;gt;Mariah Carey (born March 27, 1970) is an American singer...&amp;lt;\/td&amp;gt;\n\t\t\t&amp;lt;\/tr&amp;gt;\n\t\t&amp;lt;\/tbody&amp;gt;\n\t&amp;lt;\/table&amp;gt;\n&amp;lt;\/section&amp;gt;\n<\/pre>\n<p>At <strong>lines 2 &amp; 8<\/strong> we use <strong>#lists.isEmpty()<\/strong> to check for result emptiness. Unfortunately this method is not null safe so a prior null check is required.<\/p>\n<p><em>Edit: from ThymeLeaf version <strong>2.0.7<\/strong>, null check is no longer required because <strong>isEmpty()<\/strong> methods in  <strong>#arrays<\/strong>, <strong>#lists<\/strong>, <strong>#maps<\/strong> and <strong>#sets<\/strong> are null-safe.<\/em><\/p>\n<p>At <strong>line 21<\/strong> we use <strong>#strings.listJoin()<\/strong> to concatenate all the discography into a string and then apply <strong>#strings.abbreviate()<\/strong> to shorten it.<\/p>\n<p>Below is the render at runtime:<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple2-helper-objects.png\"><img loading=\"lazy\" class=\"aligncenter size-full wp-image-930\" title=\"thymeleaf-exemple2-helper-objects\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple2-helper-objects.png\" alt=\"\" width=\"630\" height=\"160\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple2-helper-objects.png 784w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/04\/thymeleaf-exemple2-helper-objects-300x77.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<h1>V Spring Security integration<\/h1>\n<blockquote><p>All the examples in this chapter can be found in the demo application on GitHub <a title=\"ThymeLeaf Demo\" href=\"https:\/\/github.com\/doanduyhai\/ThymeLeafDemo\" target=\"_blank\">https:\/\/github.com\/doanduyhai\/ThymeLeafDemo<\/a>, as <strong>example7<\/strong>.<\/p><\/blockquote>\n<p>Last but not least, we&#8217;ll see how Thymeleaf can be integrated with Spring Security. If you are an attentive reader if this blog, maybe you already read the post on <a title=\"Spring Security part V : Security tags\" href=\"http:\/\/doanduyhai.wordpress.com\/2012\/02\/26\/spring-security-part-v-security-tags\/\" target=\"_blank\">Spring Security taglibs<\/a> for JSP. If not I urge you to do so.<\/p>\n<p>The problem is that this very convenient tag lib is only available for JSP, not for Thymeleaf. However with the flexibility of Spring MVC, it is possible to inject a security object in the Model map so it becomes available for the template engine at runtime.<\/p>\n<p>The original solution was found by <strong>Zemi<\/strong> on the <a title=\"Thymeleaf and Spring Security\" href=\"http:\/\/forum.thymeleaf.org\/Thymeleaf-and-Spring-Security-td3205099.html\" target=\"_blank\">Thymeleaf forum<\/a>, so the credits go to him. I only briefly expose the solution here.<\/p>\n<p>First we need to create a custom interceptor for Spring MVC. This interceptor&#8217; job is to inject the security object and make it available to the template engine:<\/p>\n<pre class=\"brush: java; highlight: [21,23]; title: ; wrap-lines: false; notranslate\" title=\"\">\npublic class SecurityInterceptor extends HandlerInterceptorAdapter\n{\n\t@Override\n\tpublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception\n\t{\n\t\tif (modelAndView != null)\n\t\t{\n\t\t\tServletRequest req = (ServletRequest) request;\n\t\t\tServletResponse resp = (ServletResponse) response;\n\t\t\tFilterInvocation filterInvocation = new FilterInvocation(req, resp, new FilterChain()\n\t\t\t{\n\t\t\t\tpublic void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException\n\t\t\t\t{\n\t\t\t\t\tthrow new UnsupportedOperationException();\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tAuthentication authentication = SecurityContextHolder.getContext().getAuthentication();\n\t\t\tif (authentication != null)\n\t\t\t{\n\t\t\t\tWebSecurityExpressionRoot sec = new WebSecurityExpressionRoot(authentication, filterInvocation);\n\t\t\t\tsec.setTrustResolver(new AuthenticationTrustResolverImpl());\n\t\t\t\tmodelAndView.getModel().put(&amp;quot;sec&amp;quot;, sec);\n\t\t\t}\n\t\t}\n\t}\n}\n<\/pre>\n<p>Basically we just inject into the <strong>Model<\/strong> map a <strong>WebSecurityExpressionRoot<\/strong> variable called &#8220;<strong>sec<\/strong>&#8220;.<\/p>\n<p>Interceptor configuration for Spring MVC:<\/p>\n<pre class=\"brush: java; highlight: [6]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;bean id=&amp;quot;securityInterceptor&amp;quot; class=&amp;quot;doan.thymeleaf.demo.security.SecurityInterceptor&amp;quot;\/&amp;gt;\n\n&amp;lt;bean class=&amp;quot;org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping&amp;quot;&amp;gt;\n\t&amp;lt;property name=&amp;quot;interceptors&amp;quot;&amp;gt;\n\t\t&amp;lt;list&amp;gt;\n\t\t\t&amp;lt;ref bean=&amp;quot;securityInterceptor&amp;quot; \/&amp;gt;\n\t\t&amp;lt;\/list&amp;gt;\n\t&amp;lt;\/property&amp;gt;\n&amp;lt;\/bean&amp;gt;\n<\/pre>\n<p>Now in the template file we can access the &#8220;<strong>sec<\/strong>&#8221; variable:<\/p>\n<pre class=\"brush: java; highlight: [2,4]; title: ; wrap-lines: false; notranslate\" title=\"\">\n&amp;lt;div class=&amp;quot;span10 offset1&amp;quot;&amp;gt;\n\t&amp;lt;span class=&amp;quot;alert alert-success&amp;quot; th:text=&amp;quot;${'User login : '+sec.principal.username}&amp;quot;&amp;gt;User login : foo bar&amp;lt;\/span&amp;gt;\n\t&amp;lt;br\/&amp;gt;&amp;lt;br\/&amp;gt;\n\t&amp;lt;span class=&amp;quot;alert alert-success&amp;quot; th:text=&amp;quot;${'User authorities : '+ #strings.listJoin(sec.principal.authorities,',')}&amp;quot;&amp;gt;User authorities : simple user&amp;lt;\/span&amp;gt;\n&amp;lt;\/div&amp;gt;\n<\/pre>\n<p>That&#8217;s it folks!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post follows on from the previous post on Thymeleaf integration with Spring MVC. Today we&#8217;ll look at some advanced features of Thymeleaf<\/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\/895"}],"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=895"}],"version-history":[{"count":0,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/895\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=895"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=895"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=895"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}