模板:准备呈现给用户的视图页面
数据:提供数据有多种方式
request.setAttribute();
model.addtribute();
模板引擎:处理模板和数据的程序。获取模板,吧模板中的特定符号,替换为数据,生成输出结果文件
jsp也是一种模板
thymeleaf:服务器端的模板引擎
一、什么是Thymeleaf
Thymeleaf是一个表现层的模板引擎,一般被使用在Web环境中,它可以处理HTML,XML,JS等文档,简单来说,它可以将JSP作为Java Web应用的表现层,有能力展示与处理数据。Thymeleaf可以让表现层的界面节点与程序逻辑被共享,这样的设计,可以让界面设计人员、业务人员与技术人员都参与到项目开发中。
这样,同一个模板文件,既可以使用浏览器直接打开,也可以放到服务器中用来显示数据,并且样式之间基本不会存在差异,因此界面设计人员与程序设计人员可以使用同一个模板文件,来查看静态与动态数据的效果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XwsGNbMT-1642483354230)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210815144232819.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PSe6yR4C-1642483354231)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210815144535680.png)]
可以从类路径中来读取我们所需的模板文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMVfmCIY-1642483354231)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210815145638172.png)]
例:设置模板的前缀,后缀
前缀为模板文件相对于类路径下的一个目录名称,后缀来指定模板文件的扩展名
在resources下创建templates目录,创建index.html文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ENl8D8jI-1642483354232)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210815150611028.png)]
thymeleaf-springboot环境搭建
编写application.properties
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nuUSywRt-1642483354233)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210815151438668.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A5Ufszow-1642483354234)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210815152701232.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qVf1Hgew-1642483354234)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210817163458727.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1too21bo-1642483354235)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210817163744567.png)]
表达式语法
1、表达式分类
序号 | 表达式 | 描述 | 例子 |
---|---|---|---|
1 | ${…} | 变量表达式,可用于获取后台传过来的值 | <p th:text="${username}">hahha</p> |
2 | *{…} | 选择变量表达式 | |
3 | #{…} | 消息表达式 | |
4 | @{…} | 链接网址表达式,用于替换网页中的src,href等的值 | th:href="@{/css.home.css}" |
5 | ~{…} | 片段表达式,可以用于引用公共的目标片段 | <div th:insert="~{footer :: copy}"></div> |
2、变量表达式${…}
获取基本类型变量
获取对象类型
新建数据类Student
新建Controller
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-owUOjAAk-1642483354236)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210817172600585.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mmMls3D4-1642483354237)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210817172634941.png)]
Student的属性是public或者属性是private且有public类型getXXX的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Qhq5Lwe-1642483354238)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210817173758254.png)]
选择表达式*{…}
链接表达式@{…}
@{…}表达式用于处理web应用中的url地址,可以是相对地址,也可以是绝对地址
@{/}是相对应用根路径,其他都是相对当前路径
@{/}斜杠开头表示相对整个应用根目录,"/"表示“/应用上下文路径”
th:href是一个修饰符属性,将表达式结果设置为标签href属性的值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tCHwDHR0-1642483354239)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210817175906661.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oTPq1fyA-1642483354240)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210817175842451.png)]
链接中传参数
1)在@{…}表达式末尾使用“()"设置参数
@{/user/list(id=1001,name=zs)}
2)多个参数时,使用","隔开
3)参数值可以使用表达式动态取值
@{/user/list(id=1001,name=${name})}
消息表达式(国际化)
#{…}
实现
1、在resources目录下创建国际化的资源文件
目录 i18n
messages.properties
login=login|登录
messages_zh_CN.properties
login=登录
message_en_US.properties
login=Login
2、创建LocaleResolver实现类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UaFoIkBi-1642483354240)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210818014455568.png)]
3、创建mvc配置类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ICVK0bV8-1642483354241)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210818014523727.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4bPHW7eQ-1642483354242)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210819103131459.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0TztK4da-1642483354243)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210819103157633.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jN3irGuo-1642483354244)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210819103225852.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l8jSLRuT-1642483354245)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210819103245598.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fJKR4ReF-1642483354245)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210819103316080.png)]
标准表达式
文本
文本文字只是在单引号之间指定的字符串,它们可以包含任何字符,如果字符之中没有空格,可以不加单引号。使用”+“连接文本,也可以使用”|“连接文本
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cXmajDPl-1642483354247)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210819111601207.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GSf3Zj0J-1642483354248)(C:\Users\pumpkin\AppData\Roaming\Typora\typora-user-images\image-20210819111623288.png)]
数字
数字文本就是:数字,算术运算也可用:+,-,*,/和%,表达式中的值可以进行比较>,<,>=,<=符号,以及==和!=可以被用来检查是否相等,一些符合需要使用实体gt(>),lt(<),ge(>=),le(<=),not(!),eq(==),neq(!=)
1、创建NumberController
2、创建num.html
p th:text="6+6+'后面是字符了'+10+20">
6+6是加法运算,遇到’'后面是字符串连接,不能在数字运算了
p th:text="6+6 + '这回不一样' + (10+20)"
括号的优先级高,6+6是加法10+20后再连接字符串
布尔
布尔是true,false
and(与),or(或),not(非),!(非)
<th:if="布尔值">
,布尔值为true显示标签,反之不显示
<th:if="true|false">标签值</th:if>
null和“”
null字面量,在页面直接使用,也可以判断数据是否为null,当数据为null,标签和内容不显示,“”字符串和null处理结果一样
比较/逻辑运算符
表达式中的值可以与>,<,>=,<=,==,!=符号进行比较,一个更简单的代替方案是使用这些运算符的文本别名>;(>),<;(<),&ge;(>=),&le;(<=),eq(==),neq(!=)
逻辑运算符:and(与)、or(或)、!(非)、not(非)
<p th:if="not(false)">not(false)</p>
<p th:if="!false">!false非假为true</p>
三元运算符
thymeleaf中的三元运算与java以及javascript中基本一致,如A>B?X:Y,在X、Y中可以继续嵌套,只是Thymeleaf中需要使用括号括起来,否则报错
<p th:text="${age}!=null?(${age}>30?'大于30':'不够30'):'age是null'">嵌套的三元</p>
设置属性值
属性 | 作用 |
---|---|
th:text | 计算其值表达式并将结果设置为标签的标签体 |
th:utext | th:text会对结果中的特殊字符转义,th:utext不会转义 |
th:attr | 为标签中的任意属性设置,可以一次设置多个属性 |
th:* | 为html指定的属性设值,一次设置一个 |
th:alt-title | 同时为alt与title属性赋值 |
th:lang-xmllang | 同时为lang、xml:lang属性赋值 |
th:fragment | 定义模板片段 |
th:insert | 将被引用的模板片段插入到自己的标签体中 |
th:replace | 将引用的模板片段替换掉自己 |
th:include | 类似于th:insert,而不是插入片段,它只插入此片段内容 |
th:remove | 删除模板中的某些代码片段 |
th:each | 迭代数据,如数组、List、Map等 |
th:if | 条件为true时,显示模板片段,否则不显示 |
th:unless | 条件为false时,显示模板片段,否则不显示 |
th:case | 配合th:switch使用 |
th:with | 定义局部变量 |
th:inline | 禁用内联表达式,内联js,内联css |
设置任何属性值 th:attr
经过模板处理之后,可以给任意属性赋值
th:attr提供了更改标签属性值的能力,th:attr使用比较少,因为他的使用比较难,语法不优雅,对于标签的特定属性,请使用th:value,th:action,th:href,th:class,th:src,th:onclick等等
<form action="/hello.html" method="post" th:attr="action=${myaction}">
账号:<input type="text" name="username"><br/>
密码:<input type="text" name="pwd"><br/>
<input type="submit" value="登录" th:attr="value=${mytext}">
</form>
<head>
<script type="text/javascript">
function fun1(){
alert("button click");
}
</script>
</head>
<form action="/hello.html" method="post" th:attr="action=${myaction}">
账号:<input type="text" name="username"><br/>
密码:<input type="text" name="pwd"><br/>
<input type="button" value="登录" th:attr="οnclick='fun1()',value=${mytext}">
</form>
这样更直接方便
<form th:action="@{/user/listuser}" method="get">
username:<input type="text" value="" name="username"><br/>
password:<input type="text" value="" name="pwd"><br/>
<input type="submit" th:value="${mytext}">
</form>
同时设置多个值
<img th:src="@{/image/im1.jpg}" th:alt-title="我的图片" />
<head th:lang-xmllang="en">
</head>
alt 属性是一个必需的属性,它规定在图像无法显示时的替代文本。
boolean属性
HTML具有布尔属性的概念,例如readonly,还有checkbox的“checked”,这个属性不赋值,没有值的属性意味着该值为“true”
也可以使用属性名本身表示true,即checked=“checked”
model.addAttribute("selected",true);
model.addAttribute("unselected",false);
<input type="checkbox" value="游泳" th:checked="${selected}">游泳
<input type="checkbox" value="骑行" th:checked="${unselected}">骑行
设置标签体文本
th:text
th:utext
循环th:each
th:each处理循环,类似jstl中的<c:foreach>
特点:
①循环的对象如果是null,不存在则不循环
②循环包含自身和标签内全部内容
③可以遍历的对象:
数组
任何实现java.util.Iterable接口的对象
Enumeration枚举
实现Map接口对象
语法格式:
<tr th:each="成员遍历:${表达式}">
<td th:text="${成员}">列</td>
</tr>
使用th:each时,Thymeleaf提供了一种用于跟踪迭代状态的机制:状态变量。状态变量在每个th:each属性中定义,并包含以下数据:
①index属性:当前迭代索引,从0开始
②count属性:当前的迭代计数,从1开始
③size属性:迭代变量中的元素的总量
④current属性:每次迭代的iter变量,即当前遍历到的元素
⑤even/odd布尔属性:当前的迭代是偶数还是奇数
⑦first布尔属性:当前的迭代是否是第一个迭代
⑧last布尔属性:当前的迭代是否是最后一个迭代
<tbody>
<tr th:each="mystu:${students}">
<td th:text="${mystu.id}"></td>
<td th:text="${mystu.name}"></td>
<td th:text="${mystu.age}"></td>
</tr>
</tbody>
<p th:each="m:${stumap}">
<span th:text="${m.key}"></span>
<span th:text="${m.value}"></span>
</p>
<ul th:each="lm:${listmap}">
<li th:each="entry:${lm}"th:text="${entry.key}"></li>
<li th:each="entry:${lm}"th:text="${entry.value}"></li>
</ul>
<select>
<option value="0">请选择</option>
<option th:each="cm:${citys}" th:value="${cm.key}" th:text="${cm.value}" th:selected="${cm.value} eq ${choice}">城市</option>
</select>
<tr th:each="stu,loopStatus:${stulist}">
<td th:text="${loopStatus.count}+'/'+${loopStatus.size}"></td>
<td th:text="${stu.id}">学号</td>
<td th:text="${stu.name}">姓名</td>
<td th:text="${stu.age}">年龄</td>
<td th:text="${stu.className}">班级</td>
<td th:text="${loopStatus.odd}?'奇数行':'偶数行'"></td>
<td th:text="${loopStatus.odd}"></td>
</tr>
判断th:if和th:unless
th:if当条件满足时,显示代码片段,条件常用boolean表示,true满足,反之不满足
thymeleaf中,true不是唯一满足条件
1)如果表达式结果为布尔值,则为true或者false
2)如果表达式的值为null,th:if将判断此表达式为false
3)如果值是数字,为0时,判断为false;不为零时,判定为true
4)如果值是String,值为”false“、”off”、“no”时,判定为false,否则判断为true,字符串为空时,也判断为true
5)如果值不是布尔值、数字、字符或字符串的其它对象,只要不为null,则判断为true
th:unless是不满足条件显示代码片段,类似java中if的else部分
模板使用
模板就是公共资源,可以多次重复使用的内容,经常把页眉、页脚、菜单做成模板,在各个其它页面使用
模板使用,先定义再使用,可以在当前页面定义模板,也可在其他页面中定义模板
1)定义模板语法
<div th:fragment="模板名称">
模板内容
</div>
2)引用模板
①把模板插入到当前位置
<div insert="模板所在文件名称::模板名称">
其他内容
</div>
②用模板替换当前标签内容
<div replace="模板所在文件名称::模板名称">
其他内容
</div>
③模板内容添加到当前标签
<div include="模板所在文件名称::模板名称">
其他内容
</div>
3)模板引用语法
①:模板所在文件名称::模板名称
②:~{模板所在文件名称::模板名称}
4)模板作为函数形式使用
<div th:fragment="funtpl(one,two)">
<p th:text="'hello' + ${one} + '-' + ${two}"></p>
</div>
th:insert,th:replace使用funtpl模板,可以传入值
<div th:replace="frag/footer::funtpl(one='张三',two='李四')">
我是参数模板
</div>
5)删除模板
th:remove=“删除范围值”
①all:删除包含标签及其所有子项
②body:不删除包含标签,但删除所有的子项
③tag:删除包含标签,但不要删除其子项
④all-but-first:删除第一个子项以外的其他所有子项
⑤none:什么也不做,该值对于动态计算有用,null也会被视为none
<div th:insert="::course">
使用当前页面定义的模板
</div>
<div th:insert="~{::course}">
使用当前页面中的定义的模板
</div>
#表示id值
<p id="tplId">
这是我们使用的id定义的模板
</p>
<p>
使用dom对象的id来引用模板
</p>
<div th:insert="::#tplId">
</div>
th:inline使用
需要在thymeleaf表达式写到标签体中,而不是标签内,可以使用内联语法
1)[[…]]或[(…)]内联表达式,任何在th:text或th:utext属性中使用的表达式都可以出现在[[]]或[()]中使用
[[…]]等价于th:text;[(…)]等价于th:utext
2)禁用内联<p th:inline=“none”>原样输出的内容</p>
3)使用javascript内联
<script type=“text/javascript” th:inline=“javascript”>
<script type="text/javascript" th:inline="javascript">
var jsname=[[${name}]];
console.log("jsname:" + jsname)
var stulist=[[${students}]];
for(var i=0;i<stulist.length;i++){
console.log("i="+i+","+stulist[i].name);
}
</script>
<body>
<p th:text="${name}">
我是常用写法
</p>
<p>
内联语法:[[${name}]]
</p>
</body>
th:with局部变量
th:with=“变量名1=值1,变量名2=值2”,定义的变量只在当前标签内有效
工具类对象
1)#{execInfo}
:模板信息
${#execInfo.templateName}
模板名称
${#execInfo.templateMode}
模板的处理模式
2)#uis
处理url/uri编码解码
${#uris.escapePath(uri)}
编码
${#uris.escapePath(uri,encoding)}
指定编码转码
${#uris.unescapePath(uri)}
解码
${#uris.unescapePath(uri,encoding)}
指定编码解码
3)#dates:java.util.Date对象的实用程序方法。可以操作数组、set、list
常用方法
${#date.format(date,'dd/MMM/yyyy HH:mm')}
${#dates.arrayFormat(datesArray,'dd/MMM/yyyy HH:mm')}
${#dates.listFormat(datesList,'dd/MMM/yyyy HH:mm')}
${#dates.setFormat(dateSet,'dd/MMM/yyyy HH:mm')}
4)#numbers:数字对象的实用程序方法
${#numbers.formatInteger(num,size)}
num表示被格式的数字,size表示整数位最少保留几位
5)#string String工具类,就是字符串工具类
${#strings.toUpperCase(name)}
大写
${#strings.toLowerCase(name)}
小写
${#strings.arrayJoin(namesArray,',')}
连接,合并
${#strings.arraySplit(nameStr,',')}
分隔
${#strings.indexOf(name,frag)}
查找
${#strings.substring(name,3,5)}
取子串
${#strings.contains(name,'ez')}
是否有子串
${#strings.isEmpty(name)}
空判断
内置对象
#request,就是javax.servlet.http.HttpServletRequest
#session,就是javax.servlet.http.HttpSession
#servletContext,直接访问与当前请求关联的javax.servlet.ServletContext对象
thymeleaf在web环境中,有一系列的快捷方式用于访问请求参数、会话属性等应用属性
param,request,session访问它们而无需#
param:用于检索请求参数
快捷对象param,request,application使用,不需要#
param参数集合
获取数组第0个参数值:[[${param.foo[0]}]]
获取数组第1个参数值:[[${param.foo[1]}]]
请求中参数数量:[[${param.size()}]]
请求中userid参数值:[[${param.userid}]]
判断请求是否有指定参数:[[${param.containsKey(‘name’)}]]
session:用于获取session属性。与param同理,只是作用域不同而已
获取session指定的key的value:[[${session.sessionAttr}]]
session中key的数量:[[${session.size()}]]
application:用于获取应用程序或servlet上下文属性,与param同理
获取ServletContext中的数量:[[${application.contextAttr}]]
获取ServletContext中key的数量:[[${application.size()}]]
vletContext对象
thymeleaf在web环境中,有一系列的快捷方式用于访问请求参数、会话属性等应用属性
param,request,session访问它们而无需#
param:用于检索请求参数
快捷对象param,request,application使用,不需要#
param参数集合
获取数组第0个参数值:[[${param.foo[0]}]]
获取数组第1个参数值:[[${param.foo[1]}]]
请求中参数数量:[[${param.size()}]]
请求中userid参数值:[[${param.userid}]]
判断请求是否有指定参数:[[${param.containsKey(‘name’)}]]
session:用于获取session属性。与param同理,只是作用域不同而已
获取session指定的key的value:[[${session.sessionAttr}]]
session中key的数量:[[${session.size()}]]
application:用于获取应用程序或servlet上下文属性,与param同理
获取ServletContext中的数量:[[${application.contextAttr}]]
获取ServletContext中key的数量:[[${application.size()}]]