SpringBoot-员工管理系统

1. 准备工作

1.1 导入静态资源

QQ截图20221008174935

1.2 创建模拟数据库

项目未整合MyBatis,使用模拟数据库。

创建实体类:

  1. 创建部门表 Department

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
       package com.study.pojo;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    //部门表
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Department {
    private Integer id;
    private String departmentName;
    }

    2. 创建员工表 Employee

    ```java
    package com.study.pojo;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    import java.util.Date;

    //员工表
    @Data
    @NoArgsConstructor
    public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender; //0:女 1:男
    private Department department;
    private Date birth;

    public Employee(Integer id, String lastName, String email, Integer gender, Department department) {
    this.id = id;
    this.lastName = lastName;
    this.email = email;
    this.gender = gender;
    this.department = department;
    this.birth = new Date(); //默认的创建日期
    }
    }

创建模拟数据库Dao:

  1. 创建部门dao DepartmentDao

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    package com.study.dao;

    import com.study.pojo.Department;
    import org.springframework.stereotype.Repository;

    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;

    //部门dao
    @Repository //被Spring托管
    public class DepartmentDao {
    //模拟数据库中数据
    private static Map<Integer, Department> departments = null;
    static{
    departments = new HashMap<Integer,Department>(); //创建一个部门表

    departments.put(101,new Department(101,"教学部"));
    departments.put(102,new Department(102,"市场部"));
    departments.put(103,new Department(103,"教研部"));
    departments.put(104,new Department(104,"运营部"));
    departments.put(105,new Department(105,"后期部"));
    }

    //获得所有部门信息
    public Collection<Department> getDepartments(){
    return departments.values();
    }

    //通过id得到部门
    public Department getDepartmentById(Integer id){
    return departments.get(id);
    }
    }
  2. 创建员工dao EmployeeDao

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    package com.study.dao;

    import com.study.pojo.Department;
    import com.study.pojo.Employee;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Repository;

    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;

    //员工dao
    @Repository
    public class EmployeeDao {
    //模拟数据库数据
    private static Map<Integer, Employee> employees = null;
    //员工有所属部门
    @Autowired
    private DepartmentDao departmentDao;
    static{
    employees = new HashMap<Integer,Employee>(); //创建一个部门表

    employees.put(1001,new Employee(1001,"员工01","2746200911@qq.com",1,new Department(101,"教学部")));
    employees.put(1002,new Employee(1002,"员工02","2746200912@qq.com",0,new Department(102,"市场部")));
    employees.put(1003,new Employee(1003,"员工03","2746200913@qq.com",1,new Department(103,"教研部")));
    employees.put(1004,new Employee(1004,"员工04","2746200914@qq.com",0,new Department(104,"运营部")));
    employees.put(1005,new Employee(1005,"员工05","2746200915@qq.com",1,new Department(105,"后期部")));
    }

    //主键自增
    private static Integer initId = 1006;
    //增加一个员工
    public void save(Employee employee){
    if(employee.getId() == null){
    employee.setId(initId++);
    }
    employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));
    employees.put(employee.getId(),employee);
    }

    //查询全部员工信息
    public Collection<Employee> getAll(){
    return employees.values();
    }

    //通过id查询员工
    public Employee getEmployeeById(Integer id){
    return employees.get(id);
    }

    //删除员工
    public void delete(Integer id){
    employees.remove(id);
    }

    }

1.3 导入依赖

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--有一个父项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.study</groupId>
<artifactId>HelloWorld</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>HelloWorld</name>
<description>HelloWorld</description>
<properties>
<java.version>11</java.version>
</properties>
<!--依赖-->
<dependencies>
<!--启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--web依赖:集成了tomcat,替代了dispatcherServlet,xml配置...-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--单元测试,等价于junit-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--jQuery-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.1</version>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>

<build>
<plugins>
<!--打jar包插件-->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

2. 首页实现

  1. 首页配置

    注意:所有页面的静态资源都需要使用thymeleaf接管:@{}

    导入thymeleaf命名空间:

    1
    xmlns:th="http://www.thymeleaf.org"

    修改导入的静态文件

  2. 首页实现

    index.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <title>Signin Template for Bootstrap</title>
    <!-- Bootstrap core CSS -->
    <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
    <!-- Custom styles for this template -->
    <link th:href="@{/css/signin.css}" rel="stylesheet">
    </head>

    <body class="text-center">
    <form class="form-signin" action="dashboard.html">
    <img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
    <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
    <label class="sr-only">Username</label>
    <input type="text" class="form-control" placeholder="Username" required="" autofocus="">
    <label class="sr-only">Password</label>
    <input type="password" class="form-control" placeholder="Password" required="">
    <div class="checkbox mb-3">
    <label>
    <input type="checkbox" value="remember-me"> Remember me
    </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
    <p class="mt-5 mb-3 text-muted">© 2021-2022</p>
    <a class="btn btn-sm">中文</a>
    <a class="btn btn-sm">English</a>
    </form>

    </body>

    </html>
  3. 首页展示

    QQ截图20221008190741

3. 国际化

3.1 国际化

国际化(internationalization)是设计和制造领域适应不同区域要求的产品的一种方式。它要求从产品中抽离所有地域语言,国家/地区和文化相关的元素。换言之,应用程序的功能和代码设计考虑在不同地区运行的需要,其代码简化了不同本地版本的生产。开发这样的程序的过程,就称为国际化。

3.2 页面国际化

页面国际化步骤:

  1. 在IDEA中设置properties的编码问题

  2. 在resources资源文件下新建一个i18n目录,存放国际化配置文件

    i18n:国际化 internationalization 单词的缩写

    QQ截图20221008204411

  3. 新建国际化配置文件

    login.properties —- 默认

    1
    2
    3
    4
    5
    login.tip=请登录
    login.password=密码
    login.username=用户名
    login.remember=记住我
    login.btn=登录

    login_zh_CN.properties —- 中文

    1
    2
    3
    4
    5
    login.tip=请登录
    login.password=密码
    login.username=用户名
    login.remember=记住我
    login.btn=登录

    login_en_US.properties —- 英文

    1
    2
    3
    4
    5
    login.tip=Please sign in
    login.password=password
    login.username=username
    login.remember=Remember me
    login.btn=Sign in
  4. 配置页面国际化值

    去页面获取国际化的值,查看Thymeleaf的文档,找到message取值操作为: #{…}。

    修改index.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <form class="form-signin" action="dashboard.html">
    <img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
    <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
    <label class="sr-only" th:text="#{login.username}">Username</label>
    <input type="text" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
    <label class="sr-only" th:text="#{login.password}">Password</label>
    <input type="password" class="form-control" th:placeholder="#{login.password}" required="">
    <div class="checkbox mb-3">
    <label>
    <input type="checkbox" value="remember-me"> [[#{login.remember}]]
    </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" type="submit">[[#{login.btn}]]</button>
    <p class="mt-5 mb-3 text-muted">© 2021-2022</p>
    <a class="btn btn-sm">中文</a>
    <a class="btn btn-sm">English</a>
    </form>

    测试结果:

    QQ截图20221008201013

3.3 中英文自动切换

  1. 配置自定义国际化解析组件

    在Spring中有一个国际化的Locale (区域信息对象),里面有一个叫做LocaleResolver (获取区域信息对象)的解析器

    MyLocaleResolver.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package com.study.config;

    import org.springframework.web.servlet.LocaleResolver;
    import org.thymeleaf.util.StringUtils;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Locale;

    //自定义国际化组件
    public class MyLocaleResolver implements LocaleResolver {
    //解析请求
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
    //获取请求中的语言参数
    String language = request.getParameter("lan");
    Locale locale = Locale.getDefault(); //如果没有就使用默认的
    //如果请求的链接携带了国际化的参数
    if(!StringUtils.isEmpty(language)){
    //zh_CN
    String[] split = language.split("_");
    //国家,地区
    locale = new Locale(split[0],split[1]);
    }
    return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
    }
  2. 修改 index.html 前端页面的跳转连接

    1
    2
    <a class="btn btn-sm" th:href="@{/index.html(lan='zh_CN')}">中文</a>
    <a class="btn btn-sm" th:href="@{/index.html(lan='en_US')}">English</a>
  3. 将自定义国际化组件注入IOC容器

    添加Bean

    MyMvcConfig.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.study.config;

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.LocaleResolver;
    import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    @Configuration
    public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("index");
    registry.addViewController("/index.html").setViewName("index");
    }

    //将自定义国际化组件放入容器中生效
    @Bean
    public LocaleResolver localeResolver(){
    return new MyLocaleResolver();
    }
    }
  4. 测试

    中文:

    QQ截图20221008203731

    英文:

    QQ截图20221008203752

4. 登录功能实现

实现步骤:

  1. 把登录页面的表单提交地址写一个controller

    修改index.html,所有表单标签都需要加上一个name属性。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <form class="form-signin" th:action="@{/user/login}">
    <img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
    <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>

    <!--如果msg的值为空,则不显示消息-->
    <p style="color:red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

    <label class="sr-only" th:text="#{login.username}">Username</label>
    <input type="text" name="username" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
    <label class="sr-only" th:text="#{login.password}">Password</label>
    <input type="password" name="password" class="form-control" th:placeholder="#{login.password}" required="">
    <div class="checkbox mb-3">
    <label>
    <input type="checkbox" value="remember-me"> [[#{login.remember}]]
    </label>
    </div>
    <button class="btn btn-lg btn-primary btn-block" type="submit">[[#{login.btn}]]</button>
    <p class="mt-5 mb-3 text-muted">© 2021-2022</p>
    <a class="btn btn-sm" th:href="@{/index.html(lan='zh_CN')}">中文</a>
    <a class="btn btn-sm" th:href="@{/index.html(lan='en_US')}">English</a>
    </form>
  2. 编写对应的controller

    LoginController.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.study.controller;

    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.thymeleaf.util.StringUtils;

    @Controller
    public class LoginController {
    @RequestMapping("/user/login")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model){
    //具体的业务
    if(!StringUtils.isEmpty(username) && "123456".equals(password)){
    return "redirect:/main.html"; //跳转到登录成功页面
    }else{
    //告诉用户登录失败
    model.addAttribute("msg","用户名或者密码错误!");
    return "index";
    }
    }
    }
  3. 若登录失败,需要将后台信息输出到前端展示给用户

    修改index.html,可以在首页标题下面加上判断

    1
    2
    <!--如果msg的值为空,则不显示消息-->
    <p style="color:red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
  4. 在MyMvcConfig中添加一个视图控制映射

    1
    registry.addViewController("/main.html").setViewName("dashboard");
  5. 防止表单重复提交,将 Controller 的代码改为重定向

    1
    2
    3
    if(!StringUtils.isEmpty(username) && "123456".equals(password)){
    return "redirect:/main.html"; //跳转到登录成功页面
    }
  6. 测试

    登录成功:

    QQ截图20221008213202

    登录失败:

    QQ截图20221008212658

5. 登录拦截器

问题:可以直接登录到后台主页,不用登录也可以实现

解决:可以使用拦截器机制,实现登录检查

拦截器实现步骤:

  1. 自定义一个拦截器

    LoginHandlerInterceptor.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package com.study.config;

    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    //自定义拦截器
    public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    //登录成功之后,应该有用户的session
    Object loginUser = request.getSession().getAttribute("loginUser");
    if(loginUser == null){
    request.setAttribute("msg","没有权限,请先登录");
    request.getRequestDispatcher("/index.html").forward(request,response);
    return false;
    }else{
    return true;
    }
    }
    }
  2. 将拦截器注册到SpringMVC配置类(MyMvcConfig.java)中

    1
    2
    3
    4
    5
    6
    @Override
    public void addInterceptors(InterceptorRegistry registry){
    registry.addInterceptor(new LoginHandlerInterceptor())
    .addPathPatterns("/**")
    .excludePathPatterns("/index.html","/","/user/login","/css/**","/js/**","/img/**");
    }
  3. 在后台主页,获取用户登录的信息

    修改dashboard.html

    1
    2
    <!--后台主页显示登录用户的信息-->
    [[${session.loginUser}]]
  4. 测试拦截器

    拦截成功,只有用户名和密码输入正确才会放行,其他情况拦截。

    QQ截图20221008220247

6. 展示员工列表

Restful风格

要求:需要使用 Restful风格实现我们的CRUD操作

普通CRUD(uri来区分操作) RestfulCRUD
查询 getEmp emp—GET
添加 addEmp?xxx emp—POST
修改 updateEmp?id=xxx&xxx=xx emp/{id}—PUT
删除 deleteEmo?id=1 emp/{id}—DELETE

项目具体需求:

项目功能 请求URI 请求方式
查询所有员工 emps GET
查询某个员工(来到修改页面) emp/1 GET
来到添加页面 emp GET
添加员工 emp POST
来到修改页面(查出员工进行信息回显) emp/1 GET
修改员工 emp PUT
删除员工 emp/1 DELETE

6.1 员工列表页面跳转

  1. 将首页的侧边栏Customers改为员工管理

  2. <a>链接添加请求

    1
    <a th:class="${active=='list.html'?'nav-link active':'nav-link'}" th:href="@{/emps}">
  3. 将list放在emp文件夹下

  4. 编写处理请求的controller

    EmployeeController.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.study.controller;

    import com.study.dao.EmployeeDao;
    import com.study.pojo.Employee;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;

    import java.util.Collection;

    @Controller
    public class EmployeeController {
    @Autowired
    EmployeeDao employeeDao;
    @RequestMapping("/emps")
    public String list(Model model){
    Collection<Employee> employees = employeeDao.getAll();
    model.addAttribute("emps",employees);
    return "emp/list";
    }
    }

6.2 Thymeleaf 公共页面元素抽取

侧边栏和顶部都相同,可以抽取出来变成公共组件,实现代码复用

实现步骤:

  1. 抽取公共片段 th:fragment 定义模板名
  2. 引入公共片段 th:insert 插入模板名

具体实现:

  1. 建立一个commons文件夹,存放公共页面

    公共页面元素抽取:commons.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!--组件,可以代码复用-->
    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">

    <!--头部导航栏-->
    <nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
    <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</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/#">注销</a>
    </li>
    </ul>
    </nav>

    <!--侧边栏-->
    <nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">
    ......
    </nav>

    </html>
  2. dashboard.html页面引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!--头部导航栏-->
    <div th:replace="~{commons/commons::topbar}"></div>

    <div class="container-fluid">
    <div class="row">

    <!--侧边栏-->
    <!--传递参数给组件:判断点击高亮-->
    <div th:replace="~{commons/commons::sidebar(active='main.html')}"></div>
    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
    ......
    </main>
    </div>
    </div>
  3. list.html页面引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!--引入抽取的topbar-->
    <!--模板名:会使用thymeleaf的前后缀配置规则进行解析使用~{模板::标签名}-->
    <!--头部导航栏-->
    <div th:replace="~{commons/commons::topbar}"></div>

    <div class="container-fluid">
    <div class="row">

    <!--侧边栏-->
    <!--传递参数给组件:判断点击高亮-->
    <div th:replace="~{commons/commons::sidebar(active='list.html')}"></div>
    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
    ......
    </main>
    </div>
    </div>

6.3 侧边栏激活

  1. 将首页的超链接地址改到项目中

  2. 在<a>标签中加一个判断,使用class改变标签的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <li class="nav-item">
    <a th:class="${active=='main.html'?'nav-link active':'nav-link'}" th:href="@{/index.html}">
    ......
    首页 <span class="sr-only">(current)</span>
    </a>
    </li>

    <li class="nav-item">
    <a th:class="${active=='list.html'?'nav-link active':'nav-link'}" th:href="@{/emps}">
    ......
    员工管理
    </a>
    </li>
  3. 修改请求链接

    dashboard.html

    1
    2
    <!--传递参数给组件:判断点击高亮-->
    <div th:replace="~{commons/commons::sidebar(active='main.html')}"></div>

    list.html

    1
    2
    <!--传递参数给组件:判断点击高亮-->
    <div th:replace="~{commons/commons::sidebar(active='list.html')}"></div>

6.4 员工信息页面展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
<h2>员工列表</h2>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th>id</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>department</th>
<th>birth</th>
</tr>
</thead>
<tbody>
<tr th:each="emp:${emps}">
<td th:text="${emp.getId()}"></td>
<td th:text="${emp.getLastName()}"></td>
<td th:text="${emp.getEmail()}"></td>
<td th:text="${emp.getGender()==0?'女':'男'}"></td>
<td th:text="${emp.department.getDepartmentName()}"></td>
<td th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
<td>
<button class="btn btn-sm btn-primary">编辑</button>
<button class="btn btn-sm btn-danger">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
</main>

测试:

QQ截图20221011203103

7. 增加员工实现

7.1 表单及细节优化

  1. 将添加员工信息改为超链接

    list.html

    1
    2
    <!--添加员工按钮-->
    <h2><a class="btn btn-sm btn-success" th:href="@{/emp}">添加员工</a></h2>
  2. 编写对应的controller

    1
    2
    3
    4
    5
    //跳转到员工添加页面
    @GetMapping("/emp")
    public String toAddPage(Model model){
    return "emp/add";
    }
  3. 编写前端添加表单add.html

    add.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    ...
    <form th:action="@{/emp}" method="post">
    <div class="form-group">
    <label>LastName</label>
    <input type="text" name="lastName" class="form-control" placeholder="林慕椿">
    </div>
    <div class="form-group">
    <label>Email</label>
    <input type="email" name="email" class="form-control" placeholder="2746200911@qq.com">
    </div>
    <div class="form-group">
    <label>Gender</label><br/>
    <div class="form-check form-check-inline">
    <input class="form-check-input" type="radio" name="gender" value="1">
    <label class="form-check-label"></label>
    </div>
    <div class="form-check form-check-inline">
    <input class="form-check-input" type="radio" name="gender" value="0">
    <label class="form-check-label"></label>
    </div>
    </div>
    <div class="form-group">
    <label>department</label>
    <!--在controller接收的是一个Employee,需要提交的是其中的一个属性-->
    <select class="form-control" name="department.id">
    <option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="$dept.getId()"></option>
    </select>
    </div>
    <div class="form-group">
    <label>Birth</label>
    <input type="text" name="birth" class="form-control" placeholder="2002/02/02">
    </div>
    <button type="submit" class="btn btn-primary">添加</button>
    </form>
    ...
  4. 部门信息下拉框应该选择的是提供的数据,修改一下前端和后端

    后端controller:

    1
    2
    3
    4
    5
    6
    7
    8
    //跳转到员工添加页面
    @GetMapping("/emp")
    public String toAddPage(Model model){
    //查出所有部门的信息
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "emp/add";
    }

    前端:

    1
    2
    3
    4
    5
    6
    7
    <div class="form-group">
    <label>department</label>
    <!--在controller接收的是一个Employee,需要提交的是其中的一个属性-->
    <select class="form-control" name="department.id">
    <option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>
    </select>
    </div>

7.2 添加员工实现

  1. 修改add页面form表单提交地址和方式

    1
    2
    3
    <form th:action="@{/emp}" method="post">
    ......
    </form>
  2. 编写controller接收

    1
    2
    3
    4
    5
    6
    7
    8
    //添加、修改成功后重定向到列表页
    @PostMapping("/emp")
    public String addEmp(Employee employee){
    System.out.println("save=>"+employee);
    //添加操作
    employeeDao.save(employee); //调用底层业务方法保存员工信息
    return "redirect:/emps";
    }
  3. 跳转和接收完整controller层

    EmployeeController.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    @Controller
    public class EmployeeController {
    @Autowired
    EmployeeDao employeeDao;
    @Autowired
    DepartmentDao departmentDao;

    //跳转到员工添加页面
    @GetMapping("/emp")
    public String toAddPage(Model model){
    //查出所有部门的信息
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "emp/add";
    }

    //添加成功后重定向到列表页
    @PostMapping("/emp")
    public String addEmp(Employee employee){
    System.out.println("save=>"+employee);
    //添加操作
    employeeDao.save(employee); //调用底层业务方法保存员工信息
    return "redirect:/emps";
    }
    }
  4. 测试

    添加页面:

    QQ截图20221012110041

    添加成功页面:

    QQ截图20221012110030

8. 修改员工信息

8.1 日期格式化

因为这个错误卡了很久!😭

SpringMVC会将页面提交的值转换为指定的类型,默认日期是按照 / 的方式提交,比如将 2019/01/01 转换为一个date对象。

日期格式化:

在配置类中自定义的去修改时间格式化问题

1
2
3
4
#配置文件的真实位置
spring.messages.basename=i18n/login
#时间日期格式化
spring.mvc.date-format=yyyy-MM-dd

使用:

1
th:value="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"

8.2 修改员工信息

实现步骤:

  1. 点击编辑按钮,跳转到修改员工信息页面
  2. 显示原数据,修改完员工信息后重定向到列表页面

具体实现:

  1. 修改跳转链接位置

    1
    <a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.getId()}">编辑</a>
  2. 编写对应的controller

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //跳转到员工修改页面
    @GetMapping("/emp/{id}")
    public String toUpdateEmp(@PathVariable("id")Integer id,Model model){
    //查询出来原来的数据
    Employee employee = employeeDao.getEmployeeById(id);
    model.addAttribute("emp",employee);
    //查出所有部门的信息
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "emp/update";
    }
  3. 编写修改员工信息页面

    update.html(复制add.html页面后修改)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    <form th:action="@{/emp}" method="post">

    <!--携带id和隐藏域-->
    <input type="hidden" name="id" th:value="${emp.getId()}">

    <div class="form-group">
    <label>LastName</label>
    <input th:value="${emp.getLastName()}" type="text" name="lastName" class="form-control">
    </div>
    <div class="form-group">
    <label>Email</label>
    <input th:value="${emp.getEmail()}" type="email" name="email" class="form-control">
    </div>
    <div class="form-group">
    <label>Gender</label><br/>
    <div class="form-check form-check-inline">
    <input th:checked="${emp.getGender==1}" class="form-check-input" type="radio" name="gender" value="1">
    <label class="form-check-label"></label>
    </div>
    <div class="form-check form-check-inline">
    <input th:checked="${emp.getGender==0}" class="form-check-input" type="radio" name="gender" value="0">
    <label class="form-check-label"></label>
    </div>
    </div>
    <div class="form-group">
    <label>department</label>
    <!--在controller接收的是一个Employee,需要提交的是其中的一个属性-->
    <select class="form-control" name="department.id">
    <option th:selected="${dept.getId()==emp.getDepartment.getId()}" th:each="dept:${departments}"
    th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>
    </select>
    </div>
    <div class="form-group">
    <label>Birth</label>
    <input th:value="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}" type="text" name="birth" class="form-control">
    </div>
    <button type="submit" class="btn btn-primary">修改</button>
    </form>
  4. 日期格式化

    1
    <input th:value="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}" type="text" name="birth" class="form-control">
  5. 修改表单提交的地址

    1
    2
    3
    <form th:action="@{/emp}" method="post">
    ......
    </form>
  6. 编写对应的controller

    1
    2
    3
    4
    5
    6
    7
    8
    //添加、修改成功后重定向到列表页
    @PostMapping("/emp")
    public String addEmp(Employee employee){
    System.out.println("save=>"+employee);
    //添加操作
    employeeDao.save(employee); //调用底层业务方法保存员工信息
    return "redirect:/emps";
    }
  7. 测试

    修改前:

    QQ截图20221012204640

    修改后:

    QQ截图20221012204733

9. 删除及404处理

9.1 删除员工信息

  1. list页面编写提交地址

    1
    <a class="btn btn-sm btn-danger" th:href="@{/deleteEmp/}+${emp.getId()}">删除</a>
  2. 编写Controller

    1
    2
    3
    4
    5
    6
    //删除员工信息
    @GetMapping("/deleteEmp/{id}")
    public String deleteEmp(@PathVariable("id")int id){
    employeeDao.delete(id);
    return "redirect:/emps";
    }
  3. 测试

9.2 404处理

  1. 在templates模板目录下添加一个error文件夹,文件夹存放相应的错误页面,例如:404.html,4xx.html…,SpringBoot会自动使用

  2. 测试

    QQ截图20221012212029

9.3 注销处理

  1. 注销请求

    修改common.html

    1
    <a class="nav-link" th:href="@{/user/logout}">注销</a>
  2. 对应的controller

    1
    2
    3
    4
    5
    6
    //删除员工信息
    @GetMapping("/deleteEmp/{id}")
    public String deleteEmp(@PathVariable("id")int id){
    employeeDao.delete(id);
    return "redirect:/emps";
    }

10. 项目目录结构

QQ截图20221012213713

QQ截图20221012213803


SpringBoot-员工管理系统
https://yiqiangshiyia.cn/2022/10/08/SpringBoot-员工管理系统/
作者
一腔诗意啊
发布于
2022年10月8日
许可协议