Thymeleaf的语法详情及使用

官网: https://www.thymeleaf.org/documentation.html

1. 什么是 Thymeleaf

  • Thymeleaf是⾯向Web和独⽴环境的现代服务器端Java模板引擎,能够处 理HTML,XML,JavaScript,CSS甚⾄纯⽂本。
  • Thymeleaf旨在提供⼀个优雅的、⾼度可维护的创建模板的⽅式。 为了实 现这⼀⽬标,Thymeleaf建⽴在⾃然模板的概念上,将其逻辑注⼊到模板 ⽂件中,不会影响模板设计原型。 这改善了设计的沟通,弥合了设计和 开发团队之间的差距。
  • Thymeleaf从设计之初就遵循Web标准——特别是HTML5标准 ,如果需 要,Thymeleaf允许您创建完全符合HTML5验证标准的模板。
  • Tips:
    Spring Boot 体系内推荐使用Thymeleaf作为前端页面模板,并且Spring Boot 2.0 中默认使用 Thymeleaf 3.0,性能提升幅度很大。

2. Thymeleaf的特点

  1. Thymeleaf在不管是否连接服务器的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。
  2. Thymeleaf开箱即用的特性。它支持标准方言和Spring 方言,可以直接套用模板实现JSTL、OGNL表达式效果,避免每天套模板、改JSTL、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
  3. Thymeleaf提供Spring标准方言和一个与SpringMVC完美集成的可选模块,可以快速地实现表单绑定、属性编辑器、国际化等功能
  4. Thymeleaf相关知识脑图


    Thymeleaf相关知识脑图

3. Thymeleaf的快速入门 (简单例子)

    1. 新建一个Springboot项目,加上Thymeleaf的starter
      pom.xml (仅展示重要依赖)
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    1. 配置properties文件,加上不开启Thymeleaf的缓存
spring.thymeleaf.cache=false
    1. 创建hello.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <p>欢迎使用Thymeleaf模板</p>
    <p th:text="${msg}">这是静态段落文字</p>
</body>
</html>
    1. 创建HelloController
package cn.lazyfennec.springbootthymeleaf.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @Author: Neco
 * @Description:
 * @Date: create in 2022/5/4 16:20
 */
@Controller
public class HelloController {

    @RequestMapping("/hello")
    public String hello(ModelMap map) {
        map.addAttribute("msg", "Hello Neco!!!");
        return "hello";
    }

}

4. Thymeleaf 的基本语法 - th属性

    1. 文本属性
  • 文本拼接:||
  • 文本信息:th:text,th:id,th:value...
  • 文本信息(可以解析HTML各位): th:utext
    @RequestMapping("/hello")
    public String hello(ModelMap map){
        map.addAttribute("message","你好<b>这里加粗了</b>");
        map.put("id","这是id");
        map.put("value","这是value");
        map.put("utext","这是utext里面的内容<b>这里加粗了</b>");
        return "hello";
    }
<body>
    <!--文本属性-字符串的拼接:写法1-->
    <p th:text="|welcome to shanghai,${message}|"></p>
    <!--文本属性-字符串的拼接:写法2-->
    <p th:utext="'welcome to shanghai,'+${message}"></p>
    <!--文本属性-id属性-->
    <p th:id="${id}"></p>
    <!--文本属性-value属性-->
    <input th:value="${value}"/>
    <!--使用内联标签来书写-->
    <!--不带html的解析,类似于th:text-->
    <p>[[|welcome to shanghai,${message}|]]</p>
    <!--带html的解析,类似于th:utext-->
    <p>[('welcome to shanghai,'+${message})]</p>
    <!--也可以直接写文本-->
    <p>[['welcome to shanghai']]</p>
</body>
    1. 条件属性
  • if判断:th:if
  • unless判断:th:unless
  • switch判断:th:switch...th:case
    @RequestMapping("/if")
    public String hello(ModelMap map){
        map.put("flag","yes");
        map.put("baidu","http://www.baidu.com");
        map.put("taobao","http://www.taobao.com");
        map.put("age",19);
        return "if";
    }
<body>
    <!--if:如果条件成立,就展示-->
    <!--th:href:允许在href属性里面使用thymeleaf语法,超链接需要用@{}开头,里面可以写model里面的key-->
    <a th:if="${flag eq 'yes'}" th:href="@{${baidu}}">baidu1</a><br>
    <!--th:href:专门用来使用URL地址的,既可以直接像上面那样在里面直接写${},
    也可以先定义个变量用大括号括起来然后在url的最后面使用一个小括号来对该变量进行赋值-->
    <a th:if="${flag eq 'yes'}"
       th:href="@{{baidusite}(baidusite=${baidu})}">baidu2</a><br>
    <!--直接在href里面写${}是无法获取到后台model里面的数据的-->
    <a th:if="${flag eq 'yes'}" href="${baidu}">baidu3</a><br>
    <!--不使用th:href的话,href里面只能写死的数据-->
    <a th:if="${flag eq 'no'}" href="http://www.baidu.com">baidu4</a><br>
    <!--unless:如果条件不成立,就展示-->
    <a th:unless="${flag eq 'no'}" th:href="@{http://www.taobao.com}">taobao</a>
    <!--使用switch-->
    <div th:switch="${age}">
        <p th:case="18">这是张三</p>
        <p th:case="19">这是李四</p>
        <p th:case="20">这是王五</p>
        <p th:case="*">这是谁我不认识</p>
    </div>
</body>
    1. 循环属性-th:each
  • th:each迭代list
  • th:each的内置属性
  • th:each迭代map
    @RequestMapping("/list")
    public String list(ModelMap map){
        List<User> list = getUserList();
        map.addAttribute("list",list);
        return "list";
    }
  <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>

5. Thymeleaf的表达式语法

  • ${...}变量表达式:也叫OGNL表达式或Spring EL表达式,用于调用各种属性和方法
  • a) 可以获取对象的属性和方法
  • b) 可以使用ctx, vars, locale, request, response, session, servletContext内置对象
  • c) 可以使用dates, numbers, strings, objects, arrays, lists, sets, maps等内置方法
  • @{...}链接表达式:不管是静态资源的引用,form表单的请求,凡是链接都可以用@{...]
  • a) 无参:@{/xxx}
  • b) 有参:@{/xxx(k1=v1,k2=v2)},对应url结构:xxx?k1=v1&k2=v2
  • c) 引入本地资源:@{/项目本地的资源路径}
  • d) 引入外部资源:@{/webjars/资源在jar包中的路径}
  • #{...} 消息表达式:用于从消息源中提取消息内容实现国际化
  • 语法和变量表达式相比多了个获取参数的方式
  • 消息源主要是properties文件
  • ~{...}代码块表达式:把某一段定义好的代码块插入到另一个页面中,一般用于定义出一套通用的header或者是footer
  • 语法:~[templatename:fragmentname}或者~[templatename:.id},如果省略templatename,它将在当前页面进行寻找指定的代码块,注意:~可以省略
    a) templatename:模版名,定义模板的写法:<footer th:fragment="copy">
    b) fragmentname:片段名,引入模板的写法: <div th:insert="comm/foot : copy">
    c) id: HTML的id选择器,使用时要在前面加上#号,不支持class选择器
  • 代码块表达式需要配合th属性(th:insert,th:replace,th:include)一起使用。
    a) th:insert:将代码块片段整个插入到使用了th:insert的HTML标签中
    b) th:replace:将代码块片段整个替换使用了th:replace的HTML标签中
    c) th:include:将代码块片段包含的内容插入到使用了th:include的HTML标签中
  • *{...}选择变量表达式:是另一种类似${...},在某些时候,两者是等价的,选择变量表达式在执行时是在选择的对象上求解(使用th:object来选择对象),而${...}是在上下文的变量Map上求解。
  • 两者获取对象里边属性的方法
  • 两者进行混用的条件

6. Thymeleaf中表达式支持的语法

  • 字面
  • 文本文字: 'one text','Another one!',...
  • 数字文字:0,34,3.0,12.3,...
  • 布尔文字: true,false
  • 空字面: null
  • 文字操作:
  • 字符串连接:+
  • 文字替代:|The name is ${name}
  • 算术运算:
  • 运算符: +,-,*,/,%
  • 布尔运算:
  • 二元运算符:and,or
  • 布尔否定(一元运算符)∶ !, not
  • 比较和相等
  • 比较:>, <,>=,<= (gt,lt,ge,le)
  • 相等判断:==,!= (eq,ne)
  • 条件运算符
  • lF-THEN:(if) ? (then)
  • lF-THEN-ELSE: (if) ? (then) : (else)
  • 默认: (value) ?: (defaultvalue)

7. Thymeleaf中的基础对象

  • #ctx:上下文对象
  • #vars:上下文对象(和#ctx相同,但是一般用#ctx)
  • #locale:区域对象
  • #request:(仅Web环境可用)HttpServletRequest对象
  • #response:(仅 Web环境可用)HttpServletResponse对象
  • #session:(仅Web环境可用)HttpSession对象
  • #servletContext:(仅Web环境可用)ServletContext 对象
  • param:获取请求的参数
  • session:访问session属性
  • application:获取应用程序/ servlet上下文属性

注意:以上三个不带#的对象,都拥有以下方法:size(),isEmpty(),containsKey(), .key

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>if,unless</title>
</head>
<body>
    <h1>ctx上下文对象</h1>
    <p th:text="${#ctx}"></p>
    <h1>ctx获取保存在map里的数据</h1>
    <p th:text="${#ctx.getVariable('a')}"></p>
    <h1>vars上下文变量</h1>
    <p th:text="${#ctx}"></p>
    <h1>locale区域对象</h1>
    <p th:text="${#locale}"></p>
    <p th:text="${#locale.country}"></p>
    <h1>param的使用</h1>
<!--    http://127.0.0.1:8088/baseObject?a=1&b=2&c=3,
    param代表获取到请求里的参数-->
    <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>
</body>
</html>
package com.study.thymeleaf.thymeleafdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * @Author 来苏
 * 测试基础对象
 * #ctx、#vars、#locale
 */
@Controller
public class BaseObjectController {
    @RequestMapping("/baseObject")
    public String map1(ModelMap map, HttpServletRequest request, HttpSession session) {
        map.put("a", 123);
        map.put("b", "bbb");
        request.setAttribute("request", "123");
        session.setAttribute("session", "321");
        return "base";
    }
}

8. Thymeleaf的常用工具类

  • #strings:字符串工具类
  • #lists: List工具类
  • #arrays:数组工具类
  • #sets: Set工具类
  • #maps:常用Map方法。
  • #objects:一般对象类,通常用来判断非空
  • #bools:常用的布尔方法。
  • #execInfo:获取页面模板的处理信息。
  • #messages:在变量表达式中获取外部消息的方法,与使用#{...}语法获取的方法相同。
  • #uris:转义部分URL/URI的方法。
  • #conversions:用于执行已配置的转换服务的方法。
  • #dates:时间操作和时间格式化等。
  • #calendars:用于更复杂时间的格式化。
  • #numbers:格式化数字对象的方法。
  • #aggregates:在数组或集合上创建聚合的方法。
  • #ids:处理可能重复的id属性的方法。

9. body内的内联

  • 例子
<!--内联标签的使用-->
    <!--内联写法1-->
    <p >[[|welcome to china,${text}|]]</p>
    <!--内联写法2-->
    <p>[('welcome to china,'+${text})]</p>
    <!--内联写法3-->
    <p>[('welcome to china')]</p>
  • 我们的习惯
    1.有时候这样更合适:<p>Hello,[[${session.user.name}]]</p>
    2.而不喜欢这样写代码:<p>Hello, <span th:text="${session.user.name]">Sebastian</span></p>

  • th属性和内联标签的对应关系
    1.[[...]]等价于th:text (结果将被HTML转义)
    2.[(...)]等价于th:utext(结果不会执行HTML转义)。

  • body上加上inline="none" 可以使内联失效

<body th:inline="none">

10. JS里的内联

  • 例子
<script th:inline="javascript">
        var name = [[${name}]];
        var userName = [[${user.name}]];
        var userAge = [[${user.age}]];
        var userPass = [[${user.pass}]];
        alert("name:"+name+",userName:"+userName+",userAge:"
            +userAge+",userPass:"+userPass);
</script>
  • 在JavaScript中使用内联标签(默认不支持)
    1.在script标签上引入对内联的支持:<script type="text/javascript" th:inline="javascript">
    2.在script标签里书写[[]]、[()]来获取后端数据;

  • 在JavaScript中实现前后端分离(也称之为JavaScript自然模板)
    1.Thymeleaf的目标就是希望前后端分离,即同一个Html文件前端人员以静态原型的方式打开时,看到的是它们的内容,而后端人员通过服务器打开时,看到的是动态的数据;
    2.直接在数据上使用js注释即可实现前后端分离: var msg =/*[[S{name]]*/'666666'
    3.当在服务器打开该页面时,就会展示${name}的值,当时在静态打开时,就展示666666

  • 在JavaScript中自动进行对象序列化
    1.JavaScript 内联的一个重要的特性是,内联表达式的计算结果不限于字符串,它能自动的将后台的数据序列化为javascript对象

  • Tips
    js中开启内联标签模式只能是在Html文件内部的JavaScript 代码,不能在引入的外部JavaScript文件中进行操作

11. css里的内联

  • 例子
    <style type="text/css" th:inline="css" th:with="color='yellow',
        fontSize='25px'">
        p{
            /*这里是一个注释*/
            color: /*[[${color}]]*/ red;
            /*fontSize需要使用[()]来忽略HTML的转义*/
            font-size:[(${fontSize})];
        }
    </style>
  • 在CSS中使用内联标签(默认不支持)
    1.在style标签上引入对内联的支持: <style th:inline="css">
    2.在style标签里书写[[]][()]来获取后端数据;

  • 在CSS中实现前后端分离(也称之为CSS自然模板)
    1.与内联JavaScript一样,CSS内联也允许<style>标签可以静态和动态地工作,即通过在注释中包含内联表达式作为CSS自然模板。
    2.当服务器动态打开时,字体颜色为黄色;当以原型静态打开时,显示的是红色,因为Thymeleaf会自动忽略掉css注释之后和分号之前的代码。
    3.在CSS中,因为CSS自然模板的问题,所以不能在css中像以前一样添加注释,因为Thymeleaf会将它们当做模板进行处理。

  • Tips
    与内联JavaScript一样,内联CSS同样只能Html内嵌的<style >标签中进行使用,不能在外部关联的CSS文件中进行使用


如果觉得有收获就点个赞吧,更多知识,请点击关注查看我的主页信息哦~

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

推荐阅读更多精彩内容