上一篇博客已经介绍了登录页,接下来是主页dashboard.html,主页的侧边栏和顶部导航栏可以提取出来作为公共部分,放在templates/common路径下,命名为common.html:
<!--顶部栏-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow" th:fragment="topbar">
<a class="navbar-brand col-md-3 col-lg-2 mr-0 px-3" href="#">[[${session.username}]]</a>
<button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-toggle="collapse" data-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<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="#">Sign out</a>
</li>
</ul>
</nav>
<!--侧边栏-->
<nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse" th:fragment="sidebar(active)">
<div class="sidebar-sticky pt-3">
<ul class="nav flex-column">
<li class="nav-item">
<a th:class="${active=='main'?'nav-link active':'nav-link'}" href="/main">
<span data-feather="home"></span>
首页
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="file"></span>
Orders
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="shopping-cart"></span>
Products
</a>
</li>
<li class="nav-item">
<a th:class="${active=='list'?'nav-link active':'nav-link'}" href="/emps">
<span data-feather="users"></span>
员工管理
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="bar-chart-2"></span>
Reports
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
<span data-feather="layers"></span>
Integrations
</a>
</li>
</ul>
</div>
</nav>
两个nav标签都带有th:fragment属性,属性值可随意取,表示该标签被复用时的名字,在其他地方使用th:replace即可引用该导航栏。顶部栏中的第一个a标签里的文本取为session的username属性,即将用户名显示在左上角,session中的username属性在后台登录校验成功后进行设置:
@RequestMapping("/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password,
Model model, HttpSession session) {
if (用户名密码校验方法) {
session.setAttribute("username", username);
return "redirect:/main.html";
} else {
model.addAttribute("msg", "用户名或者密码错误");
return "index";
}
}
侧边栏里每个a标签的属性class里可设置是否为active,如果active表示该项被点亮,如下图所示:
为了实现点击某个选项,该选项被点亮的功能,需要在每个选项的class里设置条件:th:class="${条件?'nav-link active':'nav-link'}",其中active表示被点亮,条件由传入的参数决定,这里的参数名为active。如果点击首页,则传入active应为main,如果点击员工管理,则传入active应为list。因为其他选项暂时用不到,所以只设置首页和员工管理这两个选项。下面是首页dashboard.html:
<nav th:replace="~{common/common::topbar}"></nav>
<div class="container-fluid">
<div class="row">
<nav th:replace="~{common/common::sidebar(active='main')}"></nav>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard</h1>
<div class="btn-toolbar mb-2 mb-md-0">
<div class="btn-group mr-2">
<button type="button" class="btn btn-sm btn-outline-secondary">Share</button>
<button type="button" class="btn btn-sm btn-outline-secondary">Export</button>
</div>
<button type="button" class="btn btn-sm btn-outline-secondary dropdown-toggle">
<span data-feather="calendar"></span>
This week
</button>
</div>
</div>
<canvas class="my-4 w-100" id="myChart" width="900" height="380"></canvas>
<h2>Section title</h2>
</main>
</div>
</div>
其中,为了复用common.html中的代码,比如复用侧边栏,使用th:replace="~{common/common::sidebar(active='main')}",其中的~是thymeleaf中复用代码专用的符号,第一个common是目录名,第二个common.html的文件名,::后面的sidebar是th:fragment的值,还传入了参数active = 'main',以便点亮侧边栏的首页,后面的员工页也是类似的。
在common.html中,侧边栏的首页a标签的th:href属性值为“@{/main},表示点击跳转到首页,后台代码在覆写了的addViewControllers方法中:
registry.addViewController("/main").setViewName("dashboard");
侧边栏的员工管理a标签的th:href属性值为“@{/emps},表示点击跳转到员工页,后台代码在EmployeeController类中,其中查询了所有的员工信息,放在emps属性中,用于前台遍历:
@RequestMapping("/emps")
public String getAllEmployees(Model model) {
model.addAttribute("emps", employeeDao.getAllEmployees());
return "emps/list";
}
list.html如下:
<nav th:replace="~{common/common::topbar}"></nav>
<div class="container-fluid">
<div class="row ">
<nav th:replace="~{common/common::sidebar(active='list')}"></nav>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
<div class="row mt-3">
<div class="col">
<h2>员工管理</h2>
</div>
<!-- align-self-center使其垂直居中 -->
<div class="col align-self-center">
<a class="btn btn-sm btn-success" th:href="@{/toAdd}">添加员工</a>
</div>
</div>
<div class="table-responsive mt-3">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>编号</th>
<th>名字</th>
<th>年龄</th>
<th>部门</th>
<th>性别</th>
<th>生日</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="emp:${emps}">
<td>[[${emp.getId()}]]</td>
<td>[[${emp.getName()}]]</td>
<td>[[${emp.getAge()}]]</td>
<td>[[${emp.getDepartment().getName()}]]</td>
<td>[[${emp.getSex()==0?'女':'男'}]]</td>
<td>[[${#dates.format(emp.getBirthday(),'yyyy-MM-dd')}]]</td>
<td>
<!-- 注意a标签链接的restful风格传参方式 -->
<a class="btn btn-sm btn-primary" th:href="@{'/toUpdate/' + ${emp.getId()}}">编辑</a>
<a class="btn btn-sm btn-danger" th:href="@{'/delete/' + ${emp.getId()}}">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
</main>
</div>
</div>
该页面中还有添加员工、更新员工、删除员工的按钮,用于后续功能。表格取数据注意性别及出生日期两个字段,性别存储形式为0和1,因此前台展示时需要使用thymeleaf的三目运算符,而日期需要转化为自定义的'yyyy-MM-dd'的形式,使用#dates工具类的format方法实现。另外还需注意图中的垂直居中的方式:class属性中带有align-self-center即可。