SpringBoot之使用thymeleaf模板
背景
以前写前端页面都是通过jsp写的,但是由于SpringBoot最后会打成jar包,所以不支持jsp,而使用纯html页面会给开发带来非常大的困难,因此需要引入模板引擎
市面上的模板引擎非常多,譬如:jsp、Velocity、Freemarker、Thymeleaf
而SpringBoot推荐的是Thymeleaf模板
引入Thymeleaf
要想使用Thymeleaf模板首先应该先准备环境,而引入Thymeleaf的环境也非常简单,只需要引入相应的starter即可
在pom.xml中导入相关依赖
<!-- 引入Thymeleaf模板 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
使用Thymeleaf模板的规则
Themeleaf写在HTML页面中的,那么Thymeleaf要怎样才能识别我们写的HTML文件呢?我们可以就看下 ThymeleafProperties 类中的一段代码
@ConfigurationProperties(prefix = "spring.thymeleaf") public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8; public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html";
可以看到有两个属性分别是DEFAULT_PREFIX跟DEFAULT_SUFFIX,即默认的前缀跟默认的后缀,也就是说我们返回的字符串会被默认得到添加上前缀跟后缀,比如我们返回了一个login字符串,最后会被拼成classpath:/templates/login.html,也即是说我们只要将我们的HTML页面放到类路径下的templates目录下就能够被Thymeleaf渲染
基本使用
上面已经讨论了只要我们将我们的HTML页面放到类路径下的templates目录下就可以被Thymeleaf渲染,那么怎样去使用它呢?
首先我们需要导入Thymeleaf的名称空间,这样做的目的是能够在使用Thymeleaf语法的时候有语法提示
<html xmlns:th="http://www.thymeleaf.org">
之后就可以在HTML页面里面使用Thymeleaf语法了
<!-- th:text: 将div里面的内容替换 --> <div th:text="${hello}"></div>
Thymeleaf语法规则
th语法
在Thymeleaf模板中也有许多th标签,它比较类似于JSTL标签,能够帮我们完成很多诸如循环、判断等功能,不过他们是"寄生"在HTML标签上的
下图是相关的th标签以及它们之间的优先级关系
th:fragment & th:insert & th:replace & th:include
这几个标签时引用公共片段的时候使用的,例如在网页上的某一个或几个部分是不变的,那么为了减少代码量,就可以将这些片段抽取出来做成公共片段,而抽取的公共片段用th:fragment来声明,引入的时候用th:insert、th:replace或th:include引入即可
1、抽取公共片段
将相同的部分抽取出去
<div th:fragment="copy"> © 2011 The Good Thymes Virtual Grocery </div>
2、引入公共片段
<div th:insert="~{footer :: copy}"></div>
在要引入的地方将这些公共片段引入,而引入的方式有两种
①、 ~{templatename::selector}:模板名::选择器
- 模板名:即公共片段放置的文件路径
- 选择器:即公共片段所在标签的id,选择器的写法为 #idName
②、 ~{templatename::fragmentname}:模板名::片段名
- 模板名:依旧是公共片段放置的文件路径
- 片段名:即th:fragment后面跟的名字
介绍了引入片段的两种方式后,接下来就要介绍引入片段的三个标签了
- th:insert:会将整个公共片段插入到所引入的标签里面
- th:replac:将所在的标签替换成公共标签
- th:include:将所在的标签替换成公共片的最外层标签,也就是将公共片段的最外层标签去掉插入到所映入的标签中
下面分别对这三个标签的效果进行演示,引入之前的公共片段
<body> ... <div th:insert="footer :: copy"></div> <div th:replace="footer :: copy"></div> <div th:include="footer :: copy"></div> </body>
插入之后的效果
<body> ... <div> <footer> © 2011 The Good Thymes Virtual Grocery </footer> </div> <footer> © 2011 The Good Thymes Virtual Grocery </footer> <div> © 2011 The Good Thymes Virtual Grocery </div> </body>
3、引入片段时传入参数
在公共片段中添加参数(通过小括号的方式添加参数)
<div th:replace="commons/bar::#sidebar(activeUri='emps')"></div>
然后在引入的时候就可以获取在公共片段中设置的值(注意:这个值可以设置到th:fragment标注的标签的里面使用)
<nav th:fragment="topbar"> <a th:class="${activeUri=='main' ? 'nav-link active' : 'nav-link'}"></a> </nav>
th:each
遍历标签,用在标签上可以循环指定次数的当前标签
<tr th:each="item : ${items}"> <td th:text="${item.name}"></td> <td th:text="${item.age}"></td> </tr>
th:if
条件判断,如果判断成立,那么显示所在标签,如果判断不成立,不加载当前标签
<div th:if="${param == 0}"></div>
如果param等于0,那么div显示,否则div不会被加载
th:unless
跟th:if的判断相反,即如果结果正确当前的标签不会加载,反之加载
<div th:unless="${session.user != null}"></div>
如果session.user为空,结果为真,则div不会显示。否则加载
th:switch & th:case
显示switch的值跟case对应的标签
<div th:switch="${session.user}"> <p th:case="'jinxin'">call me jinxin</p> <p th:case="'timo'">call me timo</p> </div>
switch里面session.user的值是哪一个就显示哪一个p标签
th:object
替换对象,直接用属性名调用对象里面的属性
<div th:object="${session.user}"> <p th:text="*{name}"></p> <p th:text="*{age}"></p> </div>
不用通过对象点出属性的方式调用,直接写属性即可
th:with
th:with可以用来定义局部变量
<div th:with="User = ${session.user}"> <p th:text="User.name"></p> </div>
th:attr & th:attrprepend & th:attrappend
th:attr可以设置属性的值,还可以配合"|"对属性值拼接,还可以设置多个属性的值,多个属性之间用逗号隔开。而th:attrprepend可以给一个属性前面附加值,th:attrappend给一个属性后面附加值,例如在给class设置值的时候,class已经有一个类名为con了,还想再设置一个style的类名,就可以使用这两个标签添加
<!-- th:attr --> 1、写死的单个属性值添加 th:attr="src=@{/hello(l='jjj')}" 2、写死的多个属性值添加 th:attr="src=@{/hello(l='jjj')}, class=con" 3、当一个属性的值较多的时候可以用 | th:attr="class=|btn btn-group|" <!-- th:attrappend --> th:attrappend="class=${' ' + con}" /> <!-- th:attrprepend --> th:attrprepend="class=${cssStyle+' '}"
th:value & th:href & th:title & ...
th后面跟上html标签自带的属性可以替换掉原来对应的属性
th:text & th:utext
改变当前标签体里面的内容,th:text会转义特殊字符,th:utext不会转义
还可以在标签体里面添加[[ ]]或者[( )]来代替th:text跟th:utext
<div th:text="${msg}"></div> <div th:utext="${msg}"></div> [[ ${msg} ]] [( ${msg} )]
th:remove
th:remove可以删除标签,它有如下几个属性
- all:删除包含标签和所有的孩子。
- body:不包含标记删除,但删除其所有的孩子。
- tag:包含标记的删除,但不删除它的孩子。
- all-but-first:删除所有包含标签的孩子,除了第一个。
- none:什么也不做。
表达式语法
变量表达式:${}
用于获取变量的值,底层是OGNL
${}能够获取那些值?
1、获取对象的属性、调用方法
2、还能使用内置的基本对象
- #ctx :当前的上下文对象
- ${#ctx.locale}
- ${#ctx.variableNames}
- ${#ctx.request}
- ${#ctx.response}
- ${#ctx.session}
- ${#ctx.servletContext}
- #vars:当前上下文里面的变量值
- #locale:区域信息
- ${#locale.country}
- #request:request对象
- ${#request.getAttribute('foo')}
- ${#request.getParameter('foo')}
- ${#request.getContextPath()}
- ${#request.getRequestName()}
- ...
- #response:response对象
- #session:session对象
- ${#session.getAttribute('foo')}
- ${#session.id}
- ${#session.lastAccessedTime}
- ...
- #servletContext:servletContext对象
- ${#servletContext.getAttribute('foo')}
- ${#servletContext.contextPath}
- ...
3、内置的一些工具对象
- #execInfo
- #messages
- #uris
- #conversions
- #dates
- #calendars
- #numbers
- #strings
- #objects
- #bools
- #arrays
- #lists
- #sets
- #maps
- #aggregates
- #ids
变量的选择表达式:*{}
和${}表达式效果一样,但是有一个补充功能
我们如果需要打印一个对象中的属性,会像下面这样:
<div> <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>. </p> <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p> </div>
上面可以看到从session中取出user对象然后一个一个的打印里面的属性,这样有点麻烦,那么这时候就可以利用*来代替上面的session.user对象,即:
<div th:object="${session.user}"> <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div>
Message表达式:#{}
获取国际化内容
Link URL表达式: @{...}
用来定义URL的,不需要再在URL后面通过问号去拼参数了,而是将所有的参数写在小括号里面,多个参数用逗号隔开
@{/order/process(execId=${execId}, execType='FAST')}
Fragment表达式: ~{...}
片段引用的表达式
<div th:insert="~{commons :: main}">...</div>