JSP的缺陷 #
- JSP就是一个Servlet ,生命周期:翻译,编译,加载,初始化,服务,销毁
- Servlet一定要放置在Servlet容器中才可以运行,浏览器不能直接解析
- JSP页面一般构成:HTML + CSS + JS + Java代码 + JSTL标记
- 由此的坏处:
- JSP必须要在Servlet容器解析成HTML,才可以返回到浏览器中(系统:不管是静态请求也好, 还是动态请求,都压到Tomcat服务器,这就可能导致Tomcat解决动态请求的能力有所降低)
- JSP必须要在Servlet容器解析成HTML,这就意味着百度,谷歌,以及其他的搜索引擎无法去收录
- JSP从2015年之前,就开始走向灭亡,取而代之的是,HTML + 模板引擎
模板引擎 #
- 使用符号或者自定义标记 + 网页中不变的东西 = 模板引擎
- 模板引擎的作用: 将页面中动态的内容,使用标记或某些符号,进行静态的替换。从而做到:浏览器认为整个网页都是静态的内容(进而可以做到:浏览器缓存HTML,Nginx等服务器缓存HTML) 从而提升系统的整合响应性能
- 常见的模板引擎**:Freemarker,thymeleaf,velocity**
Thymeleaf的特点 #
Thymeleaf 模板引擎具有以下特点:
- 动静结合:Thymeleaf 既可以直接使用浏览器打开,查看页面的静态效果,也可以通过 Web 应用程序进行访问,查看动态页面效果。
- 开箱即用:Thymeleaf 提供了 Spring 标准方言以及一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
- 多方言支持:它提供了 Thymeleaf 标准和 Spring 标准两种方言,可以直接套用模板实现 JSTL、 OGNL 表达式;必要时,开发人员也可以扩展和创建自定义的方言。
- 与 SpringBoot 完美整合:SpringBoot 为 Thymeleaf 提供了的默认配置,并且还为 Thymeleaf 设置了视图解析器,因此 Thymeleaf 可以与 Spring Boot 完美整合。
Thymeleaf的基本使用 #
Thymeleaf通常适用于前后端不分离的页面
1、创建SpringBoot应用
2、导入依赖
<!-- 导入thymeleaf的启动器依赖:完成对thymeleaf的全部支持,自动配置了对应视图解析器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
3、配置文件
# 指定模板所在的目录
spring.thymeleaf.prefix=classpath:/templates/
# 检查模板路径是否存在
spring.thymeleaf.check-template-location=true
# 后缀
spring.thymeleaf.suffix=.html
# 默认HTML
spring.thymeleaf.mode=HTML
# 是否缓存,开发环境true、生产环境false
spring.thymeleaf.cache=false
# 解析字符集编码
spring.thymeleaf.encoding=UTF-8
spring:
thymeleaf:
encoding: UTF-8
prefix: classpath:/templates/
mode: HTML
suffix: .html
4、html页面放在src/main/resources/templates下
html模板文件需要引入命名空间http://www.thymeleaf.org
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text=""></h1>
</body>
</html>
5、js、css等静态资源放在src/main/resources/static下
由于SpringBoot约定大于配置的特性,默认的静态文件目录为src/main/resources/static,也可以通过配置文件进行更换
注意:引入静态资源的时候不需要加static这一层路径
spring:
resources:
static-locations: classpath:/myStatic/
Thymeleaf语法规则 #
标准表达式 #
Thymeleaf 模板引擎支持多种表达式:
- 变量表达式:
${...} - 选择变量表达式:
*{...} - 链接表达式:
@{...} - 国际化表达式:
#{...} - 片段引用表达式:
~{...}
变量表达式 #
使用${}包裹的表达式被称为变量表达式,该表达式具有以下功能:
- 获取对象的属性和方法
${person.name}
- 使用内置的基本对象
#ctx:上下文对象#vars:上下文变量#locale:上下文的语言环境#request:HttpServletRequest 对象(仅在 Web 应用中可用)#response:HttpServletResponse 对象(仅在 Web 应用中可用)#session:HttpSession 对象(仅在 Web 应用中可用)${#session.getAttribute('map')}${session.map}
#servletContext:ServletContext 对象(仅在 Web 应用中可用)
- 使用内置的工具对象
- strings:字符串工具对象,常用方法有:equals、equalsIgnoreCase、length、trim、toUpperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等
${#strings.equals('ygang',name)}
- numbers:数字工具对象,常用的方法有:formatDecimal 等
- bools:布尔工具对象,常用的方法有:isTrue 和 isFalse 等
- arrays:数组工具对象,常用的方法有:toArray、length、isEmpty、contains 和 containsAll 等
- lists/sets:List/Set 集合工具对象,常用的方法有:toList、size、isEmpty、contains、containsAll 和 sort 等
- maps:Map 集合工具对象,常用的方法有:size、isEmpty、containsKey 和 containsValue 等
- dates:日期工具对象,常用的方法有:format、year、month、hour 和 createNow 等
th:text="${#dates.format(date, 'yyyy-MM-dd HH:mm:ss')}"
- strings:字符串工具对象,常用方法有:equals、equalsIgnoreCase、length、trim、toUpperCase、toLowerCase、indexOf、substring、replace、startsWith、endsWith,contains 和 containsIgnoreCase 等
选择变量表达式 #
选择变量表达式与变量表达式功能基本一致,只是在变量表达式的基础上增加了与 th:object 的配合使用。当使用 th:object 存储一个对象后,我们可以在其后代标签中使用选择变量表达式*{...}获取该对象中的属性,其中,*即代表该对象。
<div th:object="${user}" >
<p th:text="*{name}">name</p>
</div>
<!-- 等价于 -->
<div>
<p th:text="${user.name}">name</p>
</div>
链接表达式 #
不管是静态资源的引用,还是 form 表单的请求,凡是链接都可以用链接表达式 @{...}。
链接表达式的形式结构如下:
- 无参请求:
@{/xxx} - 有参请求:
@{/xxx(k1=v1,k2=v2)}
<link th:href="@{/asserts/css/signin.css}" rel="stylesheet">
国际化表达式 #
消息表达式一般用于国际化的场景。
th:text="#{msg}"
片段引用表达式 #
片段引用表达式用于在模板页面中引用其他的模板片段,该表达式支持以下 2 中语法结构:
-
推荐:
~{templatename::fragmentname} -
支持:
~{templatename::#id}-
templatename:模版名,Thymeleaf 会根据模版名解析完整路径:
/resources/templates/templatename.html,要注意文件的路径。 -
fragmentname:片段名,Thymeleaf 通过 th:fragment 声明定义代码块,即:
th:fragment="fragmentname" -
id:HTML 的 id 选择器,使用时要在前面加上 # 号,不支持 class 选择器。
-
通常情况下,
~{}可以省略
-
th属性 #
th:id #
替换 HTML 的 id 属性
th:text #
文本替换,转义特殊字符,也就是会显示html标签为文本
th:utext #
文本替换,不转义特殊字符,也就是会将html标签解析
th:object #
在父标签选择对象,子标签使用 *{…} 选择表达式选取属性值。
没有选择对象,那子标签使用选择表达式和 ${…} 变量表达式是一样的效果。
同时即使选择了对象,子标签仍然可以使用变量表达式。
th:value #
替换 value 属性
th:with #
局部变量赋值运算
<div th:with="isEvens = ${prodStat.count}%2 == 0" th:text="${isEvens}"></div>
th:style #
设置样式
th:onclick #
设置点击事件
th:each #
遍历,支持 Iterable、Map、数组等。
<table>
<tr th:each="m:${session.map}">
<td th:text="${m.getKey()}"></td>
<td th:text="${m.getValue()}"></td>
</tr>
</table>
对于遍历,也可以拿到遍历中的状态变量,如索引
<table>
<tr th:each="m,status:${session.map}">
<td th:text="${m.getKey()}"></td>
<td th:text="${m.getValue()}"></td>
</tr>
</table>
status有如下属性index:当前迭代对象的迭代索引,从0开始,这是索引属性;count:当前迭代对象的迭代索引,从1开始,这个是统计属性;size:迭代变量元素的总量,这是被迭代对象的大小属性;current:当前迭代变量;even/odd:布尔值,当前循环是否是偶数/奇数(从0开始计算);first:布尔值,当前循环是否是第一个;last:布尔值,当前循环是否是最后一个;
th:if #
根据条件判断是否需要展示此标签
th:unless #
和th:if判断相反,满足条件时不显示
th:switch #
与 Java 的 switch case语句类似,通常与 th:case 配合使用,根据不同的条件展示不同的内容
<div th:switch="${name}">
<span th:case="a">ygang</span>
<span th:case="b">top</span>
</div>
th:fragment #
模板布局,类似 JSP 的 tag,用来定义一段被引用或包含的模板片段
th:insert #
将使用 th:fragment 属性指定的模板片段(包含标签)插入到当前标签中。
th:replace #
将使用 th:fragment 属性指定的模板片段(包含标签)替换当前整个标签。
th:include #
将使用 th:fragment 属性指定的模板包含的内容(不包含标签)插入到当前标签中。
th:selected #
设置select 选择框选中
<select>
<option>---</option>
<option th:selected="${name=='a'}">
ygang
</option>
<option th:selected="${name=='b'}">
top
</option>
</select>
th:src #
替换 HTML 中的 src 属性
th:inline #
内联属性;
该属性有 text、none、javascript 三种取值,
在 <script> 标签中使用时,js 代码中可以获取到后台传递页面的对象
<script type="text/javascript" th:inline="javascript">
var name = [[${name}]];
alert(name)
</script>
th:action #
替换表单提交地址
内联表达式 #
[[…]]
#
相当于th:text
<p>The message is : [[${htmlContent}]]</p>
[(…)]
#
相当于th:utext
<p>The message is : [(${htmlContent})]</p>
th:inline #
| 值 | 描述 |
|---|---|
| none | 禁止内联表达式,可以原样输出 [[]] 和 [()] 字符串 |
| text | 文本内联,可以使用 th:each 等高级语法 |
| css | 样式内联,如:<style th:inline="css"> |
| javascript | 脚本内联,如:<style th:inline="javascript"> |
组件化开发 #
定义模板,在templates/commons.html中
<div th:fragment="fragment-name" id="fragment-id">
<span>公共页面片段</span>
</div>
引入模板
<!--片段名引入-->
<div th:insert="commons::fragment-name"></div>
<!--id选择器引入-->
<div th:insert="commons::#fragment-id"></div>
传参 #
定义模板,在templates/commons.html中
<div th:fragment="fragment-name(name,age)" id="fragment-id">
<span>公共页面片段</span>
</div>
引入模板
<!--片段名引入并传参-->
<div th:insert="commons::fragment-name(${name},18)"></div>
<!--片段名替换并传参-->
<div th:replace="commons::fragment-name(${name},18)"></div>