Thymeleaf 教程手册

参考来源:Thymeleaf官方文档

消息

#{...}消息表达式允许我们链接:

<p th:utext="#{home.welcome}">Welcome to our grocery store!</p>

对此xxx.properties属性文件:

home.welcome=Bienvenido a nuestra tienda de comestibles!

如果消息文本不是完全静态会发生什么?例如,如果我们的应用程序知道谁是随时访问该网站的用户并且我们想要通过名字问候他们怎么办?

这意味着我们需要在消息中添加一个参数。像这样:

home.welcome=Bienvenido a nuestra tienda de comestibles, {0}!
<p th:utext="#{home.welcome(${session.user.name})}">
  Welcome to our grocery store, Sebastian Pepper!
</p>

请注意,使用th:utext此处意味着格式化的消息不会被转义。

可以指定几个参数,以逗号分隔。

最终输出:

<p>Bienvenido a nuestra tienda de comestibles, John Apricot!</p>

变量

${...}表达式实际上是在上下文中包含的变量映射上执行的OGNL(对象 - 图形导航语言)表达式。

使用示例:

<p>Today is: <span th:text="${today}">13 february 2011</span>.</p>

在spring boot Controller通过设置Model 的键值对赋值${today}

但是OGNL允许我们创建更强大的表达式,这就是:

<p th:utext="#{home.welcome(${session.user.name})}">
  Welcome to our grocery store, Sebastian Pepper!
</p>

模板引擎将通过执行以下命令获取用户名:

((User) ctx.getVariable("session").get("user")).getName();

但是getter方法导航只是OGNL的一个特性。让我们看看更多其他的特性:

/*
 * 使用点(.)访问属性。等价于调用属性getter。这是比较常用的方式
 */
${person.father.name}

/*
 * 还可以通过使用括号[]加单引号来访问属性。 
 */
${person['father']['name']}

/*
 * 如果对象是Map,则点和括号语法都等效于对其get(…)方法执行调用。
 */
${countriesByCode.ES}
${personsByName['Stephen Zucchini'].age}

/*
 * 通过下标访问数组或集合元素
 */
${personsArray[0].name}

/*
 * 方法可以调用,甚至可以传参数
 */
${person.createCompleteName()}
${person.createCompleteNameWithSeparator('-')}

表达式基本Expression Utility对象

在上下文变量中评估OGNL表达式时,某些对象可用于表达式以获得更高的灵活性。将以#符号开头引用这些对象(按照OGNL标准):

  • #ctx:上下文对象。
  • #vars: 上下文变量。
  • #locale:上下文区域设置。
  • #request:(仅限Web Contexts)HttpServletRequest对象。
  • #response:(仅限Web Contexts)HttpServletResponse对象。
  • #session:(仅限Web Contexts)HttpSession对象。
  • #servletContext:(仅限Web Contexts)ServletContext对象。
  • #execInfo:有关正在处理的模板的信息。
  • #messages:在变量表达式中获取外部化消息的方法,与使用#{…}语法获取的方法相同。
  • #uris:转义部分URL / URI的方法
  • #conversions:用于执行已配置的转换服务的方法(如果有)。
  • #datesjava.util.Date对象的方法:格式化,组件提取等。
  • #calendars:类似于#dates,但java.util.Calendar对象。
  • #numbers:格式化数字对象的方法。
  • #stringsString对象的方法:contains,startsWith,prepending / appending等。
  • #objects:一般的对象方法。
  • #bools:布尔评估的方法。
  • #arrays:数组的方法。
  • #lists:列表的方法。
  • #sets:集合的方法。
  • #maps:地图的方法。
  • #aggregates:在数组或集合上创建聚合的方法。
  • #ids:处理可能重复的id属性的方法(例如,作为迭代的结果)。

所以我们可以这样做:

Established locale country: <span th:text="${#locale.country}">US</span>.

选择表达式(星号语法)

变量表达式不仅可以写成${...},也可以作为*{...}

选定对象使用th:object属性。

  <div th:object="${session.user}">
    <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p>
    <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p>
    <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p>
  </div>

链接URL

@语法:@{...}

参看以下例子:

<!-- 实际的链接 'http://localhost:8080/gtvg/order/details?orderId=3'  -->
<a href="details.html" 
   th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a>

<!-- 实际的链接 '/gtvg/order/details?orderId=3' -->
<a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a>

<!-- 实际的链接 '/gtvg/order/3/details' -->
<a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>

注意:

  • 如果需要几个参数,这些参数将用逗号分隔: @{/order/process(execId=${execId},execType='FAST')}
  • URL路径中也允许使用变量: @{/order/{orderId}/details(orderId=${orderId})}
  • /(例如:)开头的相对URL /order/details将自动以应用程序上下文名称为前缀。

文字

<!-- 文本文字 -->
<span th:text="'working web application'">template file</span>.

<!--数字-->
<p>The year is <span th:text="2013">1492</span>.</p>
<p>In two years, it will be <span th:text="2013 + 2">1494</span>.</p>

<!--布尔文字-->
<div th:if="${user.isAdmin()} == false"> ...
<!--或者这样-->
<div th:if="${user.isAdmin() == false}"> ...
在这个例子中,它== false被写在大括号外面,因此Thymeleaf会照顾它。如果它是在大括号内写的,那么它将由OGNL / SpringEL引擎负责:

<!--null判断-->
<div th:if="${variable.something} == null"> ...

<!--无论是文字变量或消息表达式的结果,都可以使用+运算符轻松附加:-->
<span th:text="'The name of the user is ' + ${user.name}">
    
<!--一些算术运算也可用:+,-,*,/和%。-->
<div th:with="isEven=(${prodStat.count} % 2 == 0)">
请注意,这些运算符也可以应用于OGNL变量表达式本身(在这种情况下,将由OGNL而不是Thymeleaf标准表达式引擎执行):
<div th:with="isEven=${prodStat.count % 2 == 0}">
请注意,其中一些运算符存在文本别名:div(/),mod(%)。
    

字面替换

文字替换允许轻松格式化包含变量值的字符串,而无需附加文字'...' + '...'

这些替换必须用竖线(|)包围,如:

<span th:text="|Welcome to our application, ${user.name}!|">

这相当于:

<span th:text="'Welcome to our application, ' + ${user.name} + '!'">

文字替换可以与其他类型的表达相结合:

<span th:text="${onevar} + ' ' + |${twovar}, ${threevar}|">

属性赋值,通用方案(较少使用)

<form action="subscribe.html" th:attr="action=@{/subscribe}">
  <fieldset>
    <input type="text" name="email" />
    <input type="submit" value="Subscribe!" th:attr="value=#{subscribe.submit}"/>
  </fieldset>
</form>

th:attr="action=@{/subscribe}" 将设置action的属性值

th:attr="value=#{subscribe.submit} 将设置input 标签的value值

处理后的文件将是:

<form action="/gtvg/subscribe">
  <fieldset>
    <input type="text" name="email" />
    <input type="submit" value="¡Suscríbe!"/>
  </fieldset>
</form>

多个属性同时赋值,使用逗号分隔:

<img src="../../images/gtvglogo.png" 
     th:attr="src=@{/images/gtvglogo.png},title=#{logo},alt=#{logo}" />

为特定属性设置值(推荐使用)

例如,要设置value属性,请使用th:value

<input type="submit" value="Subscribe!" th:value="#{subscribe.submit}"/>

这看起来好多了!让我们尝试actionform标记中的属性执行相同的操作:

<form action="subscribe.html" th:action="@{/subscribe}">

你还记得th:href我们home.html以前放过的东西吗?它们正是同样的属性:

<li><a href="product/list.html" th:href="@{/product/list}">Product List</a></li>

更多特定属性,请参考:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#setting-attribute-values

迭代

控制器:

List<Product> allProducts = productService.findAll(); 
WebContext ctx = new WebContext(request, response, servletContext, request.getLocale());
ctx.setVariable("prods", allProducts);

模板:

<table>
    <tr th:each="prod : ${prods}">
        <td th:text="${prod.name}">Onions</td>
        <td th:text="${prod.price}">2.41</td>
        <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
    </tr>
</table>

迭代:保持迭代状态

使用时th:each,Thymeleaf提供了一种机制,可用于跟踪迭代的状态状态变量

状态变量在th:each属性中定义,包含以下数据:

  • 当前迭代索引,从0开始。这是index属性。
  • 当前迭代索引,从1开始。这是count属性。
  • 迭代变量中元素的总量。这是size酒店。
  • 每次迭代的iter变量。这是current酒店。
  • 当前迭代是偶数还是奇数。这些是even/odd布尔属性。
  • 当前迭代是否是第一个。这是first布尔属性。
  • 当前迭代是否是最后一次。这是last布尔属性。
<table>
  <tr>
    <th>NAME</th>
    <th>PRICE</th>
    <th>IN STOCK</th>
  </tr>
  <tr th:each="prod,stat : ${prods}" th:class="${stat.odd}? 'odd'">
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
  </tr>
</table>

如果您没有显式设置状态变量,Thymeleaf将始终通过后缀Stat为迭代变量的名称为您创建一个:

<table>
  <tr>
    <th>NAME</th>
    <th>PRICE</th>
    <th>IN STOCK</th>
  </tr>
  <tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
    <td th:text="${prod.name}">Onions</td>
    <td th:text="${prod.price}">2.41</td>
    <td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
  </tr>
</table>

简单条件:“if”和“非”

有时,如果满足某个条件,您将需要模板的片段才会出现在结果中。

<a href="comments.html"
   th:href="@{/product/comments(prodId=${prod.id})}" 
   th:if="${not #lists.isEmpty(prod.comments)}">
    view
</a>

switch语句

<div th:switch="${user.role}">
  <p th:case="'admin'">User is an administrator</p>
  <p th:case="#{roles.manager}">User is a manager</p>
</div>

请注意,只要一个th:casetrue上下文中的每个其他属性为false

默认选项指定为th:case="*"

<div th:switch="${user.role}">
  <p th:case="'admin'">User is an administrator</p>
  <p th:case="#{roles.manager}">User is a manager</p>
  <p th:case="*">User is some other thing</p>
</div>

模板布局、模板片段

在我们的模板中,我们经常需要包含其他模板中的部分,页脚,标题,菜单等部分…为了做到这一点,Thymeleaf需要我们定义这些部分,“片段”,以便包含,这可以使用th:fragment属性来完成。

定义片段:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <body>
    <div th:fragment="copy">
      &copy; 2011 The Good Thymes Virtual Grocery
    </div>
  </body>
</html>

使用片段:

上面的代码定义了一个名为的片段copy,我们可以使用其中一个th:insertth:replace属性轻松地在我们的主页中包含这些片段(或者使用th:include,尽管自Thymeleaf 3.0以来不再推荐使用它):

<body>
  ...
  <div th:insert="~{footer :: copy}"></div>
</body>

请注意,th:insert~{})封闭是完全可选的,所以上面的代码相当于:

<body>
  ...
  <div th:insert="footer :: copy"></div>
</body>

片段规范语法

  • "~{templatename::selector}" 引入指定模板文件中的某个片段
  • "~{templatename}"引入一个完整的模板文件
  • ~{::selector}""~{this::selector}"插入来自同一模板的片段

th:insertth:replace(和th:include)之间的区别

HTML片段:

<footer th:fragment="copy">
  &copy; 2011 The Good Thymes Virtual Grocery
</footer>

在主机<div>标签中包含三次,如下所示:

<body>

  ...

  <div th:insert="footer :: copy"></div>

  <div th:replace="footer :: copy"></div>

  <div th:include="footer :: copy"></div>
  
</body>

…将导致:

<body>
  ...
  <div>
    <footer>
      &copy; 2011 The Good Thymes Virtual Grocery
    </footer>
  </div>

  <footer>
    &copy; 2011 The Good Thymes Virtual Grocery
  </footer>

  <div>
    &copy; 2011 The Good Thymes Virtual Grocery
  </div>
  
</body>

片段传参

片段参数化

<div th:fragment="frag (onevar,twovar)">
    <p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>

调用片段,可通过th:insertth:replace调用片段:

<div th:replace="::frag (${value1},${value2})">...</div>
<div th:replace="::frag (onevar=${value1},twovar=${value2})">...</div>

局部变量 th:with

声明赋值局部变量:

<div th:with="firstPer=${persons[0]}">
  <p>
    The name of the first person is <span th:text="${firstPer.name}">Julius Caesar</span>.
  </p>
</div>

firstPer 的变量作用范围只在

标记包含的范围内。

多重赋值:

<div th:with="firstPer=${persons[0]},secondPer=${persons[1]}">
  <p>
    The name of the first person is <span th:text="${firstPer.name}">Julius Caesar</span>.
  </p>
  <p>
    But the name of the second person is 
    <span th:text="${secondPer.name}">Marcus Antonius</span>.
  </p>
</div>

注释的使用

普通注释正常使用:

<!-- User info follows -->
<div th:text="${...}">
  ...
</div>

Thymeleaf将删除一切在<!--/**/-->之间的内容

<!--/*--> 
  <div>
     你只能在thymeleaf解析前看到我!
  </div>
<!--*/-->

容器标签 th:block

th:block是一个纯粹的属性容器,允许模板开发人员指定他们想要的任何属性,然后简单地使块,不会解析成上下文,是消失的标签。

因此,在创建<tr>每个元素需要多个迭代表时,它可能很有用:

<table>
  <th:block th:each="user : ${users}">
    <tr>
        <td th:text="${user.login}">...</td>
        <td th:text="${user.name}">...</td>
    </tr>
    <tr>
        <td colspan="2" th:text="${user.address}">...</td>
    </tr>
  </th:block>
</table>

内联表达式

虽然标准方言允许我们使用标记属性来完成几乎所有操作,但在某些情况下我们可能更喜欢将表达式直接编写到HTML文本中。例如,我们可能更喜欢这样写:

msg = 'This is <b>great!</b>'

使用[(...)]

<p>The message is "[(${msg})]"</p>

结果是<b>标签不转义,因此:

<p>The message is "This is <b>great!</b>"</p>

使用[[...]]

<p>The message is "[[${msg}]]"</p>

结果将被HTML转义:

<p>The message is "This is &lt;b&gt;great!&lt;/b&gt;"</p>

注意:

[[...]]对应于th:text即结果将被HTML转义

[(...)]对应于th:utext并且不会执行任何HTML转义。

内联 对比 自然模板

你可能会问:为什么我们从一开始就不这样做?它的代码少于所有这些 th:text 属性!

好吧,小心那里,因为尽管你可能会发现内联非常有趣,但是你应该永远记住,当你静态打开它们时,内联表达式将逐字显示在你的HTML文件中,所以你可能无法将它们用作设计原型了!

所以自然模板是比较适合于查看原型设计原型的时候

附录:

获取url的参数值: 如http://localhost/test?foo=123
${#request.getParameter('foo')}
详情参考:

https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#appendix-a-expression-basic-objects

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值