SpringBoot默认模板引擎Thymeleaf

SpringBoot默认模板引擎Thymeleaf

官网地址

https://www.thymeleaf.org/index.html

image.png

概念:

Thymeleaf是面向Web和独立环境的现代服务器端Java模板引擎,能够处理Html,xml,JavaScript,css甚至存文本。

Thymeleaf 在提供一个优雅的,高度可维护的创建模式模板的方式。为了实现这一目标,Thymeleaf建立在自然模板的概念上,将其逻辑注入到模板文件中,不会影响模板设计原型。

Thymeleaf从设计之初就遵守web标准-特别是HTml5标准,如果需要,Thymeleaf允许创建完全符合HTML5验证标准模板。

SpringBoot 体系中默认推荐Thymeleaf作为前端页面模板,并且SpringBoot2.0中默认使用Thymeleaf3.0,性能提升幅度很大。

Thymeleaf特点

1 .Thymeleaf不管是否连接服务器的环境下皆可运行
2 .开箱即用。支持标准的方言和Spring方言,可以直接套用模板实现JSTL,OGNL表达式效果。

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

SpringBoot集成Thymeleaf

1.在pom.xml导入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

2.application.properties配置Thymeleaf

# thymeleaf 缓存,生产环境要放开
spring.thymeleaf.cache=false

3.spring boot对Thymeleaf的自动配置支持
org.springframework.boot.autoconfigure.thymeleaf


image.png
image.png

4.新建HTML文件

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>
<!--有服务器数据的时候 替换msg,没有就显示标签内的默认文字 -->
    <p th:text="${msg}">这是静态标签文字</p>

</body>
</html>

Thymeleaf语法

th属性

官方文档地址
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#setting-value-to-specific-attributes

image.png

文本属性

文本拼接: |内容|
文本信息: th:text , th:id , th:value

<!--有服务器数据的时候 替换msg,没有就显示标签内的默认文字 -->
<p th:text="|welcome to Thymeleaf,${text}|"></p>
<!-- 字符拼接 -->
<p th:text="'welcome to Thymeleaf,'+${text}"></p>

<input th:value="${value}" th:id="${id}">
<br>

<!--text 将内容原样输出-->
<p th:text="${text}" ></p>
<!-- utext 输出内容会转义  -->
<p th:utext="${utext}" ></p>
条件属性

if 判断 : th:if
unless判断 : th:unless
switch判断 :th:switch th:case

<!--如果是超链接 必须使用 @{url}表达式,里面就可以用${url}的语法-->
<a th:if="${flag eq 'yes'}" th:href="@{${baidu}}">baidu_1</a><br>

<a th:if="${flag eq 'yes'}" th:href="@{ {baidusite}(baidusite=${baidu}) }">baidu_2</a><br>

<!--unless 取反-->
<a th:unless="${flag eq 'no'}" th:href="@{${baidu}}">baidu_3</a><br>

<!--swith-->
<div th:switch="${age}">
    <p th:case="18">18岁</p>
    <p th:case="19">19岁</p>
    <p th:case="20">20岁</p>
    <p th:case="*">未知</p>
</div><br>
循环属性 th:each

th:each迭代list
th:each的内置属性
th:tach迭代map

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h4>常用的方式</h4>
<table>
    <tr>
        <th>名字</th>
        <th>年龄</th>
        <th>密码</th>
    </tr>
    <tr th:each="user:${list}">
        <td th:text="${user.name}"></td>
        <td th:text="${user.age}"></td>
        <td th:text="${user.pass}"></td>
    </tr>
</table><br>
<h4>list 详细信息</h4>
<table>
    <tr>
        <th>名字</th>
        <th>年龄</th>
        <th>密码</th>
    </tr>
    <tr th:each="user,iterStat:${list}">
        <td th:text="|索引:${iterStat.index};
        元素总数:${iterStat.count};
        current:${iterStat.current};
        奇偶数:${iterStat.even?'奇数':'偶数'};
        是第一个吗:${iterStat.first};
        是最后一个吗:${iterStat.last}|"></td>
        <td th:text="${user.name}"></td>
        <td th:text="${user.age}"></td>
        <td th:text="${user.pass}"></td>
    </tr>
</table><br>

<h4>遍历map</h4>
<table border="2px" width="60%">
    <tr th:each="m:${map}">
        <td th:text="${m.key}"></td>
        <td th:text="${m.value}"></td>
    </tr>
</table>

<h4>遍历map的value是一个user对象</h4>
<table border="2px" width="60%">
    <tr th:each="m:${map1}">
        <td th:text="${m.key}"></td>
        <td th:text="${m.value.name}"></td>
        <td th:text="${m.value.age}"></td>
        <td th:text="${m.value.pass}"></td>
    </tr>
</table>

<h4>遍历map的value是一个list user对象</h4>
<div th:each="m:${map2}">
    <p th:text="${m.key}"></p>
    <table border="2px" width="60%">
        <tr th:each="m1:${m.value}"  >
            <td th:text="${m.key}"></td>
            <td th:text="${m1.name}"></td>
            <td th:text="${m1.age}"></td>
            <td th:text="${m1.pass}"></td>
        </tr>
    </table>
</div>

</body>
</html>

表达式语法

1 .简单表达式:
变量表达式: ${...}
选择变量表达式: *{...}
消息表达: #{...}
链接URL表达式: @{...}
片段表达式: ~{...}

2 . 文字
文本文字:'one text','Another one!',...
号码文字:0,34,3.0,12.3,...
布尔文字:true,false
空文字: null
文字标记:one,sometext,main,...

3 .文字操作:
字符串串联: +
文字替换: |The name is ${name}|

4 .算术运算:
二元运算符:+,-,*,/,%
减号(一元运算符): -

5 .布尔运算:
二元运算符:and,or
布尔否定(一元运算符): !,not

6 .比较和平等:
比较:>,<,>=,<=(gt,lt,ge,le)
等号运算符:==,!=(eq,ne)

7 .条件运算符:
如果-则: (if) ? (then)
如果-则-否则: (if) ? (then) : (else)
默认: (value) ?: (defaultvalue)

8 .特殊令牌:
无操作: _

${...} :

变量表达式,也叫SpringEL表达式,OGNL
1 .用于调用各种属性和方法;
2 .获取对象的属性和方法
3 .可以使用ctx,vars,locale,request,response,session,servletContext内置对象
4 .可以使用dates,numbers,strings,objects,arrays,lists,sets,maps等内置方法

@{...} :

链接表达式,不管是静态资源的引用,form表单的请求,凡是链接都可以用@{..}
1 .无参 : @{/xxx}
2 .有参 : @{/xxx(k1=v1,k2=v2)} , 对应url结构:xxx?k1=v1&k2=v2
3 .引入本地资源 :@{/项目本地的资源路径}
4 .引入外部资源 : @{/webjars/资源在jar包中的路径}

<!--引入外部资源-->
<link th:href="@{/webjars/bootstrap/4.5.0/css/bootstrap.css}" rel="stylesheet">

<!--引入本地资源-->
<link th:href="@{/main/css/itdragon.css}" rel="stylesheet">

<!--表单提交路径-->
<form class="form-login" th:action="@{/user/login}" th:method="post"></form>

<!--超链接跳转路径附带参数-->
<a class="btn btn-sm" th:href="@{/login.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/login.html(l='en_US')}">English</a>

webjars 网站资源:https://www.webjars.org/

image.png

例如:集成bootstrap

<!--bootstrap 前端架包-->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>4.5.0</version>
        </dependency>
image.png
#{...} :消息表达式:

用于从消息源中提取消息内容实现国际化
1 .语法与变量表达式相比多了个获取参数的方式
2 .消息源主要是properties文件

~{...} 代码块 表达式:

把某一段定义好的代码插入到另一个页面中,一般用于定义出一套通用的header或者footer

语法:~{templatename::fragmentname} 或者 ~{templatename::#id} , 如果省略templatename,它将在当前页面进行寻找指定的代码块,注意,~{} 可以省略;
1 . templatename: 模板名,定义模板的写法:<footer th:fragment="copy">
2 . fragmentname: 片段名,引入模板的写法:<div th:insert="comm/foot::copy">
3 .id: HTML 的id选择器,使用时要在前面加上#号,不支持class选择器

代码表达式需要配合th属性(th:insert,th:replace,th:include)一起使用功能:
1 .th:insert : 将代码块整个插入到使用了 th:insert 的HTML标签中
2 .th:replace : 将代码块段整个替换使用了 th:replace 的HTML标签中
3 . th:include : 将代码块片段包含的内容插入到使用了 th:include 的HTML标签

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

是另一种类似{...},在某些时候,两者是等价的,选择变量表达式在执行时是在选择的对象上求解(使用th:object来选择对象),而{...} 是在上下文的变量Map上求解。
两者获取对象里面属性的方式
两者混用的条件

基础对象

官方文档 :4.2 基础对象
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-basic-objects
在上下文变量上评估OGNL表达式时,某些对象可用于表达式,以提高灵活性。这些对象将以#符号开头(按照OGNL标准)被引用:

  • #ctx:上下文对象。
  • #vars: 上下文变量。
  • #locale:上下文语言环境。
  • #request:(仅在Web上下文中)HttpServletRequest对象。
  • #response:(仅在Web上下文中)HttpServletResponse对象。
  • #session:(仅在Web上下文中)HttpSession对象。
  • #servletContext:(仅在Web上下文中)ServletContext对象。

param:获取请求参数
session:访问session属性
application:获取应用程序 Servlet上下文属性
param,session,application都有方法:size(),isEmpty(),containsKey(), .key

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>base object</title>
</head>
<body>

<h1>base object 上下文 ctx保存了所有的信息</h1>
<p th:text="${#ctx}"></p>
<h1> ctx 获取map 数据</h1>
<p th:text="${#ctx.getVariable('a')}"></p>

<h1> vars上下文对象 和 ctx 内容差不多</h1>
<p th:text="${#vars}"></p>

<h1> 获取 local区域对象 </h1>
<p th:text="${#locale}"></p>
<p th:text="${#locale.country}"></p>

<h1> param 使用 </h1>
<!--http://localhost:8080/baseobject?a=12&b=3-->
<p th:text="|size:${param.size()},a:${param.a}|"></p>

<h1> session 使用 </h1>
<p th:text="${#session.getAttribute('session')}"></p>
<p th:text="${session.session}"></p>

<br>

</body>
</html>

常用工具类

除了这些基本对象之外,Thymeleaf将为我们提供一组实用程序对象,这些对象将帮助我们在表达式中执行常见任务。

  • #execInfo:有关正在处理的模板的信息。
  • #messages:用于获取变量表达式内的外部化消息的方法,与使用#{…}语法获得消息的方法相同。
  • #uris:用于转义部分URL / URI的方法
  • #conversions:用于执行已配置的转换服务(如果有)的方法。
  • #datesjava.util.Date对象的方法:格式化,组件提取等。
  • #calendars:类似于#dates,但用于java.util.Calendar对象。
  • #numbers:格式化数字对象的方法。
  • #stringsString对象的方法:包含,startsWith,前置/附加等。
  • #objects:一般对象的方法。
  • #bools:布尔值评估的方法。
  • #arrays:数组方法。
  • #lists:列表方法。
  • #sets:套方法。
  • #maps:地图方法。
  • #aggregates:用于在数组或集合上创建聚合的方法。
  • #ids:用于处理可能重复的id属性的方法(例如,由于迭代的结果)。

表达工具对象 官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#appendix-b-expression-utility-objects

image.png

详细介绍用法:
image.png

内联标签 body 内的内联

官方文档:
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#inlining

image.png

内联表达式:
[[...]] 或 [(...)]
[[...]]对应于th:text(即结果将被HTML转义)
[(...)]对应于th:utext 且将不执行任何HTML转义

<!-- 内联 1 标签 原样输出-->
<p>hello ,[[|welcome   ,${text}|]]</p>
<!-- 内联 2 标签 文本带有转义会解析-->
<p>[('welcome ,'+${text})]</p>
<!-- 内联 3 标签 存文本输出-->
<p>[('welcome ')]</p>
<!--是内联失效 th:inline="none" -->
Js内联

JavaScript中使用内联标签(默认不支持):
在script 标签上引入对内联的支持:

<script th:inline="javascript">
    ...
//获取后端的数据
    var username = [[${session.user.name}]];
    var username2 = [(${session.user.name2})];
    ...
</script>

官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#javascript-inlining

image.png

在JavaScript中实现前后端分离(即JavaScript自然模板):
Thymeleaf 的目标是希望前后端分离,即同一个html文件前端开发以静态原型打开,看到的是他们的内容,而后端开发打开通过服务器,看到是动态的数据;
直接在数据上使用js注释实现前后端分离:

<script th:inline="javascript">
  ...
// /*...*/ 注释里的值是动态获取的,后面的是默认值
  var username = /*[[${session.user.name}]]*/ "Gertrud Kiwifruit";
  ...
</script>

在JavaScript中自动进行对象序列化:
内联表达式的计算结果不限于字符串,它能自动将后台的数据序列化为JavaScript对象。
js开启内联标签模式只能在html文件内部的JavaScript代码中,不能在引入外部的JavaScript文件中操作。

<script th:inline="javascript">
  ...
//session.user是一个user对象
  var user = /*[[${session.user}]]*/ null;
// 获取到对象,自动序列化
var user = {"age":null,"firstName":"John","lastName":"Apricot",
              "name":"John Apricot","nationality":"Antarctica"};
  ...
</script>
CSS内联

官方文档:
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#css-inlining

image.png

在CSS中使用内联标签(默认不支持):
在style标签引入对内联的支持:
在css中,因为css自然模板,所以不能在css中添加注释说明,Thymeleaf会将它们当成模板处理。
CSS内联标签模式只能在html文件内部的style标签中,不能在引入外部关联的css文件中操作。

<style th:inline="css">
  ...
</style>

在style标签里书写 [[]],[()]来获取后端数据

在CSS中实现前后端分离(即CSS自然模板):
CSS内联也允许<style>标签静态和动态工作,通过注释中包含内联表达式作为css自然模板。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <!--    内联标签-->
    <style type="text/css" th:inline="css"
           th:with="color='yellow',fontSize='25px'">
        p{
            color: /*[[${color}]]*/ red;
            /*[(...)] 不转义;在css中,这种注释说明不能出现,会报错*/
            font-size: [(${fontSize})];
        }
    </style>
</head>
<body>

//使用 p 标签    
<p>hello china</p>

</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,907评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,987评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,298评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,586评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,633评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,488评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,275评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,176评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,619评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,819评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,932评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,655评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,265评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,871评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,994评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,095评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,884评论 2 354