7、登錄
業務流程
- 在
index.html
頁,輸入用戶名和密碼,點擊登錄;- 發起請求,對用戶名密碼進行判斷
- 登錄成功,跳轉到
dashboard.html
7.1、准備:視圖控制器
- 添加視圖控制器:
MyMvcConfig
中為dashboard頁面
添加一個視圖映射
@Override
public void addViewControllers(ViewControllerRegistry registry) {
...
// dashboard頁
registry.addViewController("/main").setViewName("dashboard");
}
7.2、准備:登錄業務
登錄功能需要驗證用戶名和密碼,所以需要補充一套相應的業務。
- 自頂向下分析:Controller 調 Service,Service 調 DAO
- 自底向上編寫:先寫 DAO,再寫 Service,再寫 Controller ;
-
EmployeeMapper
/** * 查詢用戶:登錄功能 * * @param name 員工名:用戶名 * @param employeeId 員工ID:密碼 * @return 待查詢員工 */ Employee getEmployeeForLogin(String name, String employeeId);
-
EmployeeMapper.xml
<select id="getEmployeeForLogin" resultMap="employeeMap"> SELECT create_time, update_time, employee_id, name, email, gender, birthday, department_id FROM springboot_staff.employee WHERE name = #{name} and employee_id = #{employeeId} </select>
-
EmployeeService:同 EmployeeMapper
-
EmployeeServiceImpl
@Override public Employee getEmployeeForLogin(String name, String employeeId) { return employeeMapper.getEmployeeForLogin(name, employeeId); }
7.3、接口
LoginController
- 判斷用戶名和密碼是否為空;
- 調用 Service 層,查詢數據庫中是否有匹配的員工;
- 設置頁面
- 登錄成功:設置 Session,重定向到目標頁(需要視圖控制器);
- 登錄失敗:設置參數,轉發到首頁
/**
* 登錄
*/
@PostMapping("/employee/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password,
Model model, HttpSession session) {
// 判空
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
model.addAttribute("msg", "用戶名或密碼為空");
return "index";
}
Employee employee = employeeService.getEmployeeForLogin(username, password);
if (employee != null) {
// 創建一個EmployeeConstant類,靜態變量作為常量
session.setAttribute(EmployeeConstant.LOGIN_EMPLOYEE, employee);
return "redirect:/main";
} else {
model.addAttribute("msg", "用戶名或密碼錯誤");
return "index";
}
}
/**
* 注銷
*/
@GetMapping("/employee/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/index.html";
}
7.4、頁面
index.html
- Thymeleaf 語法——鏈接 URL 表達式:
@{...}
- 提交方式:post;
- 添加一個 p標簽,用於接收提示信息(如:用戶名密碼錯誤);
- 字段要求有 name 屬性,否則后台無法接收到;
<!-- 登錄 -->
<form class="form-signin" th:action="@{/employee/login}" method="post">
...
<p style="color:red" th:text="${msg}"></p>
<input name="username" ...>
<input name="password" ...>
</form>
<!-- 注銷 -->
<a class="nav-link" href="/employee/logout">Sign out</a>
dashboard.html
- 如果跳轉到 dashboard 頁面 后沒有 CSS 樣式,在引入 CSS 文件的 link 標簽的 href 前添加
/
; - 成功登錄后,dashboard 頁面左上角展示當前登錄的員工名;
- Thymeleaf 語法——插入片段:
[[${對象.屬性}]]
<head>
...
<link href="/asserts/css/bootstrap.min.css" rel="stylesheet">
<link href="/asserts/css/dashboard.css" rel="stylesheet">
</head>
<body>
...
<div class="navbar-brand col-sm-3 col-md-2 mr-0">[[${session.loginEmployee.name}]]
...
</body>
7.5、攔截器
- 編寫:根據 Session 是否為空,判斷用戶是否成功登入;
- 注冊:向注冊器中添加寫好的攔截器,攔截所有頁面,首頁和登錄請求除外;
LoginHandlerInterceptor
獲取 Session,判斷是否為空;
- Session 為空:用戶未登錄或已退出
- 設置參數(提示信息),轉發到首頁;
- 攔截請求
- Session 非空:用戶已登入
- 放行請求
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Employee loginEmployee = (Employee) request.getSession().getAttribute(EmployeeConstant.LOGIN_EMPLOYEE);
if (loginEmployee == null) {
request.setAttribute("msg", "沒有訪問權限,請登錄");
// 跳轉到首頁,【/index.html】是視圖控制器,也可以填【/】
request.getRequestDispatcher("/index.html").forward(request, response);
return false;
}
return true;
}
}
MyMvcConfig
addInterceptor
:添加攔截器;addPathPatterns
:添加攔截的路徑,/**
代表所有路徑;excludePathPatterns
:添加排除的路徑,即不被攔截的路徑
@Override
public void addInterceptors(InterceptorRegistry registry) {
LoginHandlerInterceptor loginHandlerInterceptor = new LoginHandlerInterceptor();
registry.addInterceptor(loginHandlerInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/index.html", "/", "/employee/login", "/asserts/**");
}
8、員工展示
業務流程
- 在
dashboard.html
頁,點擊員工列表;- 發起請求,查詢出所有員工列表;
- 跳轉到員工展示頁
8.1、接口
EmployeeController
- 調用 Service 層,查詢所有員工列表;
- Model 設置數據
- 跳轉頁面:
list.html
@Controller
public class EmployeeController {
@Resource
EmployeeService employeeService;
@RequestMapping("/employee/listEmployees")
public String listEmployees(Model model) {
List<Employee> employeeList = employeeService.listEmployees();
model.addAttribute("employeeList", employeeList);
return "list";
}
}
8.2、頁面
dashboard.html
- 調用接口:
/employee/listEmployees
<li class="nav-item">
<a class="nav-link" href="/employee/listEmployees">
<svg ...>
...
</svg>
Employees
</a>
</li>
list.html
- 迭代:
th:each="xxx:${Xxx}"
th:each="employee:${employeeList}"
- 對於 employeeList 中的每個元素,每次循環迭代並賦給 employee
- 取屬性:
${xxx.getXxx}
或[[]]
employee.getEmployeeId()
等,要求實體類有 getter- 三元運算符:
邏輯表達式?表達式1:表達式2
- 日期工具類:
#dates.format(日期對象,格式)
- 注意
- NPE:如
getDepartment().getName()
,如果有某個員工沒有部門,則變成null.getName()
報錯
- NPE:如
<table ...>
<thead>
<tr>
<th>EmployeeID</th>
<th>Name</th>
<th>Email</th>
<th>Gender</th>
<th>Birthday</th>
<th>Department</th>
</tr>
</thead>
<tbody>
<tr th:each="employee : ${employeeList}">
<td th:text="${employee.getEmployeeId()}"></td>
<td th:text="${employee.getName()}"></td>
<td th:text="${employee.getEmail()}"></td>
<td th:text="${employee.getGender()==1?'男':'女'}"></td>
<td th:text="${#dates.format(employee.getBirthday(),'yyyy-MM-dd')}"></td>
<td th:text="${employee.getDepartment().getName()}"></td>
</tr>
</tbody>
</table>
9、添加員工
流程:
list.html
:點擊員工添加
按鈕- 發起請求,查詢部門列表,跳轉到
員工添加
頁面
- 發起請求,查詢部門列表,跳轉到
add.html
:輸入員工的屬性,點擊添加
- 發起請求,將屬性自動封裝為對象,跳轉到
員工展示
頁
- 發起請求,將屬性自動封裝為對象,跳轉到
9.1、接口
EmployeeController
-
前往頁面
- get 請求
- 查詢所有部門,Model 設置
- 跳轉頁面
-
處理業務
- post請求
- 用實體類接收頁面字段(見SpringMVC 6.1.3)
- 要求:提交的域名稱和實體類屬性名一致、實體類有 setter
/**
* 前往員工添加頁
*
* @return 員工添加頁
*/
@GetMapping("/employee/addEmployee")
public String toAddEmployee(Model model) {
List<Department> departmentList = departmentService.listDepartments();
model.addAttribute("departmentList", departmentList);
return "add";
}
/**
* 員工添加業務
*
* @param employee 待添加員工
* @return 重定向:員工展示頁
*/
@PostMapping("/employee/addEmployee")
public String addEmployee(Employee employee) {
employeeService.insertEmployee(employee);
return "redirect:/employee/listEmployees";
}
9.2、頁面
list.html
- 添加員工按鈕:get 請求
<a class="btn btn-sm btn-success" th:href="@{/employee/addEmployee}">添加員工</a>
add.html
- 表單:post 請求
- name 屬性:要求表單域有該屬性,且屬性名與實體類屬性名一致;
- 日期格式:默認為
yyyy/MM/dd
- department:
- 獲取部門列表,迭代獲取部門名,作為下拉框選項;
- 提交到后台的是
department_id
,而不是整個部門;
<form action="/employee/addEmployee" method="post">
<div class="form-group">
<label>EmployeeID</label>
<input type="text" class="form-control" placeholder="請輸入員工ID" name="employeeId">
</div>
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" placeholder="請輸入員工姓名" name="name">
</div>
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" placeholder="請輸入員工郵箱" name="email">
</div>
<div class="form-group">
<label>Gender</label><br>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" value="1" name="gender">
<label class="form-check-label">男</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" value="0" name="gender">
<label class="form-check-label">女</label>
</div>
</div>
<div class="form-group">
<label>Birthday</label>
<input type="text" class="form-control" placeholder="請輸入員工生日" name="birthday">
</div>
<div class="form-group">
<label>Department</label>
<select class="form-control" name="department.departmentId">
<option th:each="department:${departmentList}" th:text="${department.getName()}"
th:value="${department.getDepartmentId()}"></option>
</select>
</div>
<button type="submit" class="btn btn-primary">添加</button>
</form>
10、修改員工(改名)
本項目中,通過修改員工名來體現修改功能。
流程:
list.html
:點擊編輯
按鈕- 發起請求,傳遞employeeId並查詢員工,跳轉到
員工編輯
頁面
- 發起請求,傳遞employeeId並查詢員工,跳轉到
update.html
:輸入需要修改的屬性,點擊保存- 發起請求,修改屬性,跳轉到
員工展示頁
- 發起請求,修改屬性,跳轉到
10.1、接口
- 前往頁面
- get 請求
- RESTful風格,攜帶參數employeeId
- 根據 employeeId 查詢 employee,Model設置
- 跳轉頁面
- 處理業務
- post請求
- 用實體類接收頁面字段
- 要求:提交的域名稱和實體類屬性名一致、實體類有 setter
/**
* 前往員工更新頁
*
* @param employeeId 待更新員工ID
* @return 員工更新頁
*/
@GetMapping("/employee/updateEmployee/{employeeId}")
public String toUpdateEmployee(@PathVariable String employeeId, Model model) {
Employee employee = employeeService.getEmployee(employeeId);
model.addAttribute("employee", employee);
return "update";
}
/**
* 員工更新業務
*
* @param employeeId 待更新員工ID
* @param name 員工新名
* @return 重定向:員工展示頁
*/
@PostMapping("/employee/updateEmployee")
public String updateEmployee(String employeeId, String name) {
employeeService.updateEmployee(employeeId, name);
return "redirect:/employee/listEmployees";
}
10.2、頁面
list.html
-
添加
編輯
和刪除
按鈕:get請求 -
RESTful風格,傳參:
'URL/'+${參數}
"@{'/employee/updateEmployee/'+${employee.getEmployeeId()}}"
<table class="table table-striped table-sm"> <thead> <tr> ... <th>操作</th> </tr> </thead> <tbody> <tr th:each="employee : ${employeeList}"> ... <td> <!-- 編輯 --> <a th:href="@{'/employee/updateEmployee/'+${employee.getEmployeeId()}}" class="btn btn-sm btn-primary">編輯</a> <!-- 刪除 --> </td> </tr> </tbody> </table>
update.html
- 表單:post 請求;
- 獲取員工信息,展示到頁面;
- name 屬性:要求表單域有該屬性,且屬性名與接口方法參數列表一致;
<form action="/employee/updateEmployee" method="post">
<div class="form-group">
<label>EmployeeID</label>
<input class="form-control" type="text" name="employeeId" th:value="${employee.getEmployeeId()}"
placeholder="請輸入員工ID"
readonly>
</div>
<div class="form-group">
<label>Name</label>
<input class="form-control" type="text" name="name" th:placeholder="'原員工名:'+${employee.getName()}">
</div>
<button type="submit" class="btn btn-primary">保存</button>
</form>
11、刪除員工
流程:
list.html
:點擊刪除
按鈕- 發起請求,傳遞 employeeId,刪除員工
11.1、接口
- 調用接口
- get 請求
- RESTful風格,攜帶參數 employeeId
- 處理業務
- 接收頁面字段
- 刪除員工
/**
* 刪除員工
* @param employeeId 待刪除員工ID
* @return 重定向:員工展示頁
*/
@GetMapping("/employee/deleteEmployee/{employeeId}")
public String deleteEmployee(@PathVariable String employeeId){
employeeService.deleteEmployee(employeeId);
return "redirect:/employee/listEmployees";
}
11.2、頁面
list.html
<a class="btn btn-sm btn-danger"
th:href="@{'/employee/deleteEmployee/'+${employee.getEmployeeId()}}">刪除</a>
12、小結
到此,一個簡易的 Spring Boot 員工管理系統搭建完畢。
主要技術:
- JDBC、MySQL、Druid數據源、MyBatis
- Spring Boot
- Thymeleaf模板引擎;
知識點
- 阿里巴巴編程規范;
- ORM原則、不同命名風格的映射處理;
- 常量類、工具類的使用;
- 整合Druid數據源、MyBatis;
- 一對多關系的映射處理;
- MVC模式:pojo/DAO-Service-Controller;
- 使用注解開發;
- Thymeleaf模板引擎的使用
- 視圖控制器
- 鏈接表達式
- 循環遍歷
- 頁面取值
- 攔截器
- RESTful風格:GetMapping、PostMapping、@PathVariable
- 前后台傳值:屬性、對象
- CRUD