SpringBoot项目默认不是JSP,那如何来实现我们的动态页面呢?SpringBoot推荐模板引擎Thymeleaf。其实JSP也属于一种模板引擎,比较常用的还有freemaker。模板引擎非常多,道理都一样
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
spirngboot默认配置了Thymeleaf
也可以自己写
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
mode: HTML
encoding: UTF-8
如果希望客户端可以直接访问 HTML 资源,将这些资源放置在 static 路径下即可,否则必须通过 Handler 的后台映射才可以访问静态资源。
注意使用时一定别忘了导入命名空间
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
body>
html>
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<p th:text="${msg}">p>
<p th:text="'提示:'+${msg}">p>
<p> 提示:[[${person.name}]] p>
body>
html>
是引入thymeleaf的命名空间,必须。
可以在原来的任何属性前面加上前缀th:*
来表示thymeleaf的定义。data-th-*
效果一样。
在标签内拼接字符串比较麻烦,可以在里面通过[[]]来显示跟拼接
在classpath:templates
路径下创建html文件作为显示页面,一定要放在此路径,并且一定要是html格式,比如hello.html
Thymeleaf 提供了非常丰富的标准表达式语法,总共有 8 大类:
简单表达式
字面值
文本操作
算术运算
布尔运算
比较和相等
条件运算
无操作符
语法 | 名称 | 描述 | 作用 |
---|---|---|---|
${…} | Variable Expressions | 变量表达式 | 取出上下文变量的值 |
*{…} | Selection Variable Expressions | 选择变量表达式 | 取出选择的对象的属性值 |
#{…} | Message Expressions | 消息表达式 | 使文字消息国际化,I18N |
@{…} | Link URL Expressions | 链接表达式 | 用于表示各种超链接地址 |
~{…} | Fragment Expressions | 片段表达式 | 引用一段公共的代码片段 |
使用th:with
属性可以定义局部变量
<span th:with="myName='dyk'">
<p th:text="${myName}" >p>
span>
同时定义多个局部变量时,用英文,
号分隔开
<p th:with="name=${user.name},age={user.age}">
......
p>
注释的代码块会在引擎解析的时候抹去。
和原来jsp的el表达式类似
package com.blb.springbootmybatis.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class ThymeleafController {
@GetMapping("/test1")
public ModelAndView test(){
ModelAndView modelAndView=new ModelAndView();
modelAndView.addObject("name","dyk");
modelAndView.setViewName("test");
return modelAndView;
}
}
<div th:text="${name}">div>
<div th:text="'我的名字是'+${name}+'年龄是'+18">div>
单引号加+号拼接
或者直接双引号里面使用| 拼接的内容 |
<div th:text="|我叫${name}|">div>
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div th:text="${name}">div>
<div th:text="'我的名字是'+${name}+'年龄是'+18">div>
<div th:text="|我叫${name}|">div>
body>
html>
变量表达式${}
是面向整个上下文的,而选择变量表达式*{}
的上下文是父标签(th:object
)所选择的对象。
// Person bean
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Person {
private String name ;
private String sex ;
private Integer age ;
}
// controller
@RequestMapping("/hello")
public String welcome(Model model){
Person person = new Person("dyk","男",18);
model.addAttribute("person",person);
return "hello" ;
}
<span th:object="${person}">
<p th:text="*{name}">p>
<p th:text="*{sex}">p>
<p th:text="*{age}">p>
span>
<span >
<p th:text="${person.name}">p>
<p th:text="${person.sex}">p>
<p th:text="${person.age}">p>
span>
内联表达式允许我们直接在 HTML 文本中使用标准表达式,而不需要使用th:*
标签属性
[[]]
相当于th:text
,对含有 HTML 标签的内容自动进行字符转义
<p>[[${msg}]]p>
[()]
相当于th:utext
,对含有 HTML 标签的内容不进行字符转义
<p>[(${msg})]</p>
我们已经了解到,使用[[]]
和[()]
语法可以直接在 HTML 文本中使用标准表达式,如果想要使用更多高级的功能,需要使用th:inline
属性来激活,它的取值如下
值 | 描述 |
---|---|
none | 禁止内联表达式,可以原样输出 [[]] 和 [()] 字符串 |
text | 文本内联,可以使用 th:each 等高级语法 |
css | 样式内联,如
|
javascript | 脚本内联,如:
|
none
<p th:inline="none">[[asdfsafd]]p>
text
<p th:inline="text">[[${msg}]]p>
css
<style th:inline="css">
body {
background-color:[[${bgColor}]];
}
style>
所谓字面值,首先它不是一个变量,它是一个具体的确切的值,通常这些值是比较简单的,例如:18
、'welcome'
等,它们没有名称,以至于我们只能用值来称呼它们,因此我们称其为字面值
<p th:text="'Welcome to bailiban...'">p>
<p th:text="2019">p>
<p th:text="2019 + 1">p>
<p th:text="true">p>
<p th:text="1 > 2">p>
<p th:text="1 > 2 ? '是' : '否'">p>
<p th:text="${user == null}">p>
不管是字面值还是表达式的结果,我们都可以使用+
符号将它们连接起来:
<p th:text="'Welcome to ' + ${msg} + '!'">p>
符号||
可以用来将字面值和表达式包裹起来,这样就能方便的替换变量的值,而不需要使用+
连接符:
<p th:text="|Welcome to ${msg} !|">p>
支持+
(加)、-
(减)、*
(乘)、/
(除)、%
(模)运算。
<p th:text="4 + 2">p>
<p th:text="4 - 2">p>
<p th:text="4 * 2">p>
<p th:text="4 / 2">p>
<p th:text="4 % 2">p>
<p th:text="${page + 1}">p>
<p th:text="${page} + 1">p>
支持and
(且)、or
(或)、!
(非)、not
(非)运算
<p th:text="${true and true}">p>
<p th:text="${true or false}">p>
<p th:text="${!true}">p>
<p th:text="${not false}">p>
支持<
(lt
)、>
(gt
)、<=
(le
)、>=
(ge
)、==
(eq
)、!=
(ne
)
<p th:text="${person.age < 60}">p>
<p th:text="${person.age <= 60}">p>
<p th:text="${person.age > 18}">p>
<p th:text="${person.age >= 18}">p>
<p th:text="${person.age == 18}">p>
<p th:text="${person.age != 18}">p>
(if) ? (then) : (else)
<input th:value="${name == 'dyk'? '是':'不是'}"/>
<div th:text="${age >= 20? '青年':'少年'}">div>
<div th:text="${age ge 20? '青年':'少年'}">div>
<p >[[${person.age >= 18?'成年':'未成年'}]]p>
(value) ?: (defaultValue)
其中,value
非空(null)即真,条件为真时输出value
,否则输出defaultValue
。
<p th:text="${person.name}?:'用户名不能为空'">p>
也可以使用无操作符达到相同效果。_
表示显示标签体内的内容。
<p th:text="${person.name}?:_">用户名不能为空p>
在标签体中展示表达式评估结果的文本内容
<p th:text="${message}">Welcome to bailiban!p>
当它作为静态文件直接运行时,浏览器会自动忽略它不能识别的th:text
属性,而显示标签体的文本内容Welcome to bailiban!
当它作为模板文件运行在服务器端时,th:text
属性的具体值将会替换标签体的文本内容
utext
跟text
的区别是utext会解析html标签,而text
不会。
假设model.addAttribute("msg","welcome to bailiban ... ");
<p th:text="${msg}">p>
<p th:utext="${msg}">p>
在 Thymeleaf 模板文件中,你可以使用th:*
(或者使用th:attr
属性)来设置任意的 HTML5 标签属性的值。不仅如此,你还可以th:*-*
来同时为多个不同的标签属性设置相同的一个值,甚至你可以使用th:attrappend
和th:attrprepend
来追加新的值到现有的标签属性值中
这种方式是不被推荐的,了解一下就行。下面是用th:attr="href=..."
来设置标签href
属性的值
<a th:attr="href=@{https://www.google.com}">谷歌一下你就知道a>
th:attr
不够简洁,我们推荐下面的方式
<a th:href="@{https://www.google.com}">谷歌一下你就知道a>
其中的*
可以是HTML5中的任意属性
如果想要同时为标签的多个不同属性设置相同的一个值,可以使用th:*-*
的语法
<img src="logo.png" th:alt-title="LOGO图片">
它相当于:
<img src="logo.png" th:alt="LOGO图片" th:title="LOGO图片">
<!-- <button class="btn disable ">购买</button> -->
<button class="btn" th:attrappend="class=' disable '">购买</button>
<!-- <button class=" disable btn">购买</button> -->
<button class="btn" th:attrprepend="class=' disable '">购买</button>
在 HTML 中有些属性是布尔属性,布尔属性是指没有值的属性,如readonly
、checked
、selected
等。它们若存在那就意味着值为 true。 Thymeleaf 也允许我们通过th:*
(这里的*
表示任意的布尔属性) 来选择是否使用这些布尔属性
<input type="checkbox" th:checked="${remember}" /> 记住我
当${remember}
为null就不会默认选中,不为null则会默认勾选上
th:if 表示条件成立时显示内容
当表达式的评估结果为真时则显示内容,否则不显示
<div th:if="${name=='dyk'}" th:text="${name}">div>
<div th:if="${name=='dyk'}" >[[${name}]]div>
取值也可以不写在标签里面,通过两个中括号
th:unless 表示条件不成立时显示内容
th:unless
与th:if
判断恰好相反,当表达式的评估结果为假时则显示内容,否则不显示
<div th:unless="${name=='cb'}" th:text="${name}">div>
<div th:unless="${name=='cb'}">[[${name}]]div>
由于我存的name值是dyk不等于cb所以会取出来
多路选择语句,它需要搭配th:case
来使用:
@GetMapping("/switch")
public String switchTest(Model model){
model.addAttribute("gender","女");
return "test";
}
<div th:switch="${gender}">
<p th:case="女">女p>
<p th:case="男">男p>
<p th:case="*">未知p>
div>
<div th:switch="${person.sex}">
<p th:case="男">man</p>
<p th:case="女">girl</p>
</div>
遍历(迭代)的语法th:each="自定义的元素变量名称 : ${集合变量名称}"
<table border="1px solid #000">
<tr>
<th>idth>
<th>usernameth>
<th>passwordth>
<th>hobbyth>
<th>emailth>
<th>操作th>
tr>
<tr th:each="user:${users}">
<td th:text="${user.id}">td>
<td th:text="${user.username}">td>
<td th:text="${user.password}">td>
<td th:text="${user.hobby}">td>
<td th:text="${user.email}">td>
tr>
th>
table>
th:each
提供了一个用于跟踪迭代的状态变量,stat 状态变量的使用语法:th:each="自定义的元素变量名称, 自定义的状态变量名称 : ${集合变量名称}"
。 它包含以下几个属性 :属性 | 类型 | 描述 |
---|---|---|
index | int | 当前迭代的索引,从 0 开始 |
count | int | 当前迭代的计数,从 1 开始 |
size | int | 集合中元素的总个数 |
current | int | 当前的元素对象 |
even | boolean | 当前迭代的计数是否是偶数 |
odd | boolean | 当前迭代的计数是否是奇数 |
first | boolean | 当前元素是否是集合的第一个元素 |
last | boolean | 当前元素是否是集合的最后一个元素 |
<table border="1px solid #000">
<tr>
<th>idth>
<th>usernameth>
<th>passwordth>
<th>hobbyth>
<th>emailth>
<th>操作th>
tr>
<tr th:each="user,stat:${users}" th:style="'background-color:'+@{${stat.odd}?'#F2F2F2'}">
<td th:text="${user.id}">td>
<td th:text="${user.username}">td>
<td th:text="${user.password}">td>
<td th:text="${user.hobby}">td>
<td th:text="${user.email}">td>
<td>
<a href="/toAddPage">添加a>
<a href="/delete/${user.id}">删除a>
<a href="/toUpdatePage/${user.id}">修改a>
td>
tr>
th>
table>
Thymeleaf 对于 URL 的处理是通过 @{...}
进行处理,结合 th:href 、th:src
绝对地址
<a th:href="@{http://www.baidu.com}" th:text="baidu"></a>
相对地址
<!-- 不带参数 -->
<a th:href="@{hello2}" th:text="hello2"></a> <br/>
<!-- 带参数 -->
<a th:href="@{hello2(name=${person.name},password='123')}" th:text="hello2"></a> <br/>
()
括号内,参数之间用,
号隔开${}
引用<a th:href="@{http://www.baidu.com}">跳转a>
<a th:href="@{http://localhost:9090/index/url/{na}(na=${name})}">跳转2a>
<img th:src="${src}">
<div th:style="'background:url('+ @{${src}} +');'">
<br/>
<br/>
<br/>
div>
~{…}片段表达式主要用来引用一段可重复使用的代码片段
<div th:fragment="foot-copy" >
Copyright © 2012-2019 管理系统 - Version V1.1
</div>
<div th:insert="~{base/common::foot-copy}"></div>
base/common
是文件路径,foot-copy
是定义的th:fragment
值,用::
分割。~{}
可以省略。
除了使用th:fragment
还可以通过选择器来引用。
base/common.html
<div class="foot-copy" >
Copyright © 2012-2019 管理系统 - Version V1.1
</div>
<div th:insert="~{base/common::.foot-copy}"></div>
.foot-copy
是CSS选择器去匹配。
我们定义代码片段时还可以声明一组参数:
<div th:fragment="menu(menuName1, menuName2)">
<p th:text="${menuName1}">p>
<p th:text="${menuName2}">p>
div>
<div th:insert="~{base/common::menu('用户中心', '我的订单')}">div>
th:insert
跟th:replace
的区别?
他们都是用来使用代码片段, th:insert 如同插入的字面意思,将指定的代码片段插入主标签内 。 th:replace 如同替换的字面意思,将主标签替换为指定的代码片段。
对象 | 描述 |
---|---|
#ctx | 上下文对象 |
#vars | 同 #ctx,表示上下文变量 |
#locale | 上下文本地化(特定的地理区域)变量,可参考 java.util.Locale |
#request | HttpServletRequest 对象,可参考 javax.servlet.http.HttpServletRequest |
#response | HttpServletResponse 对象,可参考 javax.servlet.http.HttpServletResponse |
#session | HttpSession 对象,可参考 javax.servlet.http.HttpSession |
#servletContext | ServletContext 对象,可参考 javax.servlet.ServletContext |
#request
<p th:text="${#request.protocol}">p>
<p th:text="${#request.scheme}">p>
<p th:text="${#request.serverName}">p>
<p th:text="${#request.serverPort}">p>
<p th:text="${#request.method}">p>
<p th:text="${#request.requestURI}">p>
<p th:text="${#request.requestURL}">p>
<p th:text="${#request.servletPath}">p>
<p th:text="${#request.getAttribute('student').name}">p>
<p th:text="${#request.queryString}">p>
#response
<p th:text="${#response.status}">p>
<p th:text="${#response.bufferSize}">p>
<p th:text="${#response.characterEncoding}">p>
<p th:text="${#response.contentType}">p>
#session
<p th:text="${#session.id}">p>
<p th:text="${#session.lastAccessedTime}">p>
<p th:text="${#session.getAttribute('person').name}">p>
@GetMapping("/object")
public String object(HttpServletRequest request){
request.setAttribute("request","request对象");
request.getSession().setAttribute("session","session对象");
return "test";
}
<p th:text="${#request.getAttribute('request')}">p>
<p th:text="${#session.getAttribute('session')}">p>
<p th:text="${#locale.country}">p>
可以直接通过 # 访问。
对象 | 作用 |
---|---|
dates | java.util.Date 的功能方法 |
calendars | java.util.Calendar 的功能方法 |
numbers | 格式化数字 |
strings | java.lang.String 的功能方法 |
objects | Object 的功能方法 |
bools | 对布尔求值的方法 |
arrays | 操作数组的功能方法 |
lists | 操作集合的功能方法 |
sets | 操作集合的功能方法 |
maps | 操作集合的功能方法 |
@GetMapping("/util")
public String util(Model model){
model.addAttribute("name","zhangsan");
model.addAttribute("users",new ArrayList<>());
model.addAttribute("count",22);
model.addAttribute("date",new Date());
return "test";
}
<p th:text="${#dates.format(date,'yyyy-MM-dd HH:mm:sss')}">p>
<p th:text="${#dates.createToday()}">p>
<p th:text="${#dates.createNow()}">p>
<p th:text="${#strings.isEmpty(name)}">p>
<p th:text="${#lists.isEmpty(users)}">p>
<p th:text="${#strings.length(name)}">p>
<p th:text="${#strings.concat(name,name,name)}">p>
<p th:text="${#strings.randomAlphanumeric(count)}">p>