SpringBoot--实战开发--整合Thymeleaf模版(十)

一、Thymeleaf模版简介

官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#appendix-a-expression-basic-objects
中文文档:
https://www.e-learn.cn/thymeleaf/thymeleaf-instroduce

SpringBoot提供了大量的模版引擎,包括FreeMarker、Groovy、Thymeleaf、Velcoity和Mustache,SpringBoot中推荐使用Thymeleaf作为模版引擎,因为Thymeleaf提供了完美的SpringMVC支持。
Thymeleaf是一个java类库,它是一个xml/xthml/html5的模版引擎,可以作为MVC的Web应用的View层。

  1. 通过xmlns:th=”http://www.thymeleaf.org”命名空间,将页面转换为动态试图,需要进行动态处理的元素使用“th:”作为前缀。
  2. 通过th:text=”${person.name}”访问model中的属性。
  3. 通过th:each=”person:${people}”来做循环迭代。
  4. 通过th:if=”${not #lists.isEmpty(people)}”来判断people是否为空。
    5 .通过th:src=”@{jquery-3.3.1.min.js}”来访问Web中的静态资源。
  5. 通过th:inline=”javascript”来添加script标签,这样在JavaScript代码中即可访问model中的属性值。
  6. 通过“[[${}]]”格式来获得实际值。
    在传统的SpringMVC中,若我们需要集成一个模版引擎的话,需要定义ViewResolver。而Thymeleaf提供了一个SpringTemplateEngine的类,用来驱动SpringMVC下使用Thymeleaf模版引擎。而在SpringBoot中对Thymeleaf进行了自动配置,可以在application中以spring.thymeleaf开发来进行配置,不配置的情况下模版的默认目录是templates。
    在src/main/resource/static中放入需要引入的静态资源:Bootstrap和jQuery。根据默认的原则在src/main/resource/templates下创建index.html文件。

二、SpringBoot整合Thymeleaf

  1. Maven依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. 静态资源
    SpringBoot默认的几个静态页面的目录:
    /static、/public、/resources 、/META-INF/resources

  2. 配置Thymeleaf,在application.properties下配置

#thymelea模板配置
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.mode=HTML5

spring.thymeleaf.cache
是否开启模板缓存,默认true
spring.thymeleaf.check-template-location
是否检查模板路径是否存在,默认true
spring.thymeleaf.content-type
指定Content-Type,默认为: text/html
spring.thymeleaf.enabled
是否允许MVC使用Thymeleaf,默认为: true
spring.thymeleaf.encoding
指定模板的编码,默认为: UTF-8
spring.thymeleaf.excluded-view-names
指定不使用模板的视图名称,多个以逗号分隔.
spring.thymeleaf.mode
**指定模板的模式,具体查看StandardTemplateModeHandlers,默认为: HTML5
spring.thymeleaf.mode = LEGACYHTML5
spring.thymeleaf.mode的默认值是HTML5,其实是一个很严格的检查,改为LEGACYHTML5可以得到一个可能更友好亲切的格式要求。
**
spring.thymeleaf.prefix
指定模板的前缀,默认为:classpath:/templates/
spring.thymeleaf.suffix
指定模板的后缀,默认为:.html
spring.thymeleaf.template-resolver-order
指定模板的解析顺序,默认为第一个.
spring.thymeleaf.view-names
指定使用模板的视图名,多个以逗号分隔.

  1. 编写Controller
@Controller
public class IndexController {
    @GetMapping("/index")
    public ModelAndView test(ModelAndView mv) {
        //视图文件名
        mv.setViewName("index");
        mv.addObject("name","欢迎使用Thymeleaf!");
        return mv;
    }
}
  1. 编写html
    在src/main/resources/templates目录下创建:index.html
<!--引入命名空间-->
<html xmlns:th="http://www.thymeleaf.org">
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8" />
    <title>thymeleaf示例</title>
</head>
<body>
<h1>Hello thymeleaf</h1>
<h2 th:text="'名称:'+${name}">默认值</h2>
</body>
</html>

文本需要th:text属性来设置。我们可以在文本元素中添加默认值,这样当Thymeleaf引擎处理失败的时候页面会显示默认值。${...}是变量表达式,将括号中的变量替换为其值。

三、基础语法

th属性:
常用th属性解读
html有的属性,Thymeleaf基本都有,而常用的属性大概有七八个。其中th属性执行的优先级从1~8,数字越低优先级越高。
1)th:text :设置当前元素的文本内容,相同功能的还有th:utext,两者的区别在于前者不会转义html标签,后者会。优先级不高:order=7
2)th:value:设置当前元素的value值,类似修改指定属性的还有th:src,th:href。优先级不高:order=6
3)th:each:遍历循环元素,和th:text或th:value一起使用。注意该属性修饰的标签位置,详细往后看。优先级很高:order=2
4)th:if:条件判断,类似的还有th:unless,th:switch,th:case。优先级较高:order=3
5)th:insert:代码块引入,类似的还有th:replace,th:include,三者的区别较大,若使用不恰当会破坏html结构,常用于公共代码块提取的场景。优先级最高:order=1
6)th:fragment:定义代码块,方便被th:insert引用。优先级最低:order=8
7)th:object:声明变量,一般和*{}一起配合使用,达到偷懒的效果。优先级一般:order=4
8)th:attr:修改任意属性,实际开发中用的较少,因为有丰富的其他th属性帮忙,类似的还有th:attrappend,th:attrprepend。优先级一般:order=5

  1. 变量表达式 {} 使用方法:直接使用th:xx = "{}" 获取对象属性 。例如:
<form id="userForm">
    <input id="id" name="id" th:value="${user.id}"/>
    <input id="username" name="username" th:value="${user.username}"/>
    <input id="password" name="password" th:value="${user.password}"/>
</form>
<div th:text="hello"></div>
<div th:text="${user.username}"></div>
  1. 选择变量表达式 {}
    使用方法:首先通过th:object 获取对象,然后使用th:xx = "
    {}"获取对象属性。
    这种简写风格极为清爽,推荐大家在实际项目中使用。 例如:
    <form id="userForm" th:object="${user}">
    <input id="id" name="id" th:value="{id}"/>
    <input id="username" name="username" th:value="
    {username}"/>
    <input id="password" name="password" th:value="*{password}"/>
    </form>
  2. 链接表达式 @{}
    使用方法:通过链接表达式@{}直接拿到应用路径,然后拼接静态资源路径。例如:
<script th:src="@{/webjars/jquery/jquery.js}"></script>
<link th:href="@{/webjars/bootstrap/css/bootstrap.css}" rel="stylesheet" type="text/css">
  1. 片段表达式 ~{}
    Thymeleaf 3.0 引入了一个新的片段表达式。形如:~{commons::footer}。
    该特性十分有用(比如解决定义通用的header和footer的问题)
    base.html

片段表达式是Thymeleaf的特色之一,细粒度可以达到标签级别,这是JSP无法做到的。
片段表达式拥有三种语法:
~{ viewName } 表示引入完整页面
~{ viewName ::selector} 表示在指定页面寻找片段 其中selector可为片段名、jquery选择器等
~{ ::selector} 表示在当前页寻找
使用方法:首先通过th:fragment定制片段 ,然后通过th:replace 填写片段路径和片段名。例如:

<!-- /views/common/head.html-->
<head th:fragment="static">
        <script th:src="@{/webjars/jquery/3.3.1/jquery.js}"></script>
</head>
<!-- /views/your.html -->
<div th:replace="~{common/head::static}"></div>

在实际使用中,我们往往使用更简洁的表达,去掉表达式外壳直接填写片段名。例如:

<!-- your.html -->
<div th:replace="common/head::static"></div>

值得注意的是,使用替换路径th:replace 开头请勿添加斜杠,避免部署运行的时候出现路径报错。(因为默认拼接的路径为spring.thymeleaf.prefix = classpath:/templates/)
支持两种语法结构
推荐:~{templatename::fragmentname}
支持:~{templatename::#id}
templatename:模版名,Thymeleaf会根据模版名解析完整路径:/resources/templates/templatename.html,要注意文件的路径。
fragmentname:片段名,Thymeleaf通过th:fragment声明定义代码块,即:th:fragment="fragmentname"
id:HTML的id选择器,使用时要在前面加上#号,不支持class选择器。
代码块表达式的使用
代码块表达式需要配合th属性(th:insert,th:replace,th:include)一起使用。
th:insert:将代码块片段整个插入到使用了th:insert的HTML标签中,
th:replace:将代码块片段整个替换使用了th:replace的HTML标签中,
th:include:将代码块片段包含的内容插入到使用了th:include的HTML标签中,
用一个官方例子来区分三者的不同,第三部分会通过实战再次用到该知识。

<!--th:fragment定义代码块标识-->
<footer th:fragment="copy">
&copy; 2011 The Good Thymes Virtual Grocery
</footer>

<!--三种不同的引入方式-->
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>

<!--th:insert是在div中插入代码块,即多了一层div-->
<div>
    <footer>
    &copy; 2011 The Good Thymes Virtual Grocery
    </footer>
</div>
<!--th:replace是将代码块代替当前div,其html结构和之前一致-->
<footer>
&copy; 2011 The Good Thymes Virtual Grocery
</footer>
<!--th:include是将代码块footer的内容插入到div中,即少了一层footer-->
<div>
&copy; 2011 The Good Thymes Virtual Grocery
</div>
  1. 消息表达式
    即通常的国际化属性:#{msg} 用于获取国际化语言翻译值。例如:
 <title th:text="#{user.title}"></title>
  1. 其它表达式
    在基础语法中,默认支持字符串连接、数学运算、布尔逻辑和三目运算等。例如:
<input name="name" th:value="${'I am '+(user.name!=null?user.name:'NoBody')}"/>
  1. 注释
    Thymeleaf 注释:
1、<!--/* This code will be removed at Thymeleaf parsing time! */-->

2、<!--/*--> 
  <div>
     you can see me only before Thymeleaf processes me!
  </div>
<!--*/-->

3、<!--/*/
  <div th:text="${...}">
    ...
  </div>
/*/-->

四、迭代循环

想要遍历List集合很简单,配合th:each 即可快速完成迭代。例如遍历用户列表:

<div th:each="user:${userList}">
    账号:<input th:value="${user.username}"/>
    密码:<input th:value="${user.password}"/>
</div>

在集合的迭代过程还可以获取状态变量,只需在变量后面指定状态变量名即可,状态变量可用于获取集合的下标/序号、总数、是否为单数/偶数行、是否为第一个/最后一个。例如:

<div th:each="user,stat:${userList}" th:class="${stat.even}?'even':'odd'">
    下标:<input th:value="${stat.index}"/>
    序号:<input th:value="${stat.count}"/>
    账号:<input th:value="${user.username}"/>
    密码:<input th:value="${user.password}"/>
</div>

如果缺省状态变量名,则迭代器会默认帮我们生成以变量名开头的状态变量 xxStat, 例如:

<div th:each="user:${userList}" th:class="${userStat.even}?'even':'odd'">
    下标:<input th:value="${userStat.index}"/>
    序号:<input th:value="${userStat.count}"/>
    账号:<input th:value="${user.username}"/>
    密码:<input th:value="${user.password}"/>
</div>

th:remove
th:remove的值如下:
  1.all:删除包含标签和所有的孩子。
  2.body:不包含标记删除,但删除其所有的孩子。
  3.tag:包含标记的删除,但不删除它的孩子。
  4.all-but-first:删除所有包含标签的孩子,除了第一个。
  5.none:什么也不做。这个值是有用的动态评估。

五、条件判断

条件判断通常用于动态页面的初始化,例如:

<div th:if="${userList}">
    <div>的确存在..</div>
</div>

如果想取反则使用unless 例如:

<div th:unless="${userList}">
    <div>不存在..</div>
</div>

六、日期格式化

使用默认的日期格式(toString方法) 并不是我们预期的格式:Mon Dec 03 23:16:50 CST 2018

<input type="text" th:value="${user.createTime}"/>

此时可以通过时间工具类#dates来对日期进行格式化:2018-12-03 23:16:50

<input type="text" th:value="${#dates.format(user.createTime,'yyyy-MM-dd HH:mm:ss')}"/>

七、内联写法

(1)为什么要使用内联写法?·答:因为 JS无法获取服务端返回的变量。
(2)如何使用内联表达式?答:标准格式为:[[${xx}]] ,可以读取服务端变量,也可以调用内置对象的方法。例如获取用户变量和应用路径:

    <script th:inline="javascript">
        var user = [[${user}]];`
        var APP_PATH = [[${#request.getContextPath()}]];
        var LANG_COUNTRY = [[${#locale.getLanguage()+'_'+#locale.getCountry()}]];
    </script>

(3)标签引入的JS里面能使用内联表达式吗?答:不能!内联表达式仅在页面生效,因为Thymeleaf只负责解析一级视图,不能识别外部标签JS里面的表达式。

八、七大基础对象:

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

九、常见问题

  1. 去掉IDE thymeleaf Html显示红色波浪线
    打开IDE的file->setting->左上角搜索inspections,然后在右边的搜索栏输入thy,就会显示如下页面,将Expression variables validation的√去掉,然后点击确定。


    红色波浪线
  2. 日期格式处理
    添加:
    @Column
    @DateTimeFormat(pattern="yyyy-MM-dd")
    private Date createtime;

显示:

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

推荐阅读更多精彩内容