入门
是什么
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。
Thymeleaf是一个Java库。它是一个XML / XHTML / HTML5模板引擎,能够对模板文件应用一组转换,以显示应用程序生成的数据和/或文本。
它更适合在Web应用程序中提供XHTML / HTML5服务,但是它可以处理任何XML文件,无论是在Web中还是在独立应用程序中。
Thymeleaf的主要目标是提供一种优雅且格式正确的模板创建方法。为了实现这一点,它基于XML标签和属性,这些属性定义了DOM(文档对象模型)上预定义逻辑的执行,而不是将该逻辑作为模板中的代码显式编写。
它的体系结构允许依靠已解析文件的智能缓存来快速处理模板,以便在执行过程中使用尽可能少的I / O操作。
最后但并非最不重要的一点是,Thymeleaf从一开始就设计了XML和Web标准,允许您在需要时创建完全验证的模板。
特性
-
Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
-
Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、该jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
-
Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
springboot 静态资源的访问
静态资源访问
在我们开发Web应用的时候,需要引用大量的js、css、图片等静态资源。
默认配置
Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则:
/static
/public
/resources
/META-INF/resources
举例:我们可以在src/main/resources/目录下创建static,在该位置放置一个图片文件。
启动程序后,尝试访问http://localhost:8080/D.jpg。如能显示图片,配置成功。
模板引擎
Spring Boot提供了默认配置的模板引擎主要有以下几种:
-
Thymeleaf
-
FreeMarker
-
Velocity
-
Groovy
-
Mustache
Spring Boot建议使用这些模板引擎,避免使用JSP,若一定要使用JSP将无法实现Spring Boot的多种特性,具体可见后文:支持JSP的配置
当你使用上述模板引擎中的任何一个,它们默认的模板配置路径为:src/main/resources/templates
。
当然也可以修改这个路径,具体如何修改,可在后续各模板引擎的配置属性中查询并修改。
springboot 整合
整体目录
├─java
│ └─com
│ └─github
│ └─houbb
│ └─springboot
│ └─learn
│ └─thymeleaf
│ │ LeafApplication.java
│ │
│ └─controller
│ HelloController.java
│
└─resources
│ application.properties
│
└─templates
hello.html
maven 引入
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
控制层
简单的一个控制器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HelloController {
@GetMapping(value = "/hello")
public String hello(Model model) {
String name = "爱开源的小叶同学";
model.addAttribute("name", name);
return "hello";
}
}
配置文件
- application.properties
# thymeleaf
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.check-template-location=true
spring.thymeleaf.suffix=.html
spring.thymeleaf.content-type=text/html
spring.thymeleaf.mode=HTML
spring.thymeleaf.cache=false
不严格的 HTML 格式
实际项目中可能会有不太严格的HTML格式,此时设置mode=HTML5将会对非严格的报错,可以参考以下配置:
spring.thymeleaf.mode=LEGACYHTML5
如果你这样设置,需要额外的依赖库
需要注意的是,LEGACYHTML5需要搭配一个额外的库NekoHTML才可用。
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
最后重启项目就可以感受到不那么严格的thymeleaf了。
对应的配置也需要调整:
# 一项是非严格的HTML检查,一项是禁用缓存来获取实时页面数据,其他采用默认项即可
thymeleaf:
mode: LEGACYHTML5
cache: false
html 编写
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>hello</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<!--/*@thymesVar id="name" type="java.lang.String"*/-->
<p th:text="'Hello!, ' + ${name} + '!'">3333</p>
</body>
</html>
访问
直接页面发访问 http://localhost:8080/hello
返回如下:
Hello!, 爱开源的小叶同学!
遇到的报错
HTML 已配置
org.thymeleaf.exceptions.TemplateInputException: Template mode \\\"HTML\\\" has not been configured
- 解决方式
mode: HTML
我直接把这个 mode 注释掉了。
meta 报错
org.xml.sax.SAXParseException: 元素类型 "meta" 必须由匹配的结束标记 "" 终止。
这个就是原来的 html 写的不够规范:
<meta charset="utf-8">
我加了一个结尾:
<meta charset="utf-8"/>
彻底解决
springboot 使用thymeleaf 模板引擎时报错org.xml.sax.SAXParseException: 元素类型 “link” 必须由匹配的结束标记 “” 终止,org.xml.sax.SAXParseException: 元素类型 “meta” 必须由匹配的结束标记 “” 终止,出现这类问题的时候,解决方法如下
在pom.xml中添加
<properties>
<java.version>1.8</java.version>
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.0.5</thymeleaf-layout-dialect.version>
</properties>
<!--启用不严格检查html-->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
在properties.yml添加如下内容
thymeleaf:
cache: false
mode: LEGACYHTML5
content-type: text/html
encoding: UTF-8
layout 引入其他页面
背景
html 中编写一般都有很多重复的内容。
比如 header、footer 等相同的内容,最简单的方式是使用 layout 或者直接 include 对应的页面。
这样做可以避免内容的重复编写,也便于后期统一维护修改。
方案1:fragement
将页面里的每个部分都分成块 -> fragment 使用 th:include
和 th:replace
来引入页面
这种用法没有layout的概念, 因为每个部分都是 fragment, 下面例子说明
<!-- index.html -->
<html>
<head>
<meta charset="utf-8"/>
<title>demo</title>
</head>
<body>
<div th:include="components/header :: header"></div>
<div class="container">
<h1>hello world</h1>
</div>
<div th:include="components/footer :: footer"></div>
</body>
</html>
<!-- components/header.html -->
<header th:fragment="header">
<ul>
<li>news</li>
<li>blog</li>
<li>post</li>
</ul>
</header>
<!-- components/footer.html -->
<header th:fragment="footer">
<div>i am footer.</div>
</header>
上面例子里用到的是th:include, 也就是把定义好的fragment引入的意思, 还有一个是th:replace, 意思是替换
layout 布局
maven 依赖
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>2.3.0</version>
</dependency>
编写布局代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>layout布局方案</title>
<style>
* {font-family: Microsoft YaHei, Tahoma, Helvetica, Arial, sans-serif;}
.header {background-color: #f5f5f5;padding: 20px;}
.header a {padding: 0 20px;}
.container {padding: 20px;margin:20px auto;}
.footer {height: 40px;background-color: #f5f5f5;border-top: 1px solid #ddd;padding: 20px;}
</style>
</head>
<body>
<header class="header">
<div>
采用layout方式进行布局
</div>
</header>
<div class="container" layout:fragment="content"></div>
<footer class="footer">
<div>
<p style="float: left">© Hylun 2017</p>
<p style="float: right">
Powered by <a href="http://my.oschina.net/alun" target="_blank">Alun</a>
</p>
</div>
</footer>
</body>
</html>
关键点:
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout": 引入layout标签
<div class="container" layout:fragment="content">页面正文内容</div> 设置页面正文内容所在位置
编写内容页面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
layout:decorator="demo/layout2">
<div layout:fragment="content">
正文内容222222222222
</div>
</html>
关键点:
layout:decorator="demo/layout2" :此位置指向layout2.html页面位置
layout:fragment="content" :指定页面正文内容 content要与layout2.html页面中定义的名字一致