📜 ⬆️ ⬇️

Thymeleaf Tutorial: Chapter 17. Shared Pattern Logic

Table of contents

17 Shared Template Logic


17.1. Shared Logic: Concept


Until now, we have worked in our Grocery Store with templates made in the usual way, with logic inserted into our templates as attributes.

But Thymeleaf also allows you to completely separate the template markup from the logic, allowing you to create completely logic-free markup templates in the modes of HTML and XML-templates.
')
The basic idea is that the template logic will be defined in a separate logical file (more precisely, a logical resource, since it does not have to be a file). By default, this logical resource will be an additional file located in the same place (for example, a folder) as a template file with the same name, but with the extension .th.xml:

/templates +->/home.html +->/home.th.xml 

Thus, the home.html file can be completely logical. It might look like this:

 <!DOCTYPE html> <html> <body> <table id="usersTable"> <tr> <td class="username">Jeremy Grapefruit</td> <td class="usertype">Normal User</td> </tr> <tr> <td class="username">Alice Watermelon</td> <td class="usertype">Administrator</td> </tr> </table> </body> </html> 

Absolutely no Thymeleaf code. This is a template file that a designer without Thymeleaf knowledge could create, edit and / or understand. Or HTML fragment provided by any external system without any Thymeleaf hooks.

Let's now turn this home.html template into a Thymeleaf template by creating an additional home.th.xml file as follows:

 <?xml version="1.0"?> <thlogic> <attr sel="#usersTable" th:remove="all-but-first"> <attr sel="/tr[0]" th:each="user : ${users}"> <attr sel="td.username" th:text="${user.name}" /> <attr sel="td.usertype" th:text="#{|user.type.${user.type}|}" /> </attr> </attr> </thlogic> 

Here we see a lot of <attr> tags inside the thlogic block. Those <attr> tags insert attributes on the nodes of the original template, selected using their sel attributes, which contain a Thymeleaf markup selector (actually AttoParser markup selectors ).

Also note that <attr> tags can be nested so that their selectors are added. For example, sel = "/ tr [0]" will be treated as sel = "# usersTable / tr [0]" . The selector for the username <td> will be processed as sel = "# usersTable / tr [0] // td.username" .

Therefore, as soon as they are merged, both files, seen above, will be like this:

 <!DOCTYPE html> <html> <body> <table id="usersTable" th:remove="all-but-first"> <tr th:each="user : ${users}"> <td class="username" th:text="${user.name}">Jeremy Grapefruit</td> <td class="usertype" th:text="#{|user.type.${user.type}|}">Normal User</td> </tr> <tr> <td class="username">Alice Watermelon</td> <td class="usertype">Administrator</td> </tr> </table> </body> </html> 

It looks more familiar and more convenient than creating two separate files. But the advantage of separated patterns is that we can provide our templates with complete independence from Thymeleaf and, therefore, better maintainability from a design point of view.

Of course, contracts between designers or developers will be required, for example, the fact that <table> users need id = "usersTable" , but in many scenarios a template with pure HTML will be a much better communication artifact between development teams and designers.

17.2 Configuring Split Templates


Including Split Templates

Split logic will not be expected for each default template. Instead, customized resolvers for templates (ITemplateResolver implementations) will have to specifically label patterns they find using split logic.

With the exception of StringTemplateResolver (which does not allow shared logic), all other ready-made versions of ITemplateResolver will provide a flag called useDecoupledLogic , which will mark all templates found by this resolver as potentially having all or part of their logic in a single resource:

 final ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext); templateResolver.setUseDecoupledLogic(true); 

Mixing Connected and Split Logic

Shared template logic is not a requirement. When enabled, this means that the engine will search for a resource containing shared logic, parsing and merging with the original template, if it exists. If there is no shared logical resource, the error will not be issued.

In addition, we can mix both connected and divided logic in the same template, for example, by adding some Thymeleaf attributes to the original template file, but leaving others for a separate shared logical file. The most common case for this is the use of the new ref attribute (in v3.0) th: ref .

17.3 th attribute: ref


th: ref is just a marker attribute. It does nothing from the point of view of processing and simply disappears when processing a template, but its usefulness is that it acts as a reference to markup, that is, it can be resolved by name from the markup selector just like the tag name or fragment ( th: fragment ).

Therefore, if we have a selector type:

 <attr sel="whatever" .../> 

This will correspond to:


What is the advantage of th: ref versus, for example, using the pure-HTML id attribute? Just the fact that we may not want to add so many id and class attributes to our tags in order to act as logical bindings that can eventually pollute our output.

And yet, what is the disadvantage of th: ref ? Obviously, we will add some Thymeleaf logic to our templates.

Note that the applicability of the th: ref attribute is not only applicable to shared logical pattern files: it works the same in other types of scripts, for example, in fragment expressions (~ {...}) .

17.4 Performance of Split Templates


The impact is very small. When the pattern found is flagged to use shared logic and it is not cached, the pattern logic will first be analyzed and processed as a sequence of instructions in memory: basically a list of attributes that will be inserted into each markup selector.

But this is the only additional step, because after that the real template will be analyzed, and while it is being analyzed, these attributes will be injected on the fly by the parser itself, thanks to the advanced features of node selection in AttoParser . Thus, the analyzed nodes will exit the analyzer as if they had entered attributes recorded in the source template file.

The biggest advantage of this? When the template is configured for caching, it will be cached, already containing the entered attributes. Thus, the overhead of using split templates for cached templates, as soon as they are cached, will be absolutely zero.

17.5. Split Logic Analysis


Thymeleaf finds shared logical resources corresponding to each pattern, and is user configurable. It is defined by the extension point, org.thymeleaf.templateparser.markup.decoupled.IDecoupledTemplateLogicResolver, for which the default implementation is provided: StandardDecoupledTemplateLogicResolver.

What does this standard implementation do?


The specific IDecoupledTemplateLogicResolver implementation you want to use can be easily configured in TemplateEngine:

 final StandardDecoupledTemplateLogicResolver decoupledresolver = new StandardDecoupledTemplateLogicResolver(); decoupledResolver.setPrefix("../viewlogic/"); ... templateEngine.setDecoupledTemplateLogicResolver(decoupledResolver); 

Source: https://habr.com/ru/post/352548/


All Articles