欢迎您的访问
专注于分享最有价值的互联网技术干货

十七、解耦的模板逻辑

几个T的资料等你来白嫖
双倍快乐

十七、解耦的模板逻辑

17.1 解耦逻辑:概念

到目前为止,我们已经为食品杂货店工作,模板以“通常的方式”完成,逻辑以属性的形式插入模板中。

但是 Thymeleaf 还允许我们将模板标记与其逻辑完全“解耦”,从而允许在HTMLXML模板模式下创建“完全无逻辑的标记模板”。

主要思想是,模板逻辑将在单独的 logic 文件(更确切地说是 logic 资源,因为它不一定是 file )中定义。默认情况下,该逻辑资源将是与模板文件位于同一位置(例如文件夹)的附加文件,其名称相同,但 extensions 为.th.xml

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

因此,home.html文件可以完全没有逻辑。它可能看起来像这样:

<!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>

那里绝对没有 Thymeleaf 代码。这是一个模板文件,没有 Thymeleaf 或模板知识的设计人员可以创建,编辑和/或理解。或某些外部系统完全没有 Thymeleaf 钩子提供的 HTML 片段。

现在,通过创建这样的其他home.th.xml文件,将home.html模板转换为 Thymeleaf 模板:

<?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>

在这里,我们可以看到thlogic块中有很多<attr>标签。那些<attr>标记通过其sel属性在原始模板的节点上执行属性注入,这些属性包含 Thymeleaf 标记 selectors(实际上 AttoParser 标记 selectors)。

另请注意,可以嵌套<attr>标签,以便其 selectors 被“附加”。例如,上面的sel="/tr[0]"将被处理为sel="#usersTable/tr[0]"。用户名<td>的 selectors 将被处理为sel="#usersTable/tr[0]//td.username"

因此,一旦合并,上面看到的两个文件将与以下内容相同:

<!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>

这看起来更熟悉,并且确实比创建两个单独的文件更“冗长”。但是,“解耦模板”的优点在于,我们可以使模板完全独立于 Thymeleaf,因此从设计的角度来看,具有更好的可维护性。

当然,仍然需要设计人员或开发人员之间的某些Contract –用户<table>将需要id="usersTable" –这一事实,但是在许多情况下,纯 HTML 模板将成为设计团队和开发团队之间更好的交流工件。

17.2 配置解耦的模板

启用解耦的模板

默认情况下,不会期望每个模板都具有解耦逻辑。取而代之的是,配置的模板解析器(ITemplateResolver的实现)将需要使用“解耦逻辑”将它们解析为的模板专门标记为*。

StringTemplateResolver(不允许解耦逻辑)外,所有其他其他现成的ITemplateResolver实现都将提供一个名为useDecoupledLogic的标志,该标志会将该解析器解析的所有模板标记为可能存在其全部或部分逻辑单独的资源:

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

混合耦合和解耦逻辑

启用后,去耦模板逻辑不是必需的。启用后,这意味着引擎将寻找包含解耦逻辑的资源,如果存在,则将其解析并与原始模板合并。如果解耦的逻辑资源不存在,则不会引发任何错误。

同样,在同一个模板中,我们可以将 coupled decoupled 逻辑混合使用,例如通过在原始模板文件中添加一些 Thymeleaf 属性,而将其他属性留给单独的 decoupled 逻辑文件。最常见的情况是使用新的(在 v3.0 中)th:ref属性。

17.3 th:ref 属性

th:ref只是标记属性。从处理的角度来看,它什么也没做,只是在处理模板时消失,但是它的作用在于它充当 markup reference 的事实,即可以像 一样通过 markupselectors的名称来解析它。标签名称片段*(th:fragment)。

因此,如果我们有一个 selectors,例如:

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

这将匹配:

  • 任何<whatever>个标记。
  • 具有th:fragment="whatever"属性的所有标签。
  • 具有th:ref="whatever"属性的所有标签。

th:ref相对于使用纯 HTML id属性有何优势?仅仅是我们可能不想在标签中添加太多idclass属性来充当逻辑锚,这最终可能污染我们的输出。

同样,th:ref的缺点是什么?好吧,显然,我们将在模板中添加一些 Thymeleaf 逻辑(“ logic” )。

请注意th:ref属性的这种适用性 不仅适用于解耦的逻辑模板文件 :它在其他类型的方案中也一样工作,例如在片段表达式(~{...})中。

17.4 解耦的模板对性能的影响

影响极小。当一个已解析的模板被标记为使用解耦逻辑并且不被缓存时,该模板逻辑资源将首先被解析,解析并处理为一系列内存中的指令:基本上是要注入到每个标记 selectors 的属性列表。

但这是唯一需要的“附加步骤”,因为在此之后,将解析实际模板,并且在解析这些模板时,这些属性将由解析器本身“即时”注入*,这要归功于 AttoParser 中的节点选择。因此,已解析的节点将从解析器中出来,就像它们的注入属性写在原始模板文件中一样。

这样最大的优势?将模板配置为要缓存时,它将缓存已包含注入属性的模板。因此,一旦缓存了模板,将解耦模板用于可缓存模板的开销将绝对为

17.5 解耦逻辑的解析

Thymeleaf 解析与每个模板相对应的解耦逻辑资源的方式可由用户配置。它由扩展点org.thymeleaf.templateparser.markup.decoupled.IDecoupledTemplateLogicResolver决定,为此提供了默认实现StandardDecoupledTemplateLogicResolver

该标准实现有什么作用?

  • 首先,它将prefixsuffix应用于模板资源的“基本名称”(通过ITemplateResource#getBaseName()方法获得)。前缀和后缀都可以配置,默认情况下,前缀为空,后缀为.th.xml
  • 其次,它要求模板资源通过其ITemplateResource#relative(String relativeLocation)方法解析具有所计算名称的“相对资源”。

可以在TemplateEngine上轻松配置要使用的IDecoupledTemplateLogicResolver的具体实现:

final StandardDecoupledTemplateLogicResolver decoupledresolver = 
        new StandardDecoupledTemplateLogicResolver();
decoupledResolver.setPrefix("../viewlogic/");
...
templateEngine.setDecoupledTemplateLogicResolver(decoupledResolver);
赞(0) 打赏
版权归原创作者所有,任何形式转载请联系我们:大白菜博客 » 十七、解耦的模板逻辑

评论 抢沙发

4 + 2 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏