本文导读
- 本文承接《Web 项目 tiger 之3 登录与拦截》
- 对于应用中公共的头部、左侧或右侧、甚至是底部区域,只要是共用的,就无需每个页面都重复去写,应该提取出来,大家引用即可。
- JSP 可以使用 <jsp:include page=” ”...动态包含,同理 Thymeleaf 也有自己方式,可以查看其官方文本如下:
thymeleaf 公共页面元素抽取
抽取公共片段
- 假设应用中需要一个公用的底部模块,如下所示 /templates/commonsFooter.html,使用 th:fragment 将其抽取为一个名字叫 "copy" 的代码片段,
- 以后在其它需要引用的地方可以使用 th:insert 、th:replace、th:include 等进行引用
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="copy">
网站标识码bm0100001 京ICP备05070218号 京公网安备11010202000001号
</div>
</body>
</html>
引用公共片段
- <div th:insert="footer :: selector|fragmentname"></div>:将公共片段整个插入到声明引入的元素中
- <div th:replace="footer :: selector|fragmentname"></div>:将声明引入的元素替换为公共片段
- <div th:include="footer :: selector|fragmentname"></div>:将被引入的片段的内容包含进这个标签中
- 注意:selector 是选择器,如标签的id值等;fragmentname就是th:fragment 声明的片段名称
<!--1、比如抽取的公用代码片段如下-->
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>
<!--2、采用如下三种方式进行引用-->
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
<!--3、则三种引用方式的效果分别对应如下-->
<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>
- 注意:th:insert 、th:replace、th:include 在标签中进行引用时可以不加 “~” 符号,也可以加,如下所示:
<div th:insert="~{footer :: #copy-section}"></div>
- 但行内写法时,必须要加 "~":[[~{}]];[(~{})];
项目实战
抽取公共头部
- 在登录进入后的用户列表页面,可以看到,可以将公告的头部和左侧菜单都可以抽取出来
- 新建一个公用的页面 commons.html,然后将 userList.html 中的公用头部 <nav>元素剪切过来,同时进行公用代码抽取th:fragment
<!DOCTYPE html>
<!--xmlns写上之后 Thymeleaf就会有提示,更加方便-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--抽取公共的头部,使用 th:fragment 命名片段;
同理这个公用的文件(模板)中还可以设置其它的公用片段,如公用的左侧菜单,底部说明等-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="head">
<!-- 获取session中的值,替换登录的用户账号-->
<a class="navbar-brand col-sm-3 col-md-2 mr-0"
href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" th:text="${session.userName}">Company name</a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Sign out</a>
</li>
</ul>
</nav>
</body>
</html>
<body>
<!--在原来的位置引用公共的头部元素,原来的 <nav元素就是在这里的
commonsHead:模板名,根据Spring Boot配置的Thymeleaf映射查找
head:是模板中公用的代码片段
如果使用 th:insert 就会是div包裹nav了,所以采用 replace进行替换-->
<div th:replace="commons::head"></div>
<div class="container-fluid">
抽取公共左侧
<!DOCTYPE html>
<!--xmlns写上之后 Thymeleaf就会有提示,更加方便-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--抽取公共的头部,使用 th:fragment 命名片段;
同理这个公用的文件(模板)中还可以设置其它的公用片段,如公用的左侧菜单,底部说明等-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="head">
<!-- 获取session中的值,替换登录的用户账号-->
<a class="navbar-brand col-sm-3 col-md-2 mr-0"
href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" th:text="${session.userName}">Company name</a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Sign out</a>
</li>
</ul>
</nav>
<!--抽取的公共左侧菜单
除了 使用 th:fragment 命名片段名称标识,也可以直接根据选择器进行标识,如 id="commonsLeft"-->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" id="commonsLeft">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-home">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
Dashboard <span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-file">
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
<polyline points="13 2 13 9 20 9"></polyline>
</svg>
Orders
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-shopping-cart">
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
Products
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-users">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
Customers
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-bar-chart-2">
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>
Reports
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-layers">
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
<polyline points="2 17 12 22 22 17"></polyline>
<polyline points="2 12 12 17 22 12"></polyline>
</svg>
Integrations
</a>
</li>
</ul>
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
<span>Saved reports</span>
<a class="d-flex align-items-center text-muted"
href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
class="feather feather-plus-circle">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="16"></line>
<line x1="8" y1="12" x2="16" y2="12"></line>
</svg>
</a>
</h6>
<ul class="nav flex-column mb-2">
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Current month
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Last quarter
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Social engagement
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-file-text">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
Year-end sale
</a>
</li>
</ul>
</div>
</nav>
</body>
</html>
</head>
<body>
<!--在原来的位置引用公共的头部元素,原来的 <nav元素就是在这里的
commonsHead:模板名,根据Spring Boot配置的Thymeleaf映射查找
head:是模板中公用的代码片段-->
<div th:replace="commons::head"></div>
<div class="container-fluid">
<div class="row">
<!-- 在原来的左侧菜单位置引用抽取好的公共左侧菜单代码-->
<div th:replace="commons :: #commonsLeft"></div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<h2>Section title</h2>
链接高亮显示
需求分析
- 说明:为了更加清晰已经方便说明,将原来公共的左侧菜单删除了部分内容,同时将第一个菜单项改为“用户列表”,第二个改为了“商品销量”
- 现在用户登录之后默认进入用户列表页面,所以“用户列表”菜单项应该高亮显示,点击商品销量则“商品销量”高亮,这也是项目中必须要做的事情
可参数化片段签名
- 实现链接动态高亮的功能需要使用到 Thymeleaf 的 参数化片段签名功能,即在引入片段的时候传传递参数过去,这在以前 JSP 中使用动态包含时也是这么做的
- 在 Thymeleaf 的官方文档的 第8章第2节 有使用说明如下:
- 在 th:fragment 声明片段的时候可以同时声明参数,里面则可以使用这些参数的值
- 在 th:insert、th:replace、th:include 引用的时候就可以将参数值传递过去,传值的时候可以直接按顺序传递过去,也可以不按顺序但是按着参数名传递过去
8.2 Parameterizable fragment signatures
1)
In order to create a more function-like mechanism for template fragments, fragments defined with th:fragment can specify a set of parameters:
<div th:fragment="frag (onevar,twovar)">
<p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>
2)
This requires the use of one of these two syntaxes to call the fragment from th:insert or th:replace :
<div th:replace="::frag (${value1},${value2})">...</div>
3)
Note that order is not important in the last option:
<div th:replace="::frag (onevar=${value1},twovar=${value2})">...</div>
<div th:replace="::frag (twovar=${value2},onevar=${value1})">...</div>
- 对于根据“选择器”进行引用的,是无法声明参数的,所以 Thymeleaf 说明如下:即 th:fragment 或者 选择器 可以不用声明参数,而在引用的时候可以直接通过参数名将值传过去
Fragment local variables without fragment arguments
Even if fragments are defined without arguments like this:
<div th:fragment="frag">
...
</div>
We could use the second syntax specified above to call them (and only the second one):
<div th:replace="::frag (onevar=${value1},twovar=${value2})">
公共页 commons.html
<!DOCTYPE html>
<!--xmlns写上之后 Thymeleaf就会有提示,更加方便-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--抽取公共的头部,使用 th:fragment 命名片段;
同理这个公用的文件(模板)中还可以设置其它的公用片段,如公用的左侧菜单,底部说明等-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="head">
<!-- 获取后台设置好的 session 中的值,显示当前登录的用户名
如果是以前jsp的动态包含,则还需要<jsp:include page 的时候使用 <param子标签传值过来
Thymeleaf 则在公共页面中也可以直接获取后台设置好的值
这是因为 JSP 的动态包含是两个不同的 Servlet-->
<a class="navbar-brand col-sm-3 col-md-2 mr-0"
href="http://getbootstrap.com/docs/4.0/examples/dashboard/#" th:text="${session.userName}">Company name</a>
<input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">Sign out</a>
</li>
</ul>
</nav>
<!--抽取的公共左侧菜单
除了 使用 th:fragment 命名片段名称标识,也可以直接根据选择器进行标识,如 id="commonsLeft"-->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" id="commonsLeft">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<!-- 点击用户列表链接之后,请求后台地址,th:href 的"/"表示应用根地址,必须写
使用 Thymeleaf 的三元运算符,如果 activeUri的值为 userList 则设置class的属性值为 nav-link active
否则为 nav-link,其实 active 就是 BootStrop 的高亮样式而已
-->
<a class="nav-link" th:class="${activeUri=='userList'?'nav-link active':'nav-link'}"
href="#" th:href="@{/userList}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-file">
<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
<polyline points="13 2 13 9 20 9"></polyline>
</svg>
用户列表
</a>
</li>
<li class="nav-item">
<!-- 请求后台控制器路径,同理进行参数值判断-->
<a class="nav-link" th:class="${activeUri=='user/products'?'nav-link active':'nav-link'}"
th:href="@{/user/products}">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-shopping-cart">
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
商品销量
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-users">
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
<circle cx="9" cy="7" r="4"></circle>
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
</svg>
Customers
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-bar-chart-2">
<line x1="18" y1="20" x2="18" y2="10"></line>
<line x1="12" y1="20" x2="12" y2="4"></line>
<line x1="6" y1="20" x2="6" y2="14"></line>
</svg>
Reports
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round" class="feather feather-layers">
<polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
<polyline points="2 17 12 22 22 17"></polyline>
<polyline points="2 12 12 17 22 12"></polyline>
</svg>
Integrations
</a>
</li>
</ul>
</div>
</nav>
</body>
</html>
用户列表页面 userList.html
</head>
<body>
<!--在原来的位置引用公共的头部元素,原来的 <nav元素就是在这里的
commonsHead:模板名,根据Spring Boot配置的Thymeleaf映射查找
head:是模板中公用的代码片段-->
<div th:replace="commons::head"></div>
<div class="container-fluid">
<div class="row">
<!-- 在原来的左侧菜单位置引用抽取好的公共左侧菜单代码
1、这是使用的 id选择器 进行的引用
2、引用公共代码的片段的同时传递参数值过去
3、参数值userList自行约定即可,也可以是1、a等字符,自己方便就行-->
<div th:replace="commons::#commonsLeft(activeUri='userList')"></div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<h2>Section title</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>#</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
<th>Header</th>
</tr>
商品销量页面 products.html
</head>
<body>
<!--在原来的位置引用公共的头部元素,原来的 <nav元素就是在这里的
commonsHead:模板名,根据Spring Boot配置的Thymeleaf映射查找
head:是模板中公用的代码片段-->
<div th:replace="commons::head"></div>
<div class="container-fluid">
<div class="row">
<!-- 在原来的左侧菜单位置引用抽取好的公共左侧菜单代码
同理引用的同时传递参数值过去-->
<div th:replace="commons::#commonsLeft(activeUri='user/products')"></div>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<div class="chartjs-size-monitor"
运行测试