SpringBoot整合Thymeleaf
摘自https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html
一、thymeleaf简介
简介
简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。相较与其他的模板引擎,它有如下三个极吸引人的特点:
模板引擎(这里特指用于Web开发的模板引擎)是为了使[用户界面](https://baike.baidu.com/item/用户界面)与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的[HTML](https://baike.baidu.com/item/HTML)文档
· 1.Thymeleaf 在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
· 2.Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、改jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
· 3.Thymeleaf 提供spring标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
为什么使用 Thymeleaf
如果希望以 Jar 形式发布模块则尽量不要使用 JSP 相关知识,这是因为 JSP 在内嵌的 Servlet 容器上运行有一些问题 (内嵌 Tomcat、 Jetty 不支持 Jar 形式运行 JSP,Undertow 不支持 JSP)。
Spring Boot 官方中推荐使用 Thymeleaf 作为模板引擎,因为 Thymeleaf 提供了完美的 Spring MVC 支持
Spring Boot 提供了大量模板引擎,包括:
FreeMarker
Groovy
Mustache
Thymeleaf
Velocity
Beetl
官网:https://www.thymeleaf.org/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IXjkRf9R-1618548158522)(http://m.qpic.cn/psb?/V13x1ZYF1dFQtq/vJkN8hHnPA4E7zakqBxOmJK68PWcYgGb2arpE2il14c!/b/dL4AAAAAAAAA&bo=sAXHAgAAAAADB1I!&rf=viewer_4)]
二、第一个Thymeleaf
1、工具创建SpringBoot项目
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eQnbLtJR-1618548158526)(http://m.qpic.cn/psb?/V13x1ZYF1dFQtq/oLBANxXFzwb.gw1bvu.B1DmRIRb24ckYZIe26G.wfks!/b/dFIBAAAAAAAA&bo=qARCAwAAAAADF98!&rf=viewer_4)]
2、pom.xml
引入依赖
主要增加 spring-boot-starter-thymeleaf 和 nekohtml 这两个依赖
spring-boot-starter-thymeleaf:Thymeleaf 自动配置
nekohtml:允许使用非严格的 HTML 语法
NekoHTML 是一个简单地HTML扫描器和标签补偿器(tag balancer) ,
使得程序能解析HTML文档并用标准的XML接口来访问其中的信息。
这个解析器能投扫描HTML文件并“修正”许多作者(人或机器)在编写HTML文档过程中常犯的错误。
NekoHTML 能增补缺失的父元素、自动用结束标签关闭相应的元素,以及不匹配的内嵌元素标签。
<!-- 支持非严格语法的neko -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
完整版如下:
<dependencies>
<!-- spring web mvc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!-- mysql 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- druid 数据源连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 支持非严格语法的neko -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3、application.yml
#server config info
server:
port: 8080
spring:
#datasource connect info
datasource:
name: test
type: com.alibaba.druid.pool.DruidDataSource
druid:
url: jdbc:mysql://localhost:3306/maven_ssm?serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root
filters: stat
initial-size: 1
min-idle: 1
max-active: 20
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: false
max-pool-prepared-statement-per-connection-size: 20
# mybatis config info
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.qfjy.bean
4、SpringBoot支持Thymeleaf
查看源代码:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q5bHdplC-1618548158529)(http://m.qpic.cn/psb?/V13x1ZYF1dFQtq/sPa36mIuPLXlKFvwx08puneL5xYKA1iAPCzYH1.v9vY!/b/dL8AAAAAAAAA&bo=zAX3AQAAAAADFw0!&rf=viewer_4)]
只需要将开发页面放到Thymeleaf /templates/***.html即可直接访问
5、yml文件中配置Thymeleaf
添加如下自定义配置:(其它默认即可)
cache: false #开发阶段建议关闭缓存
mode: LEGACYHTML5 #用非严格的HTML5 默认是HTML5
如果不想对标签进行严格的验证,使用spring.thymeleaf.mode=LEGCYHTML5去掉验证,同时需要引入NekoHTML包
spring:
thymeleaf:
encoding: UTF-8 #编码规范 默认
cache: false #开发阶段建议关闭缓存
prefix: classpath:/templates/
suffix: .html
mode: LEGACYHTML5 #用非严格的HTML5 默认是HTML5
servlet:
content-type: text/html
6、创建html页面
在 templates 目录下创建 index.html 文件,
修改 html 标签用于引入 thymeleaf 引擎,这样才可以在其他标签里使用 th:* 语法,声明如下:
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns:th="http://www.thymeleaf.org">
代码如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>主页</title>
</head>
<body>
模版引擎主页的HTML页面
<p th:text="${msg}">信息显示</p>
</body>
</html>
7、controller
@RequestMapping("index")
@Controller
public class IndexController {
@RequestMapping("index")
public String index(Model model){
model.addAttribute("msg","我的第一个信息");
model.addAttribute("author","guoweixin");
return "index"; //基于约定优于配置,默认会到 /templates/ .html
}
}
8、访问请求即可
备注:SpringBoot使用thymeleaf作为视图展示,约定将模板文件放置在src/main/resource/templates目录下,静态资源放置在static目录下
小提示:
templates文件夹,是放置模板文件的,因此需要视图解析器来解析它。所以必须通过服务器内部进行访问,也就是要走控制器–服务–视图解析器这个流程才行。
如果想直接访问html页面,可放置到静态资源下/public….
三、Thymeleaf常用语法
1、引入 Thymeleaf
修改 html 标签用于引入 thymeleaf 引擎,这样才可以在其他标签里使用 th:* 语法,这是下面语法的前提。
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
知识点补充:
xmlns属性 是用来定义xml namespace(命名空间)的。该属性可以放置在文档内任何元素的开始标签中。该属性的值类似于 URL,它定义了一个命名空间,浏览器会将此命名空间用于该属性所在元素内的所有内容。如果需要使用符合 XML 规范的 XHTML 文档,则应该在文档中的<html> 标签中至少使用一个 xmlns 属性,以指定整个文档所使用的主要命名空间。不过即使你的 XHTML 文档没有使用此属性,W3C 的验证器也不会报错。因为 "xmlns=http://www.w3.org/1999/xhtml" 是一个固定值,所以,即使你没有包含它,此值也会被添加到 <html> 标签中。
2、th:text 变量表达式
th:text 标准/选择变量表达式
标准变量表达式
语法:${…}
标准变量表达式
获取变量值用 $ 符号,对于javaBean的话使用变量名.属性名方式获取,这点和 EL 表达式一样.
<p th:text="${msg}">信息显示</p>
<p th:text="${weixin.name}">姓名</p>
另外 $ 表达式只能写在th标签内部,不然不会生效,上面例子就是使用 th:text 标签的值替换 p 标签里面的值,至于 p 里面的原有的值只是为了给前端开发时做展示用的.这样的话很好的做到了前后端分离
选择变量表达式
选择变量表达式 或 *号变量表达式
前端测试代码:(对象的获取方式)
<div th:object="${user}">
<p th:text="*{name}">姓名</p>
<p th:text="*{telphone}">手机号码</p>
</div>
3、th:utext
这是th:text
属性的默认行为。如果我们希望Thymeleaf尊重我们的HTML标签而不是逃避它们,我们将不得不使用不同的属性:( th:utext
对于“未转义的文本”)
Controller代码:
model.addAttribute("msg1","<h2>普通字符串</h2>");
model.addAttribute("msg2","<h2>普通字符串</h2>");
Html代码:
<span th:text="你好${msg1}">测试1</span>
<span th:utext="${msg2}">测试2</span>
练习:显示当前个人信息、当前的日期等功能。
4 字符串拼接
字符串拼接操作单引号:
<span th:text="'我的字符串数据:'+${msg1}">数据</span>
更简洁的方式是:|…|
<span th:text="|我的字符串数据${msg1}|">数据</span>
5. URL表达式th:href
Thymeleaf对于 URL 的处理是通过语法 @{…} 来处理的
访问页面:<br/>
<a href="/404.html">404.html</a>
<a href="/index/index" th:href="@{|/index/index?a=21&b=${msg1}|}" >查看标签</a>
访问URL路径:
观察
例:(项目的上下文 /)例:(加项目上下文/boot)
**thymeleaf th:href /**时会帮我们加上上下文路径
建议所有thymeleaf路径使用:绝对路径(**用@{}**拼接)
静态页面用相对路径进行匹配
练习功能:完成页面间跳转流程
6、行内编写
虽然标准方言允许我们使用标记属性来完成几乎所有操作,但在某些情况下我们可能更喜欢将表达式直接编写到HTML文本中。例如,我们可能更喜欢这样写:
<p>Hello, [[${session.user.name}]]!</p>
…而不是这个:
<p>Hello, <span th:text="${session.user.name}">Sebastian</span>!</p>
官方文档:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#expression-inlining
四、Thymeleaf 常用属性
1、 th:each
常用标签,类似于JSTL中的<c:forEach>,该属性循环遍历集合、数组或Map
<tr th:each="u:${list}">
<td th:text="${uStat.count}">ID</td>
<td th:text="${u.name}">姓名</td>
<td th:text="${u.telphone}">手机号</td>
<td th:text="${u.status}">状态</td>
<td>操作</td>
</tr>
${list}是后台传过来的key
u是${list}定义遍历名称
uStat是循环体的信息。默认是 名称+stat,同时也可以自定义名称,中间以,号分隔。
th:each="u,i:${list}"
循环体可以获取如下信息:
index 当前迭代对象的index(0)开始
size 迭代对象大小
count(从1开始)
current(当前迭代变量)
even/odd 布尔值(是否是偶数/奇数 0开始)
first 布尔值 是否是第一个
last 布尔值 是否是最后一个
2、 th:if
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U2hoVHWB-1618548158532)(http://m.qpic.cn/psb?/V13x1ZYF1dFQtq/IpiJORbFwVoD97r2xMxDyVy9BeYa3fTk08NofZWCQnU!/b/dMMAAAAAAAAA&bo=8QLXAAAAAAADFxY!&rf=viewer_4)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yMkJaB9n-1618548158534)(http://m.qpic.cn/psb?/V13x1ZYF1dFQtq/XAXHvAqAYHKn*8GTPCNeyDD29vJ4k3yYw4oCFIUDUmI!/b/dL4AAAAAAAAA&bo=6gLNAAAAAAADFxc!&rf=viewer_4)]
3、 th:switch case
<h1>switch示例</h1>
<div th:switch="${sex}">
<span th:case="1">男</span>
<span th:case="2">女</span>
<span th:case="3">其它</span>
<span th:case="*">未知</span>
</div>
4、 th:src
用于外部资源引入,例如
图片:
<img src="/images/1.jpg" th:src="@{/images/1.jpg}" />
外部JS文件:
<script type="text/javascript" src="js/jquery.min.js" th:src="@{/js/popup.js}"></script>
5、th:value
思考如下代码:input输入框:
<input type="text" th:text="${msg}"/>
<input type="text" th:text="${msg}" th:value="${msg}"/>
6、th:attr
该属性用于给某元素的属性进行赋值
可以通过该属性为某个name赋动态名称
给 value赋值
<input type="text" th:attr="value=${msg}" />
给 name赋值
<input type="text" th:attr="name=${msg}" />
五、Thymeleaf其它 th 标签
th:abbr
th:accept
th:accept-charset
th:accesskey
th:action
th:align
th:alt
th:archive
th:audio
th:autocomplete
th:axis
th:background
th:bgcolor
th:border
th:cellpadding
th:cellspacing
th:challenge
th:charset
th:cite
th:class
th:classid
th:codebase
th:codetype
th:cols
th:colspan
th:compact
th:content
th:contenteditable
th:contextmenu
th:data
th:datetime
th:dir
th:draggable
th:dropzone
th:enctype
th:for
th:form
th:formaction
th:formenctype
th:formmethod
th:formtarget
th:frame
th:frameborder
th:headers
th:height
th:high
th:href
th:hreflang
th:hspace
th:http-equiv
th:icon
th:id
th:keytype
th:kind
th:label
th:lang
th:list
th:longdesc
th:low
th:manifest
th:marginheight
th:marginwidth
th:max
th:maxlength
th:media
th:method
th:min
th:name
th:optimum
th:pattern
th:placeholder
th:poster
th:preload
th:radiogroup
th:rel
th:rev
th:rows
th:rowspan
th:rules
th:sandbox
th:scheme
th:scope
th:scrolling
th:size
th:sizes
th:span
th:spellcheck
th:src
th:srclang
th:standby
th:start
th:step
th:style
th:summary
th:tabindex
th:target
th:title
th:type
th:usemap
th:value
th:valuetype
th:vspace
th:width
th:wrap
th:xmlbase
th:xmllang
th:xmlspace
th:alt-title
th:lang-xmllang
六、完成增删改查功能
列表list.html:
<table align="center" width="800px" border="1">
<tr>
<td>编号</td>
<td>用户名</td>
<td>密码</td>
<td>状态</td>
<td>操作</td>
</tr>
<tr th:each="u,i:${list}">
<td th:text="${i.count}">编号</td>
<td th:text="${u.uname}">用户名</td>
<td th:text="${u.upass}">密码</td>
<td >
<div th:switch="${u.status}">
<span th:case="1">有效</span>
<span th:case="0">无效</span>
<span th:case="*">待定</span>
</div>
</td>
<td>
<a href="">添加</a>
<a href="">修改</a>
<a href="view.html" th:href="@{|/user/${u.id}|}">查询</a>
<a href="javascript:del(1)" th:href="|javascript:del('${u.id}')|">删除</a>
</td>
</tr>
</table>
ajax删除:
function del(id){
$.ajax({
type:"post",
// user/del?id=id
url:'[[@{/user/del}]]', //请求的URL要注意用@{}
data:{"id":id},
success:function(msg){
window.location.href="[[@{/user/all}]]" //请求的URL要注意用@{}
}
})
}
统一错误异常处理
演示
Spring Boot提供了一个默认的映射:
/error
,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异常内容。
@Controller
public class DemoController {
@RequestMapping("info")
public String info(){
System.out.println(1/0);
return "ok";
}
}
可以看到类似下面的报错页面,该页面就是Spring Boot提供的默认error映射页面。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5927e48S-1618548158535)(img\1.png)]
统一异常处理
在resource/templates下添加error.html页面,
springBoot会自动找到该页面作为错误页面,适合内嵌Tomcat或者war方式。
在web/servlert/error下:
ErrorMvcAutoConfiguration类
SpringBoot错误视图提供了以下错误属性:
timestamp:错误发生时间;
status:HTTP状态码;
error:错误原因;
exception:异常的类名;
message:异常消息(如果这个错误是由异常引起的);
errors:BindingResult异常里的各种错误(如果这个错误是由异常引起的);
trace:异常跟踪信息(如果这个错误是由异常引起的);
path:错误发生时请求的URL路径。
状态码具体描述:
https://www.runoob.com/http/http-status-codes.html
SpringBoot使用的前端框架模板不同,页面的名称也有所不同:
实现Spring的View接口的Bean,其ID需要设置为error(由Spring的BeanNameViewResolver所解析);
如果配置了Thymeleaf,则需命名为error.html的Thymeleaf模板;
如果配置了FreeMarker,则需命名为error.ftl的FreeMarker模板;
如果配置了Velocity,则需命名为error.vm的Velocity模板;
如果是用JSP视图,则需命名为error.jsp的JSP模板。
在resource/templates/下添加error.html页面
显示全局显示的错误页面。
(error替换成对应的错误码,404、401、500等,还可以用4xx、5xx等),
springBoot会自动找到该页面作为错误页面,需要将该页面放到 templates/error/4xx.html 下
templates
error.html //默认全局错误页面
error //文件目录
4xx.html //对应错误码页面
5xx.html