Thymeleaf模板复习

Thymeleaf学习

三大模板

  1. jsp

  2. html thymeleaf

  3. tld freemarker

面试题: 什么是模板,为什么使用thymeleaf模板?

第一,Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。

这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。

第二,Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、该jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。

第三,Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。

跟以前的技术做对比

image-20220728223633173

Th:xxx 覆盖原有属性

Th:text/th:utext 显示文本 行内 [[{})]

Th:each

${} 取值

~{} 代码段

@{} 相对于项目的绝对路径

 

第一章 模板引擎-简介和比较

1.1 Spring Boot提供了大量模板引擎技术

包含FreeMarker,Groovy,Thymeleaf,Velocity和Mustache,Spring Boot中推荐使用Thymeleaf作为模板引擎.因为Thymeleaf提供了完美的SpringMVC支持.

Thymeleaf是一个java类库,他是一个xml/xhtml/html5的模板引擎,可以作为mvc的web应用的view层。

1.2 Thymeleaf还提供了额外的模块与Spring MVC集成

所以我们可以使用Thymeleaf完全替代jsp。

spring Boot通过org.springframework.boot.autoconfigure.thymeleaf包对Thymeleaf进行了自动配置。

通过ThymeleafAutoConfiguration类对集成所需要的bean进行自动配置。

包括templateResolver,templateEngine,thymeleafViewResolver的配置。

img

1.3 模板引擎-简介和比较

img

1.4 模板引擎

JSP、Velocity、Freemarker、Thymeleaf

img

SpringBoot推荐的Thymeleaf;语法更简单,功能更强大;

 

第二章 Thymeleaf使用

2.1 Thymeleaf使用

org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration

ThymeleafViewResolver

org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties

  @ConfigurationProperties(prefix = "spring.thymeleaf")
  public class ThymeleafProperties {
  private static final Charset DEFAULT_ENCODING = Charset.forName("UTF‐8");
  private static final MimeType DEFAULT_CONTENT_TYPE = MimeType.valueOf("text/html");
  public static final String DEFAULT_PREFIX = "classpath:/templates/";
  public static final String DEFAULT_SUFFIX = ".html";
 
  }

只要我们把HTML页面放在classpath:/templates/thymeleaf就能自动渲染

导入thymeleaf的名称空间

  <html lang="en" xmlns:th="http://www.thymeleaf.org">

使用thymeleaf语法

  <!DOCTYPE html>
  <html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
  <meta charset="UTF‐8">
  <title>Title</title>
  </head>
  <body>
  <h1>成功!</h1>
  <!‐‐th:text 将div里面的文本内容设置为 ‐‐>
  <div th:text="${hello}">这是显示欢迎信息</div>
  </body>
  </html>

语法规则

th:text;改变当前元素里面的文本内容

th:任意html属性;来替换原生属性的值

  map.put("hello","<h1>你好</h1>");
  map.put("users",Arrays.asList("zhangsan","lisi","wangwu"));
 
  <!--th:text 将div里面的文本内容设置为 -->
  <div id="div01" class="myDiv" th:id="${hello}" th:class="${hello}" th:text="${hello}">这是显示欢迎信息</div>
  <hr/>
  <div th:text="${hello}"></div> <!--转译特殊字符,特殊符号原方不动输出-->
  <div th:utext="${hello}"></div> <!--会转译字符,特殊符号被转译后输出结果-->
  <hr/>
   
  <!-- th:each每次遍历都会生成当前这个标签: 3个h4 -->
  <h4 th:text="${user}" th:each="user:${users}"></h4>
  <hr/>
  <h4>
      <span th:each="user:${users}"> [[${user}]] </span> <!--inlning 行内写法 [[]]等价于th:text     [()]等价于th:utext-->
  </h4>

th:text ------> [[${...}]]

th:utext -------> [(${...})]

  <html xmlns:th="http://www.thymeleaf.org">
  <link th:href="@{/bootstrap/css/bootstrap.min.css}" rel="stylesheet" />
  <span th:text="${singlePerson.name}">姓名</span>
  <li class="list-group-item" th:each="person:${people}"></li>
  <script th:src="@{bootstrap/js/bootstrap.min.js}"></script>
  <script th:inline="javascript">
      var single=[[${singlePerson}]];
      console.log(single.name+"/"+single.age);
  </script>

 

第三章 Thymeleaf-语法

3.1 使用 th:text

3.1.1 外部文本(消息)(了解就好,ali开发几十年才走向国际)

 

Welcome Message

 

外部文本的概念: 外部文本抽取模板代码片段到模板文件外面, 使外部文本可以存在另一个文件中(比如 properties 文件). 通常把外部文本叫做消息(messages).

Thymeleaf 通过 #{...} 语法来使用消息.

在 springmvc 中使用消息要额外配置 ResourceBundleMessageSource 这个 bean:

   // 用于外部文本及国际化消息
      @Bean
      public ResourceBundleMessageSource messageSource() {
          ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
          messageSource.setBasename("messages");
          return messageSource;
    }

这个 bean 会去 classpath 根目录下去寻找 messages 为基名的 properties 文件.

比如,messages.properties, messages_en_US.properties, messages_zh_CN.properties.

th:text 外部文本会替换 p 标签内的内容.

3.1.2 使消息不转换 html 标签

如果我们在 messages.properites 中这么写: index.welcome=Welcome to SpringMVC

那么 thymeleaf 会转成 <p>Welcome to SpringMVC</p> 这显然不是我们想要的. 这时候就可以用 th:utext(for “unescaped text)

3.1.3 使用并显示变量

变量概念: 存在 java web 上下文中的变量. 比如 request, session, application, page ...

${...} 语法可以用来显示变量. 花括号内使用的是 ognl 表达式语言.

springmvc 中用 spel 语言代替 ognl 语言.

3.2 标准表达式语法

  • 变量表达式: ${...}

    • 选择变量表达式: *{...}

    • 消息表达式: #{...}

    • URL 表达式: @{...}

    • 代码段表达式: ~{...}

  • 字面量

    • 文本字面量: 'some text'

    • 数值字面量: 0, 34, 3.0, 12.3

    • 布尔值字面量: true, false

    • Null 值字面量: null

    • Tokens 字面量: one, content, sometext, ...

image-20220728225319415

3.3 消息

消息中也可以包含变量, 比如在 index.welcome 中, 想打印出时间:# 在 messages.properties 文件中用 {0}, {1}, {2}, ... 占位符

index.welcome=Welcome to SpringMVC, time is: {0}

那么在 index.html 模板文件中就可以这样写:<p th: utext="#{index.welcome(${date})}">Welcome message</p>

其中 ${date} 就像一个参数那样被传进去了.

3.4 变量

3.4.1变量表达式 ${...}

用的是 ognl(对象图导航语言). 在 springmvc 中用 spel(spring 表达式语言)代替. 其实两者在大部分情况下用法是相同的.

下面看几个例子就知道变量表达式的大部分用法了.

  <!-- springmvc 保存了一个 model 对象: departments -->
  <!-- 获取所有 departments -->
  <p th:text="${departments}"></p>
  <!-- 获取 departments 的第一个元素 -->
  <p th:text="${departments[0]}"></p>
  <!-- 获取第一个 department 对象的 name 属性 -->
  <p th:text="${departments[0].name}"></p>
  <!-- 也可以用 ['name'] 来获取第一个 department 对象的 name 属性 -->
  <p th:text="${departments[0]['name']}"></p>
  <!-- 甚至可以调用方法! -->
  <p th:text="${departments[0].getId()}"></p>
  <p th:text="${departments[0]['name'].substring(0, 1)}"></p>

3.4.2内置基本对象

加#号 取的是原生的servletAPI

不加# 取的是thymeleaf包装的API

下面是一些内置的基本对象, 可以用 # 符号直接使用

  ctx: the context object.
  vars: the context variables.
  locale: the context locale.
  request: (only in Web Contexts) the HttpServletRequest object.
  response: (only in Web Contexts) the HttpServletResponse object.
  session: (only in Web Contexts) the HttpSession object.
  servletContext: (only in Web Contexts) the ServletContext object.

使用例子:

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

3. 4.3 内置工具对象

统统加#才能取到

除了基本对象, thymeleaf 还提供了一组工具对象.

execInfo: information about the template being processed.
messages: methods for obtaining externalized messages inside variables expressions, in the same way as they would be obtained using #{…} syntax.
uris: methods for escaping parts of URLs/URIs
conversions: methods for executing the configured conversion service (if any).
dates: methods for java.util.Date objects: formatting, component extraction, etc.
calendars: analogous to #dates, but for java.util.Calendar objects.
numbers: methods for formatting numeric objects.
strings: methods for String objects: contains, startsWith, prepending/appending, etc.
objects: methods for objects in general.
bools: methods for boolean evaluation.
arrays: methods for arrays.
lists: methods for lists.
sets: methods for sets.
maps: methods for maps.
aggregates: methods for creating aggregates on arrays or collections.
ids: methods for dealing with id attributes that might be repeated (for example, as a result of an iteration).

例子, 格式化时间:

<!-- 时间格式化 -->

time:<span th:text="${#dates.format(date, 'yyyy-MM-dd HH:mm:ss')}"></span><br>

4. 选择变量表达式

获取变量可以使用 ${...} 语法外, 还可以使用 {...}, 称为选择变量表达式***.

选择变量表达式与变量表达式的不同之处在于, 如果前面有一个选择对象了, 那么用它获取这个选择对象的属性或方法时, 可以不写对象名.

那么选择对象的概念是什么呢? 选择对象是用 th:object 表示的对象.

看例子:

<p>选择变量表达式</p>
<div th:object="${departments[1]}">
    <p th:text="*{id}"></p>
    <p th:text="*{name}"></p>
</div>
<p>等价的变量表达式</p>
<div>
    <p th:text="${departments[1].id}"></p>
    <!-- 如果没有 "选择对象", 那么 * 和 $ 是等价的 -->
    <p th:text="*{departments[1].name}"></p>
</div>

如果存在选择对象了, 那么在 ${...} 中也可以用 #object 来使用选择对象.

<p>${...} 中使用 #object 引用 "选择对象"</p>
<div th:object="document[2]">
    <!-- 以下三种方式在这种情况下是等价的 -->
    <p th:text="${#object.id}"></p>
    <p th:text="*{id}"></p>
    <p th:text="${document[2].id}"></p>
</div>

5. Link URL 表达式

链接 URL 表达式语法是 @{...}

有不同类型的 URLs:

绝对路径 URLs: http://localhost:8888/demo/index

相对路径 URLs:

页面相对: user/login.html

上下文相对: /employee/emps 注意用 / 打头, 会自动把上下文路径(比如 http://localhost:8888/demo) 路径加上去.

服务器相对(不重要)

协议相对(不重要)

例子:

<!-- Common styles and scripts -->
<link rel="stylesheet" type="text/css" media="all" th:href="@{/assets/css/base.css}">
<script type="text/javascript" th:src="@{/assets/ext/jquery-3.1.1-min.js}"></script>
<script type="text/javascript" th:src="@{/assets/js/codergege.js}"></script>
<!-- ... -->
<a href="#" th:href="@{/}">返回首页</a> <br>
<a href="#" th:href="@{/thymeleaf/demo1}">去 demo1 页面</a> <br>
<!-- 会生成 url: http://localhost:8888/demo/thymeleaf/demo1?username=tom -->
<a href="#" th:href="@{/thymeleaf/demo1(username=${employees[0].name})}">去 demo1 页面, 带参数</a> <br>
<!-- 会生成 url: http://localhost:8888/demo/thymeleaf/demo1/2 RESTful 风格的 url -->
<a href="#" th:href="@{/thymeleaf/demo1/{empId}(empId=${employees[1].id})}">去 demo1 页面, 带 RESTful 风格参数</a> <br>

中文会自动转码; 如果有多个参数,用逗号隔开.

image-20220729094237976

restful

image-20220729094452149

6代码段(fragment)

语法: ~{...}

最常见的用法是与 th:insert 或 th:replace 配合使用. 例如:

<!-- ~{...} 可以省略不写 -->
<header id="header" th:replace="fragment :: header"></header>
<footer id="footer" th:replace="~{fragment :: footer}"></footer>

image-20220729100447920

image-20220729100542268

这就是三者区别

<!--替换掉外层的div元素-->
<div th:replace="~{common::foot}"></div>
<!--在外层div中直接插入代码段-->
<div th:insert="~{common::foot}"></div>
<!--只包含代码段的文本-->
<div th:include="~{common::foot}"></div>

7.字面量

image-20220729101009584

image-20220729101025132

image-20220729101041299

8. 连接字符串

文本, 不管是文本字面量还是通过 ognl/spel 计算出来的文本, 都能用 + 操作符连接.

<span th:text="'Some literal text and ' + ${departments[0].name}"></span>

image-20220729101340932

9. 条件表达式与默认表达式

条件表达式由 3 个部分组成,

condition, then, else. 每个部分自身又是一个表达式, 即它们分别可以用变量(${...}, *{...}), 消息(#{...}), URLs(@{...}), 字面量等来表示.

 <!-- else 部分可以省略, 这种情况下, 如果条件为 false, null 值会被返回 -->
 <p th:class="${employees[0].id % 2 == 0}? 'even'" th:text="${employees[0].name}"></p>
 <p th:class="${employees[1].id % 2 == 0}? 'even': 'odd'" th:text="${employees[1].name}"></p>
 <p th:class="${employees[2].id % 2 == 0}? 'even': 'odd'" th:text="${employees[2].name}"></p>
 <!-- ?: 默认表达式 -->
 <span th:text="${employees[0].getGender()}?: '没有指定性别'"></span> <br>
 <span th:text="${employees[2].getEmail()}?: '没有指定邮箱'"></span> <br>
 <!-- 可以嵌套混合, 嵌套的话用 () 包起来 -->
 <span th:text="(${employees[0].getGender()} == 1 ? '男': '女')?: '没有指定性别'"></span>

10. No-Op 操作符(_)

 No-Op 操作符指明期待的表达式结果不做任何事情. 比如说 th:text 中最后计算结果是 _,那么 th:text 元素根本就不会生成.
 <p th:text="_">这里的内容不会被 th:text 替换</p>
 <p th:text="${employees[0].email}?: _">没有指定电子邮箱</p>

11.数据转换与格式化

Thymeleaf 的变量表达式(${...}, *{...})使用 {{...}} 来表示需要进行转换. 允许我们使用自定义的数据转换服务来转换表达式返回结果.

使用 thymeleaf-spring3 和 thymeleaf-spring4 的话, 会自动调用 spring 的 ConversionService.

12.预处理表达式

用双下划线 ... 包裹普通的表达式就可以.

3.5设置属性值

本章学习 thymeleaf 如何设置或修改 html 元素属性.

3.5.1 设置任意属性 th:attr

可以用 th:attr 来设置任意属性.

 <!-- 替换 action 属性 -->
 <form action="#" th:attr="action=@{/suscribe}" >
     <input type="text" name="name">
     <input type="text" name="gender">
     <input type="text" name="birthday">
     <input type="text" name="email">
     <!-- todo select departments -->
     <!-- 一次替换多个属性值 1) submit 按钮的 value 属性; 2) class 属性 -->
     <input type="submit" value="Submit" th:attr="value=#{form.submit}, class='sep'">
 </form>

3.5.2 设置指定属性

一般 th:attr 很少会用到, 而是会直接使用指定的 th:*.

比如已经用过的 th:href, th:text, th:value, th:action ...

几乎所有的 html 元素属性都有对应的 th:* 版本.

image-20220729102257809

3.6 迭代

3.6.1 迭代初步

使用 th:each

 <ul>
     <li>
         <span class="list">编号</span>
         <span class="list">姓名</span>
         <span class="list">性别</span>
         <span class="list">生日</span>
         <span class="list">部门</span>
         <span class="list">编辑</span>
         <span class="list">删除</span>
     </li>
     <li th:each="emp : ${employees}">
         <span class="list" th:text="${emp.id}"></span>
         <span class="list" th:text="${emp.name}"></span>
         <span class="list" th:text="${emp.gender == 1} ? '男': '女'"></span>
         <span class="list" th:text="${{emp.birthday}}"></span>
         <span class="list" th:text="${emp.department.name}"></span>
         <span class="list"><a href="#">编辑</a></span>
         <span class="list"><a href="#">删除</a></span>
     </li>
 </ul>

th:each 用起来很方便, 就像 java 中的 for 循环一样.

 for(Employee emp: employees) {
 
   // Do something
 
 }

在 thymeleaf 中使用迭代太方便了! 回想 jstl 那些坑爹的标签, 泪都留下来...

可以用 th:each 迭代的 java 类型

th:each 不仅仅可以对 java.util.List 类型迭代, 实际上大部分的 java 集合类型都可以使用它来迭代.

实现了 java.util.Iterable 接口的对象

实现了 java.util.Enumeration 接口的对象

实现了 java.util.Iterator 接口的对象, 不会一次性读入内存, 返回一个读一个.

实现了 java.util.Map 接口的对象, 这时候迭代的值是 java.util.Map.Entry.

任何数组

3.6.2 保存迭代状态

th:each 还提供了一个变量可以保存迭代状态. 用法是 th:each="emp, status: ${employees}"

状态变量保存了以下数据:

*index* 属性, 0 开始的索引值

*count* 属性, 1 开始的索引值

*size* 属性, 集合内元素的总量

*current* 属性, 当前的迭代对象

*even/odd* 属性, boolean 类型的, 用来判断是否是偶数个还是奇数个

*first* 属性, boolean 类型, 是否是第一个

*last* 属性, boolean 类型, 是否是最后一个

看例子:

 <ul>
     <li>
         <span class="list">编号</span>
         <span class="list">姓名</span>
         <span class="list">性别</span>
         <span class="list">生日</span>
         <span class="list">部门</span>
         <span class="list">编辑</span>
         <span class="list">删除</span>
         <span class="list status">当前迭代状态</span>
     </li>
     <li th:each="emp, status: ${employees}" th:class="${status.odd} ? 'odd': 'even'">
         <span class="list" th:text="${emp.id}"></span>
         <span class="list" th:text="${emp.name}"></span>
         <span class="list" th:text="${emp.gender == 1} ? '男': '女'"></span>
         <span class="list" th:text="${{emp.birthday}}"></span>
         <span class="list" th:text="${emp.department.name}"></span>
         <span class="list"><a href="#">编辑</a></span>
         <span class="list"><a href="#">删除</a></span>
         <span class="list status" th:text="|index: ${status.index}; count: ${status.count}; size: ${status.size}; first: ${status.first}|"></span>
     </li>
 </ul>

image-20220729102750675

也可以不显式声明 status 变量, thymeleaf 会自动创建一个, 状态变量的名称是你声明的

变量加上 Stat, 比如上面的例子 emp: ${emplopyees} 会创建一个 empStat 的状态变量

posted @ 2022-07-29 10:29  为了她  阅读(199)  评论(0编辑  收藏  举报