前言:
最近在写一个SpringBoot的博客系统,使用的是Thymeleaf模板,所以大致学习了一下其一些常用的点,这里记录一下,以后会不断补充。
参考自:https://www.cnblogs.com/msi-chen/p/10974009.html
自动配置
自动给我们默认分配了模版的前缀和后缀,我们只需要按部就班的将模版丢进去即可
如果需要修改自动配置的前后缀,可以在配置文件中如(application.properties或application.yml)修改,如果使用application.properties,那么直接使用自动配置类中的prefix加要修改的属性值修改即可,如
spring.thymeleaf.DEFAULT_PREFIX=classpath:/static
常用语法
变量
Thymeleaf通过${}来获取model中的变量,注意这不是el表达式,而是ognl表达式,但是语法非常像。
示例:
控制器:
@GetMapping("/test")
public String test(Model model) {
// 这里我模仿从数据库中取到的type用作示例
Type type = new Type();
type.setTypeName = "Java";
model.addAttribute("type",type);
return "demo";
}
前台部分demo.html:
...
<!--感觉跟el表达式差不多的。区别在于,我们的表达式写在一个名为:th:text的标签属性中,这个叫做指令-->
<div class="item" th:text="${type.typeName}">错误日志</div>
...
这里我省略了很多无关紧要的,然后这个div中显示的就是我控制器中加入model的数据type的typeName了。
这里讲下指令吧:
Thymeleaf崇尚模板是纯正的html代码,脱离模板引擎,在纯静态环境也可以直接运行。现在如果我们直接在html中编写 ${}这样的表达式,显然在静态环境下就会出错,这不符合Thymeleaf的理念。
Thymeleaf中所有的表达式都需要写在"指令"中,指令是HTML5中的自定义属性,在Thymeleaf中所有指令都是以th:开头。因为表达式${user.name}是写在自定义属性中,因此在静态环境下,表达式的内容会被当做是普通字符串,浏览器会自动忽略这些指令,这样就不会报错了。
如果我们不经过SpringMVC,而是直接用浏览器打开编写的页面:在静态环境下,th指令不会被识别,但是也不会报错,而是显示div标签的缺省默认值:“错误日志”
指令的设计,正是Thymeleaf的高明之处,也是它优于其它模板引擎的原因。动静结合的设计,使得无论是前端开发人员还是后端开发人员可以完美契合。
另外,th:text指令出于安全考虑,会把表达式读取到的值进行处理,防止html的注入。
例如,<p>你好</p>
将会被格式化输出为
l
t
;
p
lt;p
lt;pgt;你好
l
t
;
/
p
lt;/p
lt;/plt;。
如果想要不进行格式化输出,而是要输出原始内容,则使用th:utext来代替。
变量的语法糖
刚才获取变量值,我们使用的是经典的对象.属性名方式。但有些情况下,我们的属性名可能本身也是变量,怎么办?
ognl提供了类似js的语法方式:
例如:${user.name} 可以写作${user['name']}
接下来讲的是自定义变量:
先看原始示例:
<h2>
<p>Name: <span th:text="${user.name}">Jack</span>.</p>
<p>Age: <span th:text="${user.age}">21</span>.</p>
<p>friend: <span th:text="${user.friend.name}">Rose</span>.</p>
</h2>
是不是觉得比较麻烦,对于这种都是来自一个变量的属性,有另一种简便的方法:
<h2 th:object="${user}">
<p>Name: <span th:text="*{name}">Jack</span>.</p>
<p>Age: <span th:text="*{age}">21</span>.</p>
<p>friend: <span th:text="*{ufriend.name}">Rose</span>.</p>
</h2>
首先在 h2上 用 th:object="${user}"获取user的值,并且保存。
然后,在h2内部的任意元素上,可以通过 *{属性名}的方式,来获取user中的属性,这样就省去了大量的user.前缀了。
方法调用
这个我暂时没有碰到,暂不总结。
内置对象
Thymeleaf中提供了一些内置对象,并且在这些对象中提供了一些方法,方便我们来调用。获取这些对象,需要使用#对象名来引用。和jsp类似,有session、servletContext、request等,如:
第一种:一些环境相关对象
对象 | 作用 |
---|---|
#ctx | 获取Thymeleaf自己的Context对象 |
#requset | 如果是web程序,可以获取HttpServletRequest对象 |
#response | 如果是web程序,可以获取HttpServletReponse对象 |
#session | 如果是web程序,可以获取HttpSession对象 |
#servletContext | 如果是web程序,可以获取HttpServletContext对象 |
第二种:Thymeleaf提供的全局对象
对象 | 作用 |
---|---|
#dates | 处理java.util.date的工具对象 |
#calendars | 处理java.util.calendar的工具对象 |
#numbers | 用来对数字格式化的方法 |
#strings | 用来处理字符串的方法 |
#bools | 用来判断布尔值的方法 |
#arrays | 用来护理数组的方法 |
#lists | 用来处理List集合的方法 |
#sets | 用来处理set集合的方法 |
#maps | 用来处理map集合的方法 |
我分别举个例子吧,不过现在还是不太清楚什么时候加#,emmm,后面改进吧:
先看获取session中的值(另外平常放置于ModelAndView,Model,Map,ModelMap中的数据都存在request,默认是从request中取数据的,所以request的数据不用加request前缀。)
<div class="text">
<img th:src="@{${session.user.headImage}}"class="ui avatar image" /><span th:text="${session.user.nickName}">LSY</span>
</div>
${session.user.headImage}
和${session.user.nickName}
这个就是获取session中的值(不过这里好像不用加#)
再看全局对象#strings的示例吧:
<div th:unless="${#strings.isEmpty(message)}" th:text="${message}">用户名和密码错误</div>
这里先不管th:unless,${#strings.isEmpty(message)}就是判断message是不是空的。
拼接普通字符串与对象值
我们经常会用到普通字符串与表达式拼接的情况:
<span th:text="'欢迎您:' + ${user.name} + '!'"></span>
字符串字面值需要用’’,拼接起来非常麻烦,Thymeleaf对此进行了简化,使用一对|即可:
<span th:text="|欢迎您:${user.name}|"></span>
运算
需要注意:${}
内部的是通过OGNL表达式引擎解析的,外部的才是通过Thymeleaf的引擎解析,因此运算符尽量放在${}
外进行。
算术运算
支持的算术运算符:+ - * / %
<span th:text="${user.age}"></span> //21
<span th:text="${user.age}%2 == 0"></span> //false
比较运算
支持的比较运算:>, <, >= and <= ,但是>, <不能直接使用,因为xml会解析为标签,要使用别名。
注意 == and !=不仅可以比较数值,类似于equals的功能。
可以使用的别名:gt (>), lt (<), ge (>=), le (<=), not (!). Also eq (==), neq/ne (!=).
条件运算
三元运算
<span th:text="${user.sex} ? '男':'女'"></span>
或这个类似的
<form action="#" method="post" th:object="${type}"
th:action="*{id}==null ? @{/admin/types} : @{/admin/types/{id}(id=*{id})} "
class="ui form">
...
默认值
有的时候,我们取一个值可能为空,这个时候需要做非空判断,可以使用 表达式 ?: 默认值简写:
<span th:text="${user.name} ?: '二狗'"></span>
当前面的表达式值为null时,就会使用后面的默认值。注意:?:之间没有空格。
还有一种我遇到的类似三元的:
<a href="#" th:href="@{/admin/blogs}"
class=" m-item item m-mobile-hide"
th:classappend="${n==1} ? 'active'"><i class="mini home icon"></i>博客</a>
th:classappend="${n==1} ? ‘active’"的意思为当n等于1时,给这个a标签加一个class属性active,否则不加。
循环
循环也是非常频繁使用的需求,我们使用th:each指令来完成:
假如有用户的集合:users在Context中。
<tr th:each="user : ${users}">
<td th:text="${user.name}">Onions</td>
<td th:text="${user.age}">2.41</td>
</tr>
${users} 是要遍历的集合,可以是以下类型:
Iterable,实现了Iterable接口的类
Enumeration,枚举
Interator,迭代器
Map,遍历得到的是Map.Entry
Array,数组及其它一切符合数组结果的对象
在迭代的同时,我们也可以获取迭代的状态对象:
<tr th:each="user,stat : ${users}">
<td th:text="${stat.count}">1</td>
<td th:text="${user.name}">Onions</td>
<td th:text="${user.age}">2.41</td>
</tr>
stat对象包含以下属性(我实际上使用好像也可以用iterStat,暂时没感觉到区别):
index,从0开始的角标
count,元素的个数,从1开始
size,总元素个数
current,当前遍历到的元素
even/odd,返回是否为奇偶,boolean值
first/last,返回是否为第一或最后,boolean值
逻辑判断
有了if和else,我们很简单的实现很多我们想要实现的功能。Thymeleaf中使用th:if 或者 th:unless ,两者的意思恰好相反。
<span th:if="${user.age} > 24">老油条</span>
如果表达式的值为true,则标签会渲染到页面,否则不进行渲染。
以下情况被认定为true:
表达式值为true
表达式值为非0数值
表达式值为非0字符
表达式值为字符串,但不是"false",“no”,“off”
表达式不是布尔、字符串、数字、字符中的任何一种
其它情况包括null都被认定为false
JS模板
模板引擎不仅可以渲染html,也可以对JS中的进行预处理。而且为了在纯静态环境下可以运行,其Thymeleaf代码可以被注释起来:
function loadata() {
// load() 方法通过 AJAX 请求从服务器加载数据,并把返回的数据放置到指定的元素中。
$("#table-container").load(/*[[@{/admin/blogs/search}]]*/"/admin/blogs/search",{
title : $("[name='title']").val(),
typeId : $("[name='typeId']").val(),
isRecommend : $("[name='recommend']").prop('checked'),
page : $("[name='page']").val()
}
);
}
如果需要在js中获取值,则如下所示:
<script th:inline="javascript">
// 这里最后部署的公网的域名这里要改
var serurl = /*[[#{blog.serurl}]]*/"127.0.0.1:8080";
var url = /*[[@{/blog/{id}(id=${blog.id})}]]*/"";
var qrcode = new QRCode("qrcode", {
text : serurl+url,
width : 110,
height : 110,
colorDark : "#000000",
colorLight : "#ffffff",
correctLevel : QRCode.CorrectLevel.H
});
// 当页面加载后请求评论数据
$(function () {
$("#comment-container").load(/*[[@{/comments/{id}(id=${blog.id})}]]*/"/comments/6");
})
</script>
获取值首先需要在script标签中声明th:inline="javascript“,然后通过这种方式var serurl = /*[[#{blog.serurl}]]*/"127.0.0.1:8080";
即/[[${}]]/就可以获取到了。
其他
还有一些指令如:
如果想在路径中加入参数呢?在thymeleaf中,使用()来实现这一功能,如下图,在路径的最后加入(id=xxx),thymeleaf会在前端渲染成?id=xxx。当多个参数时,以逗号分隔,写成(id=xxx,name=xxx)之类的形式即可。
<a href="#" th:href="@{/admin/types(page=${page.number}-1)}" class=" item" th:unless="${page.first}">上一页</a>
如果参数不仅仅是写在最后方,想写在路径中间,实现类似restful风格的效果,就可以看下面代码:
<td>
<a href="#" th:href="@{/admin/types/{id}/input(id=${type.id})}" class="ui mini teal basic button">编辑</a>
<a href="#" th:href="@{/admin/types/{id}/delete(id=${type.id})}" class="ui mini red basic button">删除</a>
</td>
然后怎么获取这两种得值呢?:
对于th:href="@{/admin/types(page=${page.number}-1)}"
即实际效果近似为/admin/types?page=3,这种方式其实就是表单(Get方式)提交的值的获取方式。在controller得获取方式是:
@GetMapping("/admin/types")
public String test(@RequestParam("page")String page){
return "demo";
}
对于th:href="@{/admin/types/{id}/input(id=${type.id})}"
这种,即实际效果近似为/admin/types/3 ,就如下所示“
@GetMapping("/admin/types/{id}/input")
public String test(@PathVariable("id") String id){
return "demo";
}
另外,springboot从前台获取值还有一种情况即前台传json值,此时需要使用@RequestBody接受,这个我没有尝试过,有兴趣得可以自行测试。这里推荐一个博主关于这个知识点得介绍:@RequestBody的使用
这个是用来做片段的替换的,先写一个_fragment.html,将一些要统一替换的片段写在_fragment.html中,并声明一些东西,就可以达到替换的效果。这里由于篇幅过长,暂不总结…
<head th:replace="_fragments :: head(~{::title})">
这个th:href就是起到运行后用这个路径替换本来的href,还有th:src功能也类似
<a href="#" th:href="@{/admin/blogs}"><a/>
<!-- 其中data-page这个就是自定义的属性,你可以定义成任何你想要的格式比如data-ceshi,然后在js文件中使用jquery的$(this).data('ceshi')获取到(另外,使用自定义属性,data-的后面尽量不要使用大写,可能会取不到值)
然后这里前面加th:attr=的原因是${page.number}-1这个值是thymeleaf中的,必须加这个data-page才能获取到数据-->
<a onclick="page(this)" th:attr="data-page=${page.number}-1" class=" item" th:unless="${page.first}">上一页</a>
<a onclick="page(this)" th:attr="data-page=${page.number}+1" class=" item" th:unless="${page.last}">下一页</a>
<script>
// 上一页下一页
function page(obj) {
$("[name='page']").val($(obj).data("page"));
loadata();
}
// 刷新局部
function loadata() {
// load() 方法通过 AJAX 请求从服务器加载数据,并把返回的数据放置到指定的元素中。
$("#table-container").load(/*[[@{/admin/blogs/search}]]*/"/admin/blogs/search",{
title : $("[name='title']").val(),
typeId : $("[name='typeId']").val(),
isRecommend : $("[name='recommend']").prop('checked'),
page : $("[name='page']").val()
}
);
}
$("#search-btn").click(function () {
loadata();
});
</script>
还有一个我觉得比较有用的就是<!--/*-->
和<!--*/-->
之间的内容,在静态时可以被当成普通html,动态时即运行在实际项目中时就会被thymeleaf模板注释掉。
等等。暂时先不写了,后面再完善吧。