Thymeleaf: Custom Layout Dialect – Thymeleaf:自定义布局方言

最后修改: 2016年 10月 13日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

Thymeleaf is a Java template engine for processing and creating HTML, XML, JavaScript, CSS and plain text. For an intro to Thymeleaf and Spring, have a look at this write-up.

Thymeleaf是一个Java模板引擎,用于处理和创建HTML、XML、JavaScript、CSS和纯文本。关于Thymeleaf和Spring的介绍,请看本篇文章

In this write-up, we’ll focus on templating – something that most reasonably complex sites need to do one way or another. Simply put, pages need to share common page components like the header, footer, menu and potentially much more.

在这篇文章中,我们将重点讨论模板化问题–大多数合理复杂的网站都需要以这种或那种方式进行模板化。简单地说,页面需要共享共同的页面组件,如页眉、页脚、菜单和可能的更多。

Thymeleaf addresses that with custom dialects – you can build layouts using the Thymeleaf Standard Layout System or the Layout Dialect – which uses the decorator pattern for working with the layout files.

Thymeleaf通过自定义方言解决了这个问题–你可以使用Thymeleaf标准布局系统布局方言构建布局–它使用装饰器模式来处理布局文件。

In this article, we’ll discuss a handful of features of Thymeleaf Layout Dialect – which can be found here. To be more specific, we will discuss its features like creating layouts, custom titles or head element merging.

在这篇文章中,我们将讨论Thymeleaf Layout Dialect的少数功能–它可以在这里找到。更具体地说,我们将讨论其功能,如创建布局、自定义标题或头部元素合并。

2. Maven Dependencies

2.Maven的依赖性

First, let’s see the required configuration needed to integrate Thymeleaf with Spring. The thymeleaf-spring library is required in our dependencies:

首先,让我们看看将Thymeleaf与Spring集成所需的配置。在我们的依赖中需要thymeleaf-spring库。

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.11.RELEASE</version>
</dependency>

Note that, for a Spring 4 project, the thymeleaf-spring4 library must be used instead of thymeleaf-spring5. The latest version of the dependencies may be found here.

请注意,对于Spring 4项目,必须使用thymeleaf-spring4库而不是thymeleaf-spring5。最新版本的依赖项可以在这里找到。

We’ll also need a dependency for custom layouts dialect:

我们还需要一个自定义布局方言的依赖项。

<dependency>
    <groupId>nz.net.ultraq.thymeleaf</groupId>
    <artifactId>thymeleaf-layout-dialect</artifactId>
    <version>2.4.1</version>
</dependency>

The latest version can be found at the Maven Central Repository.

最新版本可在Maven中央仓库找到。

3. Thymeleaf Layout Dialect Configuration

3.Thymeleaf布局方言配置

In this section, we will discuss how to configure Thymeleaf to use Layout Dialect. If you want to take a step back and see how to configure Thymeleaf 3.0 in your web app project, please check this tutorial.

在本节中,我们将讨论如何配置Thymeleaf以使用Layout Dialect。如果您想回头看看如何在您的Web应用项目中配置Thymeleaf 3.0,请查看这个教程

Once we add Maven dependency as a part of a project, we’ll need to add the Layout Dialect to our existing Thymeleaf template engine. We can do this with Java configuration:

一旦我们将Maven依赖作为项目的一部分,我们就需要将Layout Dialect添加到我们现有的Thymeleaf模板引擎。我们可以用Java配置来完成这个任务。

SpringTemplateEngine engine = new SpringTemplateEngine();
engine.addDialect(new LayoutDialect());

Or by using XML file config:

或者通过使用XML文件配置。

<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
    <property name="additionalDialects">
        <set>
            <bean class="nz.net.ultraq.thymeleaf.LayoutDialect"/>
        </set>
    </property>
</bean>

When decorating the sections of the content and layout templates, the default behaviour is to place all content elements after the layout ones.

当装饰内容和布局模板的部分时,默认行为是将所有内容元素放在布局元素之后。

Sometimes we need a smarter merging of elements, allowing to group similar elements together (js scripts together, stylesheets together etc.).

有时,我们需要一个更智能的元素合并,允许将类似的元素组合在一起(js脚本在一起,样式表在一起等等)。

To achieve that, we need to add sorting strategy to our configuration – in our case, it will be the grouping strategy:

为了实现这一点,我们需要在我们的配置中添加排序策略–在我们的案例中,它将是分组策略。

engine.addDialect(new LayoutDialect(new GroupingStrategy()));

or in XML:

或在XML中。

<bean class="nz.net.ultraq.thymeleaf.LayoutDialect">
    <constructor-arg ref="groupingStrategy"/>
</bean>

The default strategy is to append elements. With above-mentioned, we will have everything sorted and grouped.

默认策略是追加元素。通过上述方法,我们将对所有东西进行分类和分组。

If neither strategy suits our needs, we can implement our own SortingStrategy and pass it along to the dialect like above.

如果这两种策略都不适合我们的需要,我们可以实现我们自己的SortingStrategy,并像上面那样把它传递给方言。

4. Namespace and Attribute Processors’ Features

4.名称空间和属性处理器的特点

Once, configured we can start using layout namespace, and five new attribute processors: decorate, title-pattern, insert, replace, and fragment.

一旦配置好,我们就可以开始使用layout命名空间,以及五个新的属性处理器。decorate, title-pattern, insert, replace, 和fragment。

In order to create the layout template that we want to use for our HTML files, we created the following file, named template.html:

为了创建我们想用于HTML文件的布局模板,我们创建了以下文件,名为template.html

<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
...
</html>

As we can see, we changed the namespace from the standard xmlns:th=”http://www.thymeleaf.org” to xmlns:layout=”http://www.ultraq.net.nz/thymeleaf/layout”.

我们可以看到,我们把命名空间从标准的xmlns:th=”http://www.thymeleaf.org”改为xmlns:layout=”http://www.ultraq.net.nz/thymeleaf/layout”

Now we can start working with attribute processors in our HTML files.

现在我们可以开始在我们的HTML文件中使用属性处理器了。

4.1. layout:fragment

4.1. layout:fragment

In order to create custom sections in our layout or reusable templates that can be replaced by sections which share the same name, we use fragment attribute inside our template.html body:

为了在我们的布局中创建自定义部分或可重复使用的模板,可以由共享相同名称的部分取代,我们在template.html体内使用fragment属性。

<body>
    <header>
        <h1>New dialect example</h1>
    </header>
    <section layout:fragment="custom-content">
        <p>Your page content goes here</p>
    </section>
    <footer>
        <p>My custom footer</p>
        <p layout:fragment="custom-footer">Your custom footer here</p>
    </footer>
</body>

Notice that there are two sections that will be replaced by our custom HTML – content and footer.

注意,有两个部分将被我们的自定义HTML所取代–内容和页脚。

It’s also important to write the default HTML that’s going to be used if any of the fragments will not be found.

编写默认的HTML也很重要,如果任何一个片段都找不到的话,就会使用这个片段。

4.2. layout:decorate

4.2.layout:decorate

Next step that we need to make is to create an HTML file, that will be decorated by our layout:

我们需要做的下一步是创建一个HTML文件,它将被我们的布局所装饰。

<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
  layout:decorate="~{template.html}">
<head>
<title>Layout Dialect Example</title>
</head>
<body>
    <section layout:fragment="custom-content">
        <p>This is a custom content that you can provide</p>
    </section>
    <footer>
        <p layout:fragment="custom-footer">This is some footer content
          that you can change</p>
    </footer>
</body>
</html>

As it is shown in the 3rd line, we use layout:decorate and specify the decorator source. All fragments from the layout file that match fragments in a content file will be replaced by its custom implementation.

如第三行所示,我们使用layout:decorate 并指定装饰器的来源。布局文件中所有与内容文件中的片段相匹配的片段将被其自定义实现所取代。

4.3. layout:title-pattern

4.3.layout:title-pattern

Given that the Layout dialect automatically overrides the layout’s title with the one that is found in the content template, you might preserve parts of the title found in the layout.

鉴于布局方言会自动用内容模板中的标题覆盖布局的标题,你可能会保留布局中的部分标题。

For example, we can create breadcrumbs or retain the name of the website in the page title. The layout:title-pattern processor comes with help in such a case. All you need to specify in your layout file is:

例如,我们可以创建面包屑或在页面标题中保留网站的名称。在这种情况下,layout:title-pattern处理器会带来帮助。你所需要在你的布局文件中指定的就是。

<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Baeldung</title>

So the final result for the layout and content file presented in the previous paragraph will look like this:

因此,上一段中介绍的布局和内容文件的最终结果将是这样的。

<title>Baeldung - Layout Dialect Example</title>

4.4. layout:insert/layout:replace

4.4.layout:insert/layout:replace

The first processor, layout:insert, is similar to Thymeleaf’s original th:insert, but allows to pass the entire HTML fragments to the inserted template. It is very useful if you have some HTML that you want to reuse, but whose contents are too complex to determine or construct with context variables alone.

第一个处理器,layout:insert,类似于Thymeleaf最初的th:insert,但允许将整个HTML片段传递给插入的模板。如果你有一些想重用的HTML,但其内容太复杂,无法单独用上下文变量来确定或构建,那么它就非常有用。

The second one, layout:replace, is similar to the first one, but with the behaviour of th:replace, which will actually substitute the host tag by the defined fragment’s code.

第二个,layout:replace,与第一个类似,但有th:replace的行为,它实际上将用定义的片段的代码替换主机标签。

5. Conclusion

5.结论

In this article, we described a few ways of implementing layouts in Thymeleaf.

在这篇文章中,我们描述了在Thymeleaf中实现布局的几种方法。

Note that the examples use the Thymeleaf version 3.0; if you want to learn how to migrate your project, please follow this procedure.

请注意,这些例子使用的是Thymeleaf 3.0版本;如果你想学习如何迁移你的项目,请按照这个程序进行操作。

The full implementation of this tutorial can be found in the GitHub project.

本教程的完整实现可以在GitHub项目中找到。

How to test? Our suggestion is to play with a browser first, then check the existing JUnit tests as well.

如何测试?我们的建议是先用浏览器玩一玩,然后也检查一下现有的JUnit测试。

Remember, you can build layouts using above-mentioned Layout Dialect or you can easily create your own solution. Hopefully, this article gives you some more insights on the topic and you will find your preferred approach depending on your needs.

记住,你可以使用上面提到的Layout Dialect构建布局,或者你可以轻松地创建自己的解决方案。希望这篇文章能让你对这个话题有更多的了解,你会根据自己的需要找到自己喜欢的方法。