员工管理系统

该项目实现了以下功能,对应的源码与数据库文件在资源中可下载
在这里插入图片描述
项目部分展示
在这里插入图片描述

1. 数据库设计

创建数据库 employee,创建两个表 employee(员工表)和depart(部门表)

在这里插入图片描述

在这里插入图片描述

2. 后端部分

2.1 创建SpringBoot项目,导入依赖

<!--数据库连接-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybaits-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.1.2</version>
</dependency>
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!--thymeleaf模板引擎-->
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<!--web-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.2 配置文件

spring:
  messages:
    basename: i18n.login  # 国际化配置
  datasource:             # 数据源配置
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/employee?serverTimezone=GMT%2b8&useSSL=true&useUnicode=true&characterEncoding=utf-8
    username: root
    password: root

mybatis-plus:   # mybatis-plus配置
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志输出
  mapper-locations: classpath:mapper/*.xml  # xml文件的位置配置
  type-aliases-package: com.hua.pojo        # 别名

2.3 实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
    @TableId(type = IdType.AUTO)               // 自增  数据库该字段也要设计自增
    private Integer id;       // 员工编号
    private String name;      // 员工姓名
    private String password;  // 账号密码
    private Integer age;      // 员工年龄
    private Integer sex;      // 员工性别  1 男 0 女
    private String phone;     // 联系方式
    private Date birth;       // 员工生日
    @TableField(fill = FieldFill.INSERT)        // 此字段添加操作时自动填充
    private Date createtime;  // 创建时间
    @TableField(fill = FieldFill.INSERT_UPDATE) // 此字段添加、更新操作时自动填充
    private Date updatetime;  // 修改时间
    @Version
    private Integer version;  // 乐观锁
    @TableLogic
    private Integer deleted;  // 逻辑删除
    private Integer departid; // 员工部门编号
    @TableField(updateStrategy = FieldStrategy.NEVER)  // 此字段不更新
    private Depart depart;    // 员工部门
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Depart {
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String name;
    @TableField(fill = FieldFill.INSERT)
    private Date createtime;  // 创建时间
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updatetime;  // 修改时间
    @Version
    private Integer version;  // 乐观锁
    @TableLogic
    private Integer deleted;  // 逻辑删除
}

2.4 自己的编写的配置

import java.util.Date;
// 自动填充配置
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createtime",new Date(),metaObject); // 添加时填充createtime字段为当前的时间
        this.setFieldValByName("updatetime",new Date(),metaObject); // 添加时填充updatetime字段为当前的时间
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updatetime",new Date(),metaObject); // 更新时填充updatetime字段为当前的时间
    }
}
// mybatis-plus的相关配置
@Configuration
public class MyBatisConfig {
    @Bean // 配置乐观锁
    OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
    @Bean // 配置逻辑删除
    ISqlInjector iSqlInjector(){
        return new LogicSqlInjector();
    }
}

2.5 dao层

@Repository
@Mapper  // 配置扫描该包
public interface DepartDao extends BaseMapper<Depart> {  // 继承BaseMapper 获取基本的CRUD操作

}
@Repository
@Mapper    // 配置扫描该包
public interface EmployeeDao extends BaseMapper<Employee>{ // 继承BaseMapper 获取基本的CRUD方法
    // 查询所有员工
    List<Employee> getEmpList();   // 扩展自己的CRUD方法
    // 根据姓名查询员工
    Employee getEmployeeByName(@Param("name") String name);
    // 根据id查询员工
    Employee getEmployeeByID(@Param("id") int id);
}

EmployeeDao对应的xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hua.dao.EmployeeDao">
    <resultMap id="employeedepart" type="employee">
        <result property="id" column="id"></result>
        <result property="name" column="name"></result>
        <result property="password" column="password"></result>
        <result property="age" column="age"></result>
        <result property="sex" column="sex"></result>
        <result property="phone" column="phone"></result>
        <result property="birth" column="birth"></result>
        <result property="createtime" column="createtime"></result>
        <result property="updatetime" column="updatetime"></result>
        <result property="version" column="version"></result>
        <result property="deleted" column="deleted"></result>
        <result property="departid" column="departid"></result>
        <association property="depart" javaType="depart">
            <result property="id" column="did"></result>
            <result property="name" column="dname"></result>
            <result property="createtime" column="dcreatetime"></result>
            <result property="updatetime" column="dupdatetime"></result>
            <result property="version" column="dversion"></result>
            <result property="deleted" column="ddeleted"></result>
        </association>
    </resultMap>

    <select id="getEmpList" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted
        from depart d,employee e
        where d.id = e.departid
    </select>

    <select id="getEmployeeByName" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted
        from depart d,employee e
        where d.id = e.departid and e.name = #{name}
    </select>

    <select id="getEmployeeByID" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted
        from depart d,employee e
        where d.id = e.departid and e.id = #{id}
    </select>

    <select id="login" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted
        from depart d,employee e
        where d.id = e.departid and e.name = #{username} and e.password = #{password}
    </select>
</mapper>

2.6 service层

public interface DepartService {
    // 通过id获取部门信息
    Depart getDepartByID(int id);
    // 获取所有的部门信息
    List<Depart> getDepartList();
    // 通过id删除部门
    int delete(int id);
    // 通过id更新部门
    int update(Depart depart);
    // 增加部门
    int add(Depart depart);
}

DepartService对应的实现类

@Service
public class DepartServiceImpl implements DepartService{

    @Autowired
    DepartDao departDao;  // 调用dao层

    /**
     * selectById()、selectList()、deleteById()、updateById()、insert()
     * 这些都是继承BaseMapper之后 就直接可以使用的
     * */
    @Override
    public Depart getDepartByID(int id) {
        return departDao.selectById(id);
    }

    @Override
    public List<Depart> getDepartList() {
        return departDao.selectList(null);
    }

    @Override
    public int delete(int id) {
        return departDao.deleteById(id);
    }

    @Override
    public int update(Depart depart) { // 需要用到乐观锁,需要先获取depart对象,再对其进行修改
        Depart departByID = this.getDepartByID(depart.getId()); 
        departByID.setName(depart.getName());
        return departDao.updateById(departByID);
    }

    @Override
    public int add(Depart depart) {
        return departDao.insert(depart);
    }
}
public interface EmployeeService {
    // 增加员工
    int add(Employee employee);
    // 查询所有员工
    List<Employee> getEmployeeList();
    // 根据id查询员工
    Employee getEmployeeByID(int id);
    // 根据姓名查询员工
    Employee getEmployeeByName(String name);
    // 根据id删除员工
    int delete(int id);
    // 根据id更新员工
    int update(Employee employee);
}

EmployeeService对应的实现类

@Service
public class EmployeeServiceImpl implements EmployeeService{

    @Autowired
    EmployeeDao employeeDao; // 调用dao层

    @Override
    public int add(Employee employee) {
        return employeeDao.insert(employee);
    }

    @Override
    public List<Employee> getEmployeeList() {
        return employeeDao.getEmpList(); // 调用自己的方法
    }

    @Override
    public Employee getEmployeeByID(int id) {
        return employeeDao.getEmployeeByID(id);// 调用自己的方法
    }

    @Override
    public Employee getEmployeeByName(String name) {
        return employeeDao.getEmployeeByName(name);
    } // 调用自己的方法

    @Override
    public int delete(int id) {
        return employeeDao.deleteById(id);
    }

    @Override
    public int update(Employee employee) {
        Employee employeeByID = employeeDao.getEmployeeByID(employee.getId());
        employeeByID.setName(employee.getName());
        employeeByID.setPassword(employee.getPassword());
        employeeByID.setAge(employee.getAge());
        employeeByID.setSex(employee.getSex());
        employeeByID.setPhone(employee.getPhone());
        employeeByID.setBirth(employee.getBirth());
        employeeByID.setDepartid(employee.getDepartid());
        /**
         * 注意此处的employee属性的部门对象在数据库中并没有存储,所以不需要进行更新,
         * 只更新其另加的部门id字段即可,但是mybatis-plus默认的更新策略时更新所有不为空的字段,
         * 在更新的时候sql语句中会有部门对象的字段,此时就需要修改employee实体类的该字段的
         * 更新策略,改为never,这样sql语句中就不会再出现该字段
         * */
        //
        return employeeDao.updateById(employeeByID);
    }
}

3. 登录页面国际化

在这里插入图片描述

创建自己的国际化解析器

// 国际化的解析器
public class MyLocaleResolver implements LocaleResolver {
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String language = request.getParameter("language");
        Locale locale = Locale.getDefault(); // 如果language为空就是使用默认的
        if(!StringUtils.isEmpty(language)){
            String[] s = language.split("_");
            locale = new Locale(s[0],s[1]);
        }
        return locale;
    }

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

    }
}

将自己的解析器注册

@Configuration
// 自己的mvc配置
public class MyMVCConfig implements WebMvcConfigurer {
    @Override // 配置路由
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
        registry.addViewController("/main.html").setViewName("dashboard");
    }
    // 注册解析器
    @Bean
    LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }
}

修改首页,相应的提示文字要修改

在这里插入图片描述

4. 登录功能

dao层

Employee login(@Param("username") String username,@Param("password") String password);

xml

<select id="login" resultMap="employeedepart">
    select e.*,d.id as did,d.name as dname
    from depart d,employee e
    where d.id = e.departid and e.name = #{username} and e.password = #{password}
</select>

service层

// 姓名和密码进行登录
Employee login(String username,String password);

实现类

@Override
public Employee login(String username, String password) {
    return employeeDao.login(username,password);
}

前端页面

<body class="text-center">
    <form class="form-signin" th:action="@{/login}">
        <img class="mb-4" th:src="@{asserts/img/bootstrap-solid.svg}" alt="" width="72" height="72">
        <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}"></h1>
        <h4 style="color: red" th:text="${msg}"></h4>
        <label class="sr-only">Username</label>
        <input type="text" name="username" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
        <br/>
        <label class="sr-only">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">© 2017-2018</p>
        <a class="btn btn-sm" th:href="@{/index.html(language='zh_CN')}">中文</a>
        <a class="btn btn-sm" th:href="@{/index.html(language='en_US')}">English</a>
    </form>
</body>

controller

@RequestMapping("/login")
public String login(String username, String password, Model model, HttpSession session){
    Employee employee = employeeService.login(username, password);
    if (!StringUtils.isEmpty(employee)){
        session.setAttribute("employee",employee);
        return "redirect:/main.html"; // 重定向到首页
    }else {
        model.addAttribute("msg","用户名或者密码不正确");
        return "index";
    }
}

登录拦截器

public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        Object employee = session.getAttribute("employee");
        if(employee == null){ // 未登录,跳转到登录页,提示以下信息
            request.setAttribute("msg","无法访问,请先登录...");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false; // 进行拦截
        }else {
            return true;  // 放行
        }
    }
}

将拦截器注册到容器

@Configuration
// 自己的mvc配置
public class MyMVCConfig implements WebMvcConfigurer {
    @Override // 配置路由
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
        registry.addViewController("/main.html").setViewName("dashboard");
    }
    // 注册解析器
    @Bean
    LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }

    // 拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginHandlerInterceptor())
                .addPathPatterns("/**")  // 拦截所有请求
                .excludePathPatterns("/index.html","/","/login","/css/**","/js/**","/img/**"); // 对这些请求放行
    }
}

5. 注销功能

// controller层
@RequestMapping("/logout")
public String logout(HttpSession session){
    Object employee = session.getAttribute("employee");
    if(employee==null)  // 未登录 直接跳转登录页
        return "index";
	}else {
    	session.removeAttribute("employee"); // 已登录 清除session 跳转登录页
    	return "index";
	}
}

6. 公共页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
  <link rel="stylesheet" th:href="@{/asserts/icon/iconfont.css}">
</head>
<body>
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="navbar">
  <a class="navbar-brand col-sm-3 col-md-2 mr-0" th:href="@{/main.html}">欢迎您 [[${session.employee.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" th:href="@{/logout}">退出登录</a>
    </li>
  </ul>
</nav>


<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">
  <div class="sidebar-sticky">
    <ul class="nav flex-column">
      <li class="nav-item">
        <a class="nav-link active" th:href="@{/main.html}">
          首页
        </a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">
          xxxxx
        </a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">
          部门管理
        </a>
      </li>
      <li class="nav-item">
        <a class="nav-link" th:href="@{/emp/list}">
          员工管理
        </a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">
          xxxxx
        </a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">
          xxxxx
        </a>
      </li>
    </ul>
  </div>
</nav>
</body>
</html>

7. 员工展示页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.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>员工列表</title>
    <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">

    <style>
        tr{
            /*表格内容居中显示*/
            text-align: center;
        }
    </style>
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
    <div class="row">
        <!--引入公共侧边栏-->
        <div th:insert="~{commons/commons::sidebar}"></div>
        <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>工号</th>
                        <th>姓名</th>
                        <th>年龄</th>
                        <th>性别</th>
                        <th>联系方式</th>
                        <th>生日</th>
                        <th>部门</th>
                        <th>创建日期</th>
                        <th>修改日期</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    <!--循环遍历后端传来的列表-->
                    <tr th:each="employee:${employeeList}">
                        <td th:text="${employee.id}"></td>
                        <td th:text="${employee.name}"></td>
                        <td th:text="${employee.age}"></td>
                        <td th:text="${employee.sex==0?'':''}"></td>
                        <td th:text="${employee.phone}"></td>
                        <!--格式化日期输出-->
                        <td th:text="${#dates.format(employee.birth,'yyyy-MM-dd')}"></td>
                        <td th:text="${employee.depart.name}"></td>
                        <td th:text="${#dates.format(employee.createtime,'yyyy-MM-dd HH:mm:ss')}"></td>
                        <td th:text="${#dates.format(employee.updatetime,'yyyy-MM-dd HH:mm:ss')}"></td>
                        <td>
                            <a class="btn btn-sm btn-primary" th:href="@{#}">修改</a>
                            <a class="btn btn-sm btn-danger"  th:href="@{#}">删除</a>
                        </td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </main>
    </div>
</div>
</body>
</html>

controller

@RequestMapping("/emp/list")
public String list(Model model){
    List<Employee> employeeList = employeeService.getEmployeeList();
    model.addAttribute("employeeList",employeeList);
    return "list";
}

8. 添加员工

<!--在列表界面添加按钮-->
<h3><a class="btn  btn-success" style="float: right" th:href="@{/emp/toAdd}">添加员工</a></h3>

跳转添加页面

@RequestMapping("/emp/toAdd")
public String toAdd(Model model){
    List<Depart> departList = departService.getDepartList();
    model.addAttribute("departList",departList);
    return "emp/add";
}

添加页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.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>添加员工</title>
  <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
  <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
  <div class="row">
    <!--引入公共侧边栏-->
    <div th:insert="~{commons/commons::sidebar}"></div>
    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
      <form th:action="@{/emp/add}" method="post">
        <div class="form-group">
          <label>姓名</label>
          <input type="text" name="name" class="form-control">
        </div>
        <div class="form-group">
          <label>密码</label>
          <input type="password" name="password" class="form-control">
        </div>
        <div class="form-group">
          <label>年龄</label>
          <input type="text" name="age" class="form-control">
        </div>
        <div class="form-group">
          <label>性别</label><br/>
          <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="sex" value="1">
            <label class="form-check-label"></label>
          </div>
          <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="sex" value="0">
            <label class="form-check-label"></label>
          </div>
        </div>
        <div class="form-group">
          <label>联系方式</label>
          <input type="text" name="phone" class="form-control">
        </div>
        <div class="form-group">
          <label>生日</label>   <!--注意此处的日期格式  SpringBoot默认格式为 1778/12/12 12:12:12 可以在配置文件修改-->
          <input type="text" class="form-control" placeholder="例如:1778-12-12" name="birth">
        </div>
        <div class="form-group">
          <label>部门</label>
          <!--注意这边应该不是department-->
          <select class="form-control" name="departid">
            <option th:each="department:${departList}" th:value="${department.id}">[[${department.name}]]</option>
          </select>
        </div>
        <button type="submit" class="btn btn-primary">添加</button>
      </form>
    </main>
  </div>
</div>
</body>
</html>

配置文件

spring:
  messages:
    basename: i18n.login  # 国际化配置
  datasource:             # 数据源配置
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/employee?serverTimezone=GMT%2b8&useSSL=true&useUnicode=true&characterEncoding=utf-8
    username: root
    password: root
  thymeleaf: 
    cache: false  # 关闭thymeleaf的缓存
  mvc:
    format:
      date: yyyy-MM-dd HH:mm:ss # 修改默认日期格式
mybatis-plus:   # mybatis-plus配置
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志输出
  mapper-locations: classpath:mapper/*.xml  # xml文件的位置配置
  type-aliases-package: com.hua.pojo        # 别名

添加

@RequestMapping("/emp/add")
public String add(Employee employee){
    employeeService.add(employee);
    return "redirect:/emp/list";
}

9. 修改员工

<a class="btn btn-sm btn-primary" th:href="@{/emp/toUpdate/}+${employee.id}">修改</a>

跳转修改页面

@RequestMapping("/emp/toUpdate/{id}")
public String toUpdate(@PathVariable("id") int id,Model model){ // 需要将指定id的员工信息和部门列表返回
    Employee employeeByID = employeeService.getEmployeeByID(id);
    model.addAttribute("employee",employeeByID);
    List<Depart> departList = departService.getDepartList();
    model.addAttribute("departList",departList);
    return "emp/update";
}

修改页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.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>添加员工</title>
  <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
  <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
  <div class="row">
    <!--引入公共侧边栏-->
    <div th:insert="~{commons/commons::sidebar}"></div>
    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
      <form th:action="@{/emp/update}" method="post">
        <input type="hidden" name="id" th:value="${employee.id}">
        <div class="form-group">
          <label>姓名</label>
          <input type="text" name="name" th:value="${employee.name}"  class="form-control">
        </div>
        <div class="form-group">
          <label>密码</label>
          <input type="text" name="password" th:value="${employee.password}" class="form-control">
        </div>
        <div class="form-group">
          <label>年龄</label>
          <input type="text" name="age" th:value="${employee.age}" class="form-control">
        </div>
        <div class="form-group">
          <label>性别</label><br/>
          <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="sex" value="1" th:checked="${employee.sex==1}">
            <label class="form-check-label"></label>
          </div>
          <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="sex" value="0" th:checked="${employee.sex==0}">
            <label class="form-check-label"></label>
          </div>
        </div>
        <div class="form-group">
          <label>联系方式</label>
          <input type="text" name="phone" th:value="${employee.phone}" class="form-control">
        </div>
        <div class="form-group">
          <label>生日</label>
          <!--注意此处的日期格式  SpringBoot默认格式为 1778/12/12 12:12:12 可以在配置文件修改-->
          <input type="text" class="form-control" th:value="${employee.birth.toLocaleString()}" placeholder="例如:1778-12-12" name="birth">
        </div>
        <div class="form-group">
          <label>部门</label>
          <select class="form-control" name="departid">
            <option th:each="department:${departList}" th:value="${department.id}" th:selected="${employee.departid==department.id}">[[${department.name}]]</option>
          </select>
        </div>
        <button type="submit" class="btn btn-primary">修改</button>
      </form>
    </main>
  </div>
</div>
</body>
</html>

修改操作

@RequestMapping("/emp/update")
public String update(Employee employee){
    System.out.println(employee);
    employeeService.update(employee);
    return "redirect:/emp/list";
}

10. 删除员工

<a class="btn btn-sm btn-danger"  th:href="@{/emp/delete/}+${employee.id}">删除</a>

删除操作

@RequestMapping("/emp/delete/{id}")
public String delete(@PathVariable("id") int id){
    employeeService.delete(id);
    return "redirect:/emp/list";
}

此时出现一个问题,发现数据库中已经删除,但是列表中还会查到员工,原因是用到了逻辑删除,而sql语句不是使用mybatis-plus原生的语句,是自己编写的,所以where条件中需要添加 deleted = 0

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hua.dao.EmployeeDao">
   <resultMap id="employeedepart" type="employee">
       <result property="id" column="id"></result>
       <result property="name" column="name"></result>
       <result property="password" column="password"></result>
       <result property="age" column="age"></result>
       <result property="sex" column="sex"></result>
       <result property="phone" column="phone"></result>
       <result property="birth" column="birth"></result>
       <result property="createtime" column="createtime"></result>
       <result property="updatetime" column="updatetime"></result>
       <result property="version" column="version"></result>
       <result property="deleted" column="deleted"></result>
       <result property="departid" column="departid"></result>
       <association property="depart" javaType="depart">
           <result property="id" column="did"></result>
           <result property="name" column="dname"></result>
           <result property="createtime" column="dcreatetime"></result>
           <result property="updatetime" column="dupdatetime"></result>
           <result property="version" column="dversion"></result>
           <result property="deleted" column="ddeleted"></result>
       </association>
   </resultMap>

    <select id="getEmpList" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted
        from depart d,employee e
        where d.id = e.departid and e.deleted = 0
    </select>

    <select id="getEmployeeByName" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted
        from depart d,employee e
        where d.id = e.departid and e.name = #{name} and e.deleted = 0
    </select>

    <select id="getEmployeeByID" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted
        from depart d,employee e
        where d.id = e.departid and e.id = #{id} and e.deleted = 0
    </select>

    <select id="login" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted
        from depart d,employee e
        where d.id = e.departid and e.name = #{username} and e.password = #{password} and e.deleted = 0
    </select>
</mapper>

11. 查询员工

通过名字模糊查询 或者 通过部门名字查询

dao层

// 用户名或部门查询
List<Employee> get(@Param("name") String name,@Param("departid") int departid);

xml文件

<select id="get" resultMap="employeedepart">
    select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted
    from depart d,employee e
    <where>   <!--此处用到了mybatis的模糊查询-->
        d.id = e.departid and e.deleted = 0
        <if test="name!=null">  <!--如果name不为空,就加上下边一条查询语句-->
            and e.name like "%"#{name}"%"
        </if>
        <if test="departid!=0"> <!--如果departid不为0,就加上下边一条查询语句-->
            and e.departid = #{departid}
        </if>
    </where>
</select>

service层

// 名字或部门进行查询
List<Employee> get(String name,int id);

service实现类

@Override
public List<Employee> get(String name, int id) {
    if (StringUtils.isEmpty(name)){  // 此处需要判断一下,因为传来的值,可能为null也可能为"",而sql语句只判断了空值,所以将两种可能全部赋值为null
        name=null;
    }
    return employeeDao.get(name,id);
}

前端页面

<form class="form-inline" role="form" th:action="@{/emp/get}">
    <div class="form-group col-lg-3">
        员工姓名:<input type="text" name="name" class="form-control" placeholder="请输入员工姓名">
    </div>
    <div class="form-group col-lg-3">
        部门:<select name="departid">
        <option value="0">---请选择---</option>
        <option th:each="depart:${departList}" th:value="${depart.id}" th:text="${depart.name}"></option>
        </select>
    </div>
    <div class="form-group col-lg-3" >
        <input type="submit" value="查询">
    </div>
</form>

controller

@RequestMapping("/emp/list")
public String list(Model model){
    List<Employee> employeeList = employeeService.getEmployeeList();
    System.out.println(employeeList);
    model.addAttribute("employeeList",employeeList);
    List<Depart> departList = departService.getDepartList();
    model.addAttribute("departList",departList);  // 需要修改之前进行员工列表界面所携带的参数,将部门列表加上
    return "emp/list";
}
@RequestMapping("/emp/get")
public String get(String name,String departid,Model model){
    List<Employee> employeeList = employeeService.get(name, Integer.parseInt(departid));
    model.addAttribute("employeeList",employeeList);
    List<Depart> departList = departService.getDepartList();
    model.addAttribute("departList",departList); // 需要注意的是   此处仍需要传部门列表
    return "emp/list";
}

12. 部门的CRUD与员工的类似,相对简单 直接上代码

12.1 后端代码

dao层

@Repository
@Mapper  // 配置扫描该包
public interface DepartDao extends BaseMapper<Depart> {  // 继承BaseMapper 获取基本的CRUD操作

}

没有附加自己的sql语句,所以没有.xml文件

service层

public interface DepartService {
    // 通过id获取部门信息
    Depart getDepartByID(int id);
    // 获取所有的部门信息
    List<Depart> getDepartList();
    // 通过id删除部门
    int delete(int id);
    // 通过id更新部门
    int update(Depart depart);
    // 增加部门
    int add(Depart depart);
}

实现类

@Service
public class DepartServiceImpl implements DepartService{

    @Autowired
    DepartDao departDao;  // 调用dao层

    /**
     * selectById()、selectList()、deleteById()、updateById()、insert()
     * 这些都是继承BaseMapper之后 就直接可以使用的
     * */
    @Override
    public Depart getDepartByID(int id) {
        return departDao.selectById(id);
    }

    @Override
    public List<Depart> getDepartList() {
        return departDao.selectList(null);
    }

    @Override
    public int delete(int id) {
        return departDao.deleteById(id);
    }

    @Override
    public int update(Depart depart) { // 需要用到逻辑删除,需要先获取depart对象,再对其进行修改
        Depart departByID = this.getDepartByID(depart.getId());
        departByID.setName(depart.getName());
        return departDao.updateById(departByID);
    }

    @Override
    public int add(Depart depart) {
        return departDao.insert(depart);
    }
}

12.2 部门展示

controller

@RequestMapping("/dep/list")
public String list(Model model){
    List<Depart> departList = departService.getDepartList();
    model.addAttribute("departList",departList); 
    return "dep/list";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.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>员工列表</title>
  <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
  <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">

  <style>
    tr{
      /*表格内容居中显示*/
      text-align: center;
    }
  </style>
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
  <div class="row">
    <!--引入公共侧边栏-->
    <div th:insert="~{commons/commons::sidebar}"></div>
    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
      <h2>部门列表</h2>
      <h3><a class="btn  btn-success" style="float: right" th:href="@{/dep/toAdd}">添加部门</a></h3>
      <br/>
      <div class="table-responsive">
        <table class="table table-striped table-sm">
          <thead>
          <tr>
            <th>部门编号</th>
            <th>部门名称</th>
            <th>创建时间</th>
            <th>修改时间</th>
            <th>操作</th>
          </tr>
          </thead>
          <tbody>
          <!--循环遍历后端传来的列表-->
          <tr th:each="depart:${departList}">
            <td th:text="${depart.id}"></td>
            <td th:text="${depart.name}"></td>
            <td th:text="${#dates.format(depart.createtime,'yyyy-MM-dd HH:mm:ss')}"></td>
            <td th:text="${#dates.format(depart.updatetime,'yyyy-MM-dd HH:mm:ss')}"></td>
            <td>
              <a class="btn btn-sm btn-primary" th:href="@{/dep/toUpdate/}+${depart.id}">修改</a>
              <a class="btn btn-sm btn-danger"  th:href="@{/dep/delete/}+${depart.id}">删除</a>
            </td>
          </tr>
          </tbody>
        </table>
      </div>
    </main>
  </div>
</div>
</body>
</html>

12.3 增加部门

controller

@RequestMapping("/dep/toAdd")
public String toAdd(){
    return "dep/add";  // 跳转到增加页面
}
@RequestMapping("/dep/add")
public String add(Depart depart){
    departService.add(depart);  // 增加操作
    return "redirect:/dep/list";
}

前端页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.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>添加部门</title>
    <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
    <div class="row">
        <!--引入公共侧边栏-->
        <div th:insert="~{commons/commons::sidebar}"></div>
        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <form th:action="@{/dep/add}" method="post">
                <div class="form-group">
                    <label>部门名称</label>
                    <input type="text" name="name" class="form-control">
                </div>
                <button type="submit" class="btn btn-primary">添加</button>
            </form>
        </main>
    </div>
</div>
</body>
</html>

12.4 修改部门

controller

@RequestMapping("/dep/toUpdate/{id}")  // 跳转到修改页面 需要携带该部门的信息
public String toUpdate(@PathVariable("id") int id,Model model){
    Depart departByID = departService.getDepartByID(id);
    model.addAttribute("depart",departByID);
    return "dep/update";
}
@RequestMapping("/dep/update")
public String update(Depart depart){
    departService.update(depart);  // 修改操作
    return "redirect:/dep/list";
}

前端页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.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>添加员工</title>
    <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
    <div class="row">
        <!--引入公共侧边栏-->
        <div th:insert="~{commons/commons::sidebar}"></div>
        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <form th:action="@{/dep/update}" method="post">
                <input type="hidden" name="id" th:value="${depart.id}">
                <div class="form-group">
                    <label>部门名称</label>
                    <input type="text" name="name" th:value="${depart.name}"  class="form-control">
                </div>
                <button type="submit" class="btn btn-primary">修改</button>
            </form>
        </main>
    </div>
</div>
</body>
</html>

12.5 删除部门

controller

@RequestMapping("/dep/delete/{id}")
public String delete(@PathVariable("id") int id){
    departService.delete(id);
    return "redirect:/dep/list";
}
}

13. 角色管理

现在想要新增一个表,角色表,员工属性中也有对应的角色信息,另外使用shiro进行权限管理,对于员工的管理进行了修改。

添加依赖

<!--shiro与thymeleaf整合包-->
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.1.0</version>
</dependency>
<!--shiro-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.7.1</version>
</dependency>

13.1 数据库设计

员工表

在这里插入图片描述

角色表

在这里插入图片描述

13.2 后端

实体类

// 员工实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee implements Serializable {
    @TableId(type = IdType.AUTO)
    private Integer id;       // 员工编号
    private String name;      // 员工姓名
    private String password;  // 账号密码
    private Integer age;      // 员工年龄
    private Integer sex;      // 员工性别  1 男 0 女
    private String phone;     // 联系方式
    private Date birth;       // 员工生日
    private Integer role;     // 角色编号
    @TableField(updateStrategy = FieldStrategy.NEVER)
    private Roles roles;      // 角色
    @TableField(fill = FieldFill.INSERT)
    private Date createtime;  // 创建时间
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updatetime;  // 修改时间
    @Version
    private Integer version;  // 乐观锁
    @TableLogic
    private Integer deleted;  // 逻辑删除
    private Integer departid; // 员工部门编号
    @TableField(updateStrategy = FieldStrategy.NEVER)
    private Depart depart;    // 员工部门
}
// 角色实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Roles implements Serializable {
    @TableId(type = IdType.AUTO)  // id自增 数据库字段也需自增
    private Integer id;            
    private String name;          // 角色名称
    private String perms;         // 角色权限
}

dao层

// EmployeeDao
@Repository
@Mapper    // 配置扫描该包
public interface EmployeeDao extends BaseMapper<Employee>{ // 继承BaseMapper 获取基本的CRUD方法
    // 查询所有员工
    List<Employee> getEmpList();   // 扩展自己的CRUD方法
    // 根据姓名查询员工
    Employee getEmployeeByName(@Param("name") String name);
    // 根据id查询员工
    Employee getEmployeeByID(@Param("id") int id);
    // 用户名和密码进行登录
    Employee login(@Param("username") String username,@Param("password") String password);
    // 根据用户名或部门或角色查询  
    List<Employee> get(@Param("name") String name,@Param("departid") int departid,@Param("roleid") int roleid);
    // 根据姓名查询员工  之后设计员工登录的时候只显示自己的信息  
    List<Employee> getEmployee(@Param("name") String name);
    // 根据部门查询员工  之后设计各个部门经理登录会会显示各自部门的员工
    List<Employee> getEmployeeByDepartId(@Param("departid") int departid);
}

xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hua.dao.EmployeeDao">
   <resultMap id="employeedepart" type="employee">
       <result property="id" column="id"></result>
       <result property="name" column="name"></result>
       <result property="password" column="password"></result>
       <result property="age" column="age"></result>
       <result property="sex" column="sex"></result>
       <result property="phone" column="phone"></result>
       <result property="birth" column="birth"></result>
       <result property="role" column="role"></result>
       <result property="createtime" column="createtime"></result>
       <result property="updatetime" column="updatetime"></result>
       <result property="version" column="version"></result>
       <result property="deleted" column="deleted"></result>
       <result property="departid" column="departid"></result>
       <association property="roles" javaType="roles">
           <result property="id" column="rid"></result>
           <result property="name" column="rname"></result>
           <result property="perms" column="perms"></result>
       </association>
       <association property="depart" javaType="depart">
           <result property="id" column="did"></result>
           <result property="name" column="dname"></result>
           <result property="createtime" column="dcreatetime"></result>
           <result property="updatetime" column="dupdatetime"></result>
           <result property="version" column="dversion"></result>
           <result property="deleted" column="ddeleted"></result>
       </association>
   </resultMap>
    <!--代码运行时要将该文件的注释删掉-->
    <!--需要注意的是 自己写的sql语句 mybatis-plus查询的时候不会自动增加 deleted=0条件,需要自己添加-->
    <select id="getEmpList" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted,r.id as rid,r.name as rname,r.perms
        from depart d,employee e,roles r
        where d.id = e.departid and r.id = e.role and e.deleted = 0
    </select>  

    <select id="getEmployeeByName" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted,r.id as rid,r.name as rname,r.perms
        from depart d,employee e,roles r
        where d.id = e.departid and r.id = e.role and e.name = #{name} and e.deleted = 0
    </select>

    <select id="getEmployeeByID" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted,r.id as rid,r.name as rname,r.perms
        from depart d,employee e,roles r
        where d.id = e.departid and r.id = e.role and e.id = #{id} and e.deleted = 0
    </select>

    <select id="login" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted,r.id as rid,r.name as rname,r.perms
        from depart d,employee e,roles r
        where d.id = e.departid and r.id = e.role and e.name = #{username} and e.password = #{password} and e.deleted = 0
    </select>
 
    <!--该处用到了mybatis的动态sql,即查询时名字可能输入也可能不输入,部门和角色也有可能选择与不选择,都需要判断是否有值,只有在有值的时候才会加上相应的sql语句-->
    <select id="get" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted,r.id as rid,r.name as rname,r.perms
        from depart d,employee e,roles r
        <where>
            d.id = e.departid and r.id = e.role and e.deleted = 0
            <if test="name!=null">
               and e.name like "%"#{name}"%"   <!--模糊查询-->
            </if>
            <if test="departid!=0">
               and e.departid = #{departid}
            </if>
            <if test="roleid!=0">
                and e.role = #{roleid}
            </if>
        </where>
    </select>

    <select id="getEmployee" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted,r.id as rid,r.name as rname,r.perms
        from depart d,employee e,roles r
        where d.id = e.departid and r.id = e.role and e.name = #{name} and e.deleted = 0
    </select>

    <select id="getEmployeeByDepartId" resultMap="employeedepart">
        select e.*,d.id as did,d.name as dname,d.createtime as dcreatetime,d.updatetime as dupdatetime,d.version as dversion,d.deleted as ddeleted,r.id as rid,r.name as rname,r.perms
        from depart d,employee e,roles r
        where d.id = e.departid and r.id = e.role and e.deleted = 0 and e.departid = #{departid}
    </select>
</mapper>
@Repository
@Mapper
public interface RoleDao extends BaseMapper<Roles> {  // 角色相关的CRUD使用mybatis-plus自带的语句
}

service层

public interface EmployeeService {
    // 增加员工
    int add(Employee employee);
    // 查询所有员工
    List<Employee> getEmployeeList();
    // 根据id查询员工
    Employee getEmployeeByID(int id);
    // 根据姓名查询员工
    Employee getEmployeeByName(String name);
    // 根据id删除员工
    int delete(int id);
    // 根据id更新员工
    int update(Employee employee);
    // 姓名和密码进行登录
    Employee login(String username,String password);
    // 名字或部门进行查询
    List<Employee> get(String name,int departid,int roleid);
    // 根据姓名查询员工
    List<Employee> getEmployee(String name);
    // 根据部门id查询员工
    List<Employee> getEmployeeByDepart(int departid);
}

实现类

@Service
public class EmployeeServiceImpl implements EmployeeService{

    @Autowired
    EmployeeDao employeeDao; // 调用dao层

    @Override
    public int add(Employee employee) {
        return employeeDao.insert(employee);
    }

    @Override
    public List<Employee> getEmployeeList() {
        return employeeDao.getEmpList(); // 调用自己的方法
    }

    @Override
    public Employee getEmployeeByID(int id) {
        return employeeDao.getEmployeeByID(id);// 调用自己的方法
    }

    @Override
    public Employee getEmployeeByName(String name) {
        return employeeDao.getEmployeeByName(name);
    } // 调用自己的方法

    @Override
    public int delete(int id) {
        return employeeDao.deleteById(id);
    }

    @Override
    public int update(Employee employee) {
        Employee employeeByID = employeeDao.getEmployeeByID(employee.getId());
        employeeByID.setName(employee.getName());
        employeeByID.setPassword(employee.getPassword());
        employeeByID.setAge(employee.getAge());
        employeeByID.setSex(employee.getSex());
        employeeByID.setPhone(employee.getPhone());
        employeeByID.setBirth(employee.getBirth());
        employeeByID.setRole(employee.getRole());
        employeeByID.setDepartid(employee.getDepartid());
        /**
         * 注意此处的employee属性的部门对象在数据库中并没有存储,所以不需要进行更新,
         * 只更新其另加的部门id字段即可,但是mybatis-plus默认的更新策略时更新所有不为空的字段,
         * 在更新的时候sql语句中会有部门对象的字段,此时就需要修改employee实体类的该字段的
         * 更新策略,改为never,这样sql语句中就不会再出现该字段
         * */
        //
        return employeeDao.updateById(employeeByID);
    }

    @Override
    public Employee login(String username, String password) {
        return employeeDao.login(username,password);
    }

    @Override
    public List<Employee> get(String name, int departid,int roleid) {
        if (StringUtils.isEmpty(name)){ // 此处前端可能会传来null或者"",此处统一变为null,方便sql语句判断
            name=null;
        }
        return employeeDao.get(name,departid,roleid);
    }

    @Override
    public List<Employee> getEmployee(String name) {
       return employeeDao.getEmployee(name);
    }

    @Override
    public List<Employee> getEmployeeByDepart(int departid) {
       return employeeDao.getEmployeeByDepartId(departid);
    }
}

public interface RoleService {
    // 查询所有的角色
    List<Roles> getRolesList();
    // 增加角色
    int add(Roles roles);
    // 删除角色
    int delete(int id);
    // 更新角色
    int update(Roles roles);
    // 根据id查询角色
    Roles getRoleByID(int id);
    // 根据名字删除角色
    int deleteByName(String name);
    // 根据名字查询角色
    Roles getRoleByName(String name);
}

实现类

@Service
public class RoleServiceImpl implements RoleService{
    @Autowired
    RoleDao roleDao;  // 调用dao层

    @Override
    public List<Roles> getRolesList() {
        return roleDao.selectList(null);
    }

    @Override
    public int add(Roles roles) {
        return roleDao.insert(roles);
    }

    @Override
    public int delete(int id) {
        return roleDao.deleteById(id);
    }

    @Override
    public int update(Roles roles) {
        return roleDao.updateById(roles);
    }

    @Override
    public Roles getRoleByID(int id) {
        return roleDao.selectById(id);
    }

    @Override
    public int deleteByName(String name) {
        QueryWrapper<Roles> rolesQueryWrapper = new QueryWrapper<>();
        rolesQueryWrapper.eq("name",name);  // 使用条件构造器
        return roleDao.delete(rolesQueryWrapper);
    }

    @Override
    public Roles getRoleByName(String name) {
        QueryWrapper<Roles> rolesQueryWrapper = new QueryWrapper<>();
        rolesQueryWrapper.eq("name",name); // 使用条件构造器
        return roleDao.selectOne(rolesQueryWrapper);
    }
}

controller层

@Controller
public class EmployeeController {
    @Autowired
    EmployeeService employeeService;

    @Autowired
    DepartService departService;

    @Autowired
    RoleService roleService;

    @RequestMapping("/toLogin")
    public String toLogin(){
        return "index";
    }

    @RequestMapping("/login")
    public String login(String username, String password,Model model, HttpSession session){
        Subject subject = SecurityUtils.getSubject();  // 使用shiro 实现安全管理, 获取当前的对象
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            subject.login(token);  // 登录
            return "redirect:/main.html"; // 重定向到首页
        }catch (UnknownAccountException e){ 
            model.addAttribute("msg","没有该用户");
            return "index";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg","密码错误");
            return "index";
        }
    }
    @RequestMapping("/logout")
    public String logout(HttpSession session){
        Object employee = session.getAttribute("employee");
        if(employee==null){ // 未登录 直接跳转登录页
            return "index";
        }else {
            session.removeAttribute("employee");  // 已登录 清除session 跳转登录页
            return "index";
        }
    }
    @RequestMapping("/emp/list")
    public String list(Model model,HttpSession session){
        Employee employee = (Employee)session.getAttribute("employee");
        Employee employeeByID = employeeService.getEmployeeByID(employee.getId()); // 根据id重新查一遍,以防信息不准确
        String name = employeeByID.getRoles().getName();  // 得到当前角色名字
        List<Employee> employeeList = null;
        if(name.equals("管理员")){
            employeeList = employeeService.getEmployeeList(); // 当前登录的是管理员,查询全部的员工
        }else if (name.equals("普通员工")){
            employeeList = employeeService.getEmployee(employeeByID.getName()); // 当前登录的是普通员工,只能查询自己的信息
        }else{
            employeeList = employeeService.getEmployeeByDepart(employee.getDepartid()); // 当前登录的是部门经理,查询自己部门的员工
        }
        model.addAttribute("employeeList",employeeList);  // 统一将查询的员工信息返回前端
        List<Depart> departList = departService.getDepartList();
        model.addAttribute("departList",departList);  // 将所有的部门信息返回前端
        List<Roles> rolesList = roleService.getRolesList();
        model.addAttribute("rolesList",rolesList);    // 将所有的角色信息返回前端
        return "emp/list";
    }
    @RequestMapping("/emp/toAdd")
    public String toAdd(Model model){
        List<Depart> departList = departService.getDepartList();
        model.addAttribute("departList",departList); // 将所有的部门信息返回前端
        List<Roles> rolesList = roleService.getRolesList();
        model.addAttribute("rolesList",rolesList);   // 将所有的角色信息返回前端
        return "emp/add";
    }
    @RequestMapping("/emp/add")
    public String add(Employee employee){
        employeeService.add(employee); // 添加员工操作
        return "redirect:/emp/list";
    }
    @RequestMapping("/emp/toUpdate/{id}")
    public String toUpdate(@PathVariable("id") int id,Model model){
        Employee employeeByID = employeeService.getEmployeeByID(id); // 更新员工先查到该员工,将信息返回更新页面
        model.addAttribute("employee",employeeByID);
        List<Depart> departList = departService.getDepartList();
        model.addAttribute("departList",departList);
        List<Roles> rolesList = roleService.getRolesList();
        model.addAttribute("rolesList",rolesList);
        return "emp/update";
    }
    @RequestMapping("/emp/update")
    public String update(Employee employee){
        employeeService.update(employee); // 更新员工操作
        return "redirect:/emp/list";
    }
    @RequestMapping("/emp/delete/{id}")
    public String delete(@PathVariable("id") int id){
        employeeService.delete(id);      // 删除员工操作
        return "redirect:/emp/list";
    }

    @RequestMapping("/emp/get")
    public String get(String name,String departid,String roleid,Model model){
        List<Employee> employeeList = employeeService.get(name, Integer.parseInt(departid),Integer.parseInt(roleid));
        model.addAttribute("employeeList",employeeList); 
        List<Depart> departList = departService.getDepartList();
        model.addAttribute("departList",departList); // 需要注意的是   此处仍需要传部门列表和角色列表
        List<Roles> rolesList = roleService.getRolesList();
        model.addAttribute("rolesList",rolesList);
        return "emp/list";
    }
    @RequestMapping("/unauthorized")
    public String unauthorized(){
        return "unauthorized";
    }  // 此处需要设置一个未授权页面,之后当有没有权限的用户不合法访问页面时会跳转到该页面
}
@Controller
public class RoleController {
    @Autowired
    RoleService roleService;

    @RequestMapping("/role/list")
    public String list(Model model){
        List<Roles> rolesList = roleService.getRolesList();
        if(rolesList!=null){
            for (Roles roles : rolesList) {
                StringBuilder builder = new StringBuilder();
                if(!StringUtils.isEmpty(roles.getPerms())){
                    String[] split = roles.getPerms().split(",");
                    for (String s : split) {
                        if(s.equals("emp:*")){
                            builder.append("操作员工的所有权限--"); // 将数据库中的权限取出来,换成文字展示
                        }
                        if(s.equals("dep:*")){
                            builder.append("操作部门的所有权限--");
                        }
                        if(s.equals("role:*")){
                            builder.append("操作角色的所有权限--");
                        }
                        if(s.equals("emp:list")){
                            builder.append("查看员工列表--");
                        }
                        if(s.equals("emp:toAdd")){
                            builder.append("跳转增加员工--");
                        }
                        if(s.equals("emp:add")){
                            builder.append("增加员工--");
                        }
                        if(s.equals("emp:toUpdate")){
                            builder.append("跳转修改员工--");
                        }
                        if(s.equals("emp:update")){
                            builder.append("修改员工--");
                        }
                        if(s.equals("emp:delete")){
                            builder.append("删除员工--");
                        }
                        if(s.equals("emp:get")){
                            builder.append("查询员工--");
                        }

                        if(s.equals("dep:list")){
                            builder.append("查看部门列表--");
                        }
                        if(s.equals("dep:toAdd")){
                            builder.append("跳转增加部门--");
                        }
                        if(s.equals("dep:add")){
                            builder.append("增加部门--");
                        }
                        if(s.equals("dep:toUpdate")){
                            builder.append("跳转修改部门--");
                        }
                        if(s.equals("dep:update")){
                            builder.append("修改部门--");
                        }
                        if(s.equals("dep:delete")){
                            builder.append("删除部门--");
                        }


                        if(s.equals("role:list")){
                            builder.append("查看角色列表--");
                        }
                        if(s.equals("role:toAdd")){
                            builder.append("跳转增加角色--");
                        }
                        if(s.equals("role:add")){
                            builder.append("增加角色--");
                        }
                        if(s.equals("role:toUpdate")){
                            builder.append("跳转修改角色--");
                        }
                        if(s.equals("role:update")){
                            builder.append("修改角色--");
                        }
                        if(s.equals("role:delete")){
                            builder.append("删除角色--");
                        }
                        if(s.equals("无")){
                            builder.append("无权限");
                        }
                    }
                    roles.setPerms(builder.toString());
                }
            }
        }
        model.addAttribute("rolesList",rolesList);
        return "role/list";
    }
    @RequestMapping("/role/toAdd")
    public String toAdd(){
        return "role/add";
    }
    @RequestMapping("/role/add")
    public String add(Roles roles,String[] perms){
        if (roles.getName()==null || roles.getName()==""){  // 用户不输入,角色名字就是默认
            roles.setName("默认");
        }
        String perm = null;
        if(!StringUtils.isEmpty(perms)&&perms!=null){  
            List<String> list = Arrays.asList(perms); // 将用户在多选框中选择的权限组成一个list列表
            perm = String.join(",", list);  // 各个权限之间用,分割
        }else {
            perm = "无"; // 用户没有选择权限
        }
        roles.setPerms(perm);   // 设置权限
        roleService.add(roles); // 增加角色
        return "redirect:/role/list";
    }
    @RequestMapping("/role/toUpdate/{id}")
    public String toUpdate(@PathVariable("id") int id, Model model){
        Roles roleByID = roleService.getRoleByID(id);
        model.addAttribute("role",roleByID);
//        String perms = roleByID.getPerms();
//        String[] split = perms.split(",");
//        List<String> list = Arrays.asList(split);
//        System.out.println(list);
//        model.addAttribute("lists",list);
        return "role/update";
    }
    @RequestMapping("/role/update")
    public String update(Roles roles,String [] perms){
        if(roles.getName()==""||roles.getName()==null){
            roles.setName("默认");
        }
        String join = null;
        if(perms!=null&&!StringUtils.isEmpty(perms)){
            List<String> list = Arrays.asList(perms);
            join = String.join(",", list);
        }
        roles.setPerms(join);
        roleService.update(roles);
        return "redirect:/role/list";
    }
    @RequestMapping("/role/delete/{id}")
    public String delete(@PathVariable("id") int id){
        roleService.delete(id);
        return "redirect:/role/list";
    }
}

shiro安全

public class MyRealm extends AuthorizingRealm {

    @Autowired
    EmployeeService employeeService;

    @Override // 授权
    // 通过验证后,会对登录的用户进行授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Subject subject = SecurityUtils.getSubject();
        Employee employee = (Employee)subject.getPrincipal(); // 获取当前登录的用户
        String perms = employee.getRoles().getPerms();        // 将数据库中权限字段以,进行拆分
        String[] split = perms.split(",");                    // 构成权限数组
        List<String> list = Arrays.asList(split);
        info.addStringPermissions(list);                      // 授予权限
        return info;
    }
    @Override // 认证
    // 会从登录请求到此
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        String username = token1.getUsername();
        Employee employeeByName = employeeService.getEmployeeByName(username); // 拿到当前的登录的用户名
        if(employeeByName==null){ // 用户不存在,返回为空,此时登录请求会出现异常UnknownAccountException,提示前端用户名不存在
            return null;
        }
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("employee",employeeByName); // 将当前的登录用户存入session
        return new SimpleAuthenticationInfo(employeeByName,employeeByName.getPassword(),""); // shiro会自己判断密码是否正确,不正确同样会出现异常,提示前端密码不正确
    }
}

@Configuration
public class ShiroConfig {

    // 3.ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("manager") DefaultWebSecurityManager manager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        // 关联DefaultWebSecurityManager,同样需要传参引入,此处的bean使用了别名
        bean.setSecurityManager(manager);
        Map<String,String> map = new LinkedHashMap<>();
        // 员工管理 所需权限
        map.put("/emp/list","perms[emp:list]");
        map.put("/emp/toAdd","perms[emp:toAdd]");
        map.put("/emp/add","perms[emp:add]");
        map.put("/emp/toUpdate/**","perms[emp:toUpdate]");
        map.put("/emp/update","perms[emp:update]");
        map.put("/emp/delete/**","perms[emp:delete]");
        map.put("/emp/get","perms[emp:get]");
        // 部门管理 所需权限
        map.put("/dep/list","perms[dep:list]");
        map.put("/dep/toAdd","perms[dep:toAdd]");
        map.put("/dep/add","perms[dep:add]");
        map.put("/dep/toUpdate/**","perms[dep:toUpdate]");
        map.put("/dep/update","perms[dep:update]");
        map.put("/dep/delete/**","perms[dep:delete]");
        // 角色管理 所需权限
        map.put("/role/list","perms[role:list]");
        map.put("/role/toAdd","perms[role:toAdd]");
        map.put("/role/add","perms[role:add]");
        map.put("/role/toUpdate/**","perms[role:toUpdate]");
        map.put("/role/update","perms[role:update]");
        map.put("/role/delete/**","perms[role:delete]");
        bean.setFilterChainDefinitionMap(map);    // 设置访问权限
        bean.setUnauthorizedUrl("/unauthorized"); // 设置未授权跳转页面
        return bean;
    }

    //2.DefaultWebSecurityManager
    @Bean(name = "manager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("myRealm") MyRealm myRealm)	{
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        // 关联Realm 因为MyRealm已经被Spring接管,所以需要传参引入,传参的时候需要用到Qualifier指定bean的名字
        manager.setRealm(myRealm);
        return manager;
    }

    //1.创建Realm
    @Bean
    public MyRealm myRealm(){
        return new MyRealm();
    }

    // shiro整合thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
}

13.3 前端

员工展示

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

<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>员工列表</title>
    <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">

    <style>
        tr{
            /*表格内容居中显示*/
            text-align: center;
        }
    </style>
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
    <div class="row">
        <!--引入公共侧边栏-->
        <div th:insert="~{commons/commons::sidebar}"></div>
        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <h2>员工列表</h2>
            <br/>    
            <!--此处使用了shiro与thfmeleaf整合, shiro:hasPermission 登录的角色需要有指定权限,该组件才会显示-->
            <form shiro:hasPermission="'emp:get'" class="form-inline" role="form" th:action="@{/emp/get}" method="post">
                <div class="form-group col-lg-3">
                    员工姓名:<input type="text" name="name" class="form-control" placeholder="请输入员工姓名">
                </div>
                <div class="form-group col-lg-3" shiro:hasPermission="'emp:*'">
                    部门:<select name="departid">
                        <option value="0">---请选择---</option>
                        <option th:each="depart:${departList}" th:value="${depart.id}" th:text="${depart.name}"></option>
                    </select>
                </div>
                <div class="form-group col-lg-3" shiro:hasPermission="'emp:*'">
                    角色:<select name="roleid">
                    <option value="0">---请选择---</option>
                    <option th:each="roles:${rolesList}" th:value="${roles.id}" th:text="${roles.name}"></option>
                </select>
                </div>
                <div class="form-group col-lg-3" >
                    <input type="submit" value="查询">
                </div>
            </form>
            <h3><a shiro:hasPermission="'emp:toAdd'" class="btn  btn-success" style="float: right" th:href="@{/emp/toAdd}">添加员工</a></h3>
            <br/>
            <div class="table-responsive">
                <table class="table table-striped table-sm">
                    <thead>
                    <tr>
                        <th>工号</th>
                        <th>姓名</th>
                        <th>年龄</th>
                        <th>性别</th>
                        <th>联系方式</th>
                        <th>生日</th>
                        <th>角色</th>
                        <th>部门</th>
                        <th>创建日期</th>
                        <th>修改日期</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    <!--循环遍历后端传来的列表-->
                    <tr th:each="employee:${employeeList}">
                        <td th:text="${employee.id}"></td>
                        <td th:text="${employee.name}"></td>
                        <td th:text="${employee.age}"></td>
                        <td th:text="${employee.sex==0?'':''}"></td>
                        <td th:text="${employee.phone}"></td>
                        <!--格式化日期输出-->
                        <td th:text="${#dates.format(employee.birth,'yyyy-MM-dd')}"></td>
                        <td th:text="${employee.roles.name}"></td>
                        <td th:text="${employee.depart.name}"></td>
                        <td th:text="${#dates.format(employee.createtime,'yyyy-MM-dd HH:mm:ss')}"></td>
                        <td th:text="${#dates.format(employee.updatetime,'yyyy-MM-dd HH:mm:ss')}"></td>
                        <td>
                            <a shiro:hasPermission="'emp:toUpdate'" class="btn btn-sm btn-primary" th:href="@{/emp/toUpdate/}+${employee.id}">修改</a>
                            <a shiro:hasPermission="'emp:delete'" class="btn btn-sm btn-danger"  th:href="@{/emp/delete/}+${employee.id}">删除</a>
                        </td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </main>
    </div>
</div>
</body>
</html>

添加员工

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

<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>添加员工</title>
  <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
  <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
  <div class="row">
    <!--引入公共侧边栏-->
    <div th:insert="~{commons/commons::sidebar}"></div>
    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
      <form th:action="@{/emp/add}" method="post">
        <div class="form-group">
          <label>姓名</label>
          <input type="text" name="name" class="form-control" required>
        </div>
        <div class="form-group">
          <label>密码</label>
          <input type="password" name="password" class="form-control" required>
        </div>
        <div class="form-group">
          <label>年龄</label>
          <input type="text" name="age" class="form-control" required>
        </div>
        <div class="form-group">
          <label>性别</label><br/>
          <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="sex" value="1" required>
            <label class="form-check-label"></label>
          </div>
          <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="sex" value="0" required>
            <label class="form-check-label"></label>
          </div>
        </div>
        <div class="form-group">
          <label>联系方式</label>
          <input type="text" name="phone" class="form-control" required>
        </div>
        <div class="form-group">
          <label>生日</label>
          <!--注意此处的日期格式  SpringBoot默认格式为 1778/12/12 12:12:12 可以在配置文件修改-->
          <input type="text" class="form-control" placeholder="例如:1778-12-12" name="birth" required>
        </div>
        <div class="form-group">
          <label>部门</label>
          <select class="form-control" name="departid" required>
            <option th:each="department:${departList}" th:value="${department.id}">[[${department.name}]]</option>
          </select>
        </div>
        <div class="form-group">
          <label>角色</label>
          <select class="form-control" name="role" required>
            <option th:each="roles:${rolesList}" th:value="${roles.id}">[[${roles.name}]]</option>
          </select>
        </div>
        <button type="submit" class="btn btn-primary">添加</button>
      </form>
    </main>
  </div>
</div>
</body>
</html>

修改员工

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

<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>修改员工</title>
  <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
  <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
  <div class="row">
    <!--引入公共侧边栏-->
    <div th:insert="~{commons/commons::sidebar}"></div>
    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
      <form th:action="@{/emp/update}" method="post">
        <input type="hidden" name="id" th:value="${employee.id}">
        <div class="form-group">
          <label>姓名</label>
          <input type="text" name="name" th:value="${employee.name}"  class="form-control">
        </div>
        <div class="form-group">
          <label>密码</label>
          <input type="text" name="password" th:value="${employee.password}" class="form-control">
        </div>
        <div class="form-group">
          <label>年龄</label>
          <input type="text" name="age" th:value="${employee.age}" class="form-control">
        </div>
        <div class="form-group">
          <label>性别</label><br/>
          <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="sex" value="1" th:checked="${employee.sex==1}">
            <label class="form-check-label"></label>
          </div>
          <div class="form-check form-check-inline">
            <input class="form-check-input" type="radio" name="sex" value="0" th:checked="${employee.sex==0}">
            <label class="form-check-label"></label>
          </div>
        </div>
        <div class="form-group">
          <label>联系方式</label>
          <input type="text" name="phone" th:value="${employee.phone}" class="form-control">
        </div>
        <div class="form-group">
          <label>生日</label>
          <!--注意此处的日期格式  SpringBoot默认格式为 1778/12/12 12:12:12 可以在配置文件修改-->
          <input type="text" class="form-control" th:value="${employee.birth.toLocaleString()}" placeholder="例如:1778-12-12" name="birth">
        </div>
        <div class="form-group" shiro:hasPermission="'emp:*'">
          <label>部门</label>
          <select class="form-control" name="departid">
            <option th:each="department:${departList}" th:value="${department.id}" th:selected="${employee.departid==department.id}">[[${department.name}]]</option>
          </select>
        </div>
        <div class="form-group" shiro:hasPermission="'emp:*'">
          <label>角色</label>
          <select class="form-control" name="role">
            <option th:each="roles:${rolesList}" th:value="${roles.id}" th:selected="${employee.role==roles.id}">[[${roles.name}]]</option>
          </select>
        </div>
        <button type="submit" class="btn btn-primary">修改</button>
      </form>
    </main>
  </div>
</div>
</body>
</html>

角色展示

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

<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>角色列表</title>
  <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
  <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">

  <style>
    tr{
      /*表格内容居中显示*/
      text-align: center;
    }
  </style>
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
  <div class="row">
    <!--引入公共侧边栏-->
    <div th:insert="~{commons/commons::sidebar}"></div>
    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
      <h2>角色列表</h2>
      <h3><a shiro:hasPermission="'role:toAdd'" class="btn  btn-success" style="float: right" th:href="@{/role/toAdd}">添加角色</a></h3>
      <br/>
      <div class="table-responsive">
        <table class="table table-striped table-sm">
          <thead>
          <tr>
            <th>角色编号</th>
            <th>角色名称</th>
            <th>角色权限</th>
            <th>操作</th>
          </tr>
          </thead>
          <tbody>
          <!--循环遍历后端传来的列表-->
          <tr th:each="roles:${rolesList}">
            <td th:text="${roles.id}"></td>
            <td th:text="${roles.name}"></td>
            <td th:text="${roles.perms}"></td>
            <td>
              <a shiro:hasPermission="'role:toUpdate'" th:href="@{/role/toUpdate/}+${roles.id}" class="btn btn-sm btn-primary">修改</a>
              <a shiro:hasPermission="'role:delete'" th:href="@{/role/delete/}+${roles.id}" class="btn btn-sm btn-danger">删除</a>
            </td>
          </tr>
          </tbody>
        </table>
      </div>
    </main>
  </div>
</div>
</body>
</html>

角色添加

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

<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>添加角色</title>
  <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
  <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
  <div class="row">
    <!--引入公共侧边栏-->
    <div th:insert="~{commons/commons::sidebar}"></div>
    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
      <form th:action="@{/role/add}" method="post">
        <div class="form-group">
          <label>角色名称</label>
          <input type="text" name="name" class="form-control" placeholder="不填写会使用默认的...">
        </div>
        <div class="form-group">
          <label>角色权限:</label>
          <br/>
          <br/>
          <label>员工操作权限:</label>
          <input type="checkbox" name="perms" value="emp:*">操作员工的所有权限--
          <input type="checkbox" name="perms" value="emp:list">查看员工列表--
          <input type="checkbox" name="perms" value="emp:toAdd">跳转添加员工--
          <input type="checkbox" name="perms" value="emp:add">添加员工--
          <input type="checkbox" name="perms" value="emp:toUpdate">跳转修改员工--
          <input type="checkbox" name="perms" value="emp:update">修改员工--
          <input type="checkbox" name="perms" value="emp:delete">删除员工--
          <input type="checkbox" name="perms" value="emp:get">查询员工--
          <br/>
          <br/>
          <br/>
          <label>部门操作权限:</label>
          <input type="checkbox" name="perms" value="dep:*">操作部门的所有权限--
          <input type="checkbox" name="perms" value="dep:list">查看部门列表--
          <input type="checkbox" name="perms" value="dep:toAdd">跳转添加部门--
          <input type="checkbox" name="perms" value="dep:add">添加部门--
          <input type="checkbox" name="perms" value="dep:toUpdate">跳转修改部门--
          <input type="checkbox" name="perms" value="dep:update">修改部门--
          <input type="checkbox" name="perms" value="dep:delete">删除部门--
          <br/>
          <br/>
          <br/>
          <label>角色操作权限:</label>
          <input type="checkbox" name="perms" value="role:*"/>操作角色的所有权限--
          <input type="checkbox" name="perms" value="role:list"/>查看角色列表--
          <input type="checkbox" name="perms" value="role:toAdd"/>跳转添加角色--
          <input type="checkbox" name="perms" value="role:add"/>添加角色--
          <input type="checkbox" name="perms" value="role:toUpdate"/>跳转修改角色--
          <input type="checkbox" name="perms" value="role:update"/>修改角色--
          <input type="checkbox" name="perms" value="role:delete"/>删除角色--
        </div>
        <button type="submit" class="btn btn-primary">添加</button>
      </form>
    </main>
  </div>
</div>
</body>
</html>

更新角色

<!DOCTYPE html>
<html lang="en" xmlns:th="http://wwww.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

<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>修改角色</title>
    <link th:href="@{/asserts/css/bootstrap.min.css}" rel="stylesheet">
    <link th:href="@{/asserts/css/dashboard.css}" rel="stylesheet">
</head>

<body>
<!--引入公共顶部栏-->
<div th:insert="~{commons/commons::navbar}"></div>
<div class="container-fluid">
    <div class="row">
        <!--引入公共侧边栏-->
        <div th:insert="~{commons/commons::sidebar}"></div>
        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <form th:action="@{/role/update}" method="post">
                <input type="hidden" name="id" th:value="${role.id}">
                <div class="form-group">
                    <label>角色名称</label>
                    <input type="text" name="name" th:value="${role.name}"  class="form-control">
                </div>
                <div class="form-group" >
                    <label>角色权限:</label>
                    <br/>
                    <br/>
<!--此处曾想后端传来perms的列表,然后遍历, th:each="list:${lists}" th:checked="${list=='emp:*')}" 这样的话多选框会重复创建-->
                    <label>员工操作权限:</label>
                    <input type="checkbox" name="perms" value="emp:*"        th:checked="${#strings.containsIgnoreCase(role.perms,'emp:*')}">操作员工的所有权限--
                    <input type="checkbox" name="perms" value="emp:list"     th:checked="${#strings.containsIgnoreCase(role.perms,'emp:list')}">查看员工列表--
                    <input type="checkbox" name="perms" value="emp:toAdd"    th:checked="${#strings.containsIgnoreCase(role.perms,'emp:toAdd')}">跳转添加员工--
                    <input type="checkbox" name="perms" value="emp:add"      th:checked="${#strings.containsIgnoreCase(role.perms,'emp:add')}">添加员工--
                    <input type="checkbox" name="perms" value="emp:toUpdate" th:checked="${#strings.containsIgnoreCase(role.perms,'emp:toUpdate')}">跳转修改员工--
                    <input type="checkbox" name="perms" value="emp:update"   th:checked="${#strings.containsIgnoreCase(role.perms,'emp:update')}">修改员工--
                    <input type="checkbox" name="perms" value="emp:delete"   th:checked="${#strings.containsIgnoreCase(role.perms,'emp:delete')}">删除员工--
                    <input type="checkbox" name="perms" value="emp:get"      th:checked="${#strings.containsIgnoreCase(role.perms,'emp:get')}">查询员工--
                    <br/>
                    <br/>
                    <br/>
                    <label>部门操作权限:</label>
                    <input type="checkbox" name="perms" value="dep:*"        th:checked="${#strings.containsIgnoreCase(role.perms,'dep:*')}">操作部门的所有权限--
                    <input type="checkbox" name="perms" value="dep:list"     th:checked="${#strings.containsIgnoreCase(role.perms,'dep:list')}">查看部门列表--
                    <input type="checkbox" name="perms" value="dep:toAdd"    th:checked="${#strings.containsIgnoreCase(role.perms,'dep:toAdd')}">跳转添加部门--
                    <input type="checkbox" name="perms" value="dep:add"      th:checked="${#strings.containsIgnoreCase(role.perms,'dep:add')}">添加部门--
                    <input type="checkbox" name="perms" value="dep:toUpdate" th:checked="${#strings.containsIgnoreCase(role.perms,'dep:toUpdate')}">跳转修改部门--
                    <input type="checkbox" name="perms" value="dep:update"   th:checked="${#strings.containsIgnoreCase(role.perms,'dep:update')}">修改部门--
                    <input type="checkbox" name="perms" value="dep:delete"   th:checked="${#strings.containsIgnoreCase(role.perms,'dep:delete')}">删除部门--
                    <br/>
                    <br/>
                    <br/>
                    <label>角色操作权限:</label>
                    <input type="checkbox" name="perms" value="role:*"       th:checked="${#strings.containsIgnoreCase(role.perms,'role:*')}">操作角色的所有权限--
                    <input type="checkbox" name="perms" value="role:list"    th:checked="${#strings.containsIgnoreCase(role.perms,'role:list')}">查看角色列表--
                    <input type="checkbox" name="perms" value="role:toAdd"   th:checked="${#strings.containsIgnoreCase(role.perms,'role:toAdd')}">跳转添加角色--
                    <input type="checkbox" name="perms" value="role:add"     th:checked="${#strings.containsIgnoreCase(role.perms,'role:add')}">添加角色--
                    <input type="checkbox" name="perms" value="role:toUpdate"th:checked="${#strings.containsIgnoreCase(role.perms,'role:toUpdate')}">跳转修改角色--
                    <input type="checkbox" name="perms" value="role:update"  th:checked="${#strings.containsIgnoreCase(role.perms,'role:update')}">修改角色--
                    <input type="checkbox" name="perms" value="role:delete"  th:checked="${#strings.containsIgnoreCase(role.perms,'role:delete')}">删除角色--
                </div>
                <button type="submit" class="btn btn-primary">修改</button>
            </form>
        </main>
    </div>
</div>
</body>
</html>

14. 总结

至此,这个简单的员工管理系统暂时告一段落,下面总结一下系统实现的功能:

在这里插入图片描述

收获:

  1. mybatis-plus。自动填充,乐观锁(先获取该对象,再对其更新),逻辑删除,自带的CRUD语句,

    多对一 ,自己编写查询sql时需要添加逻辑删除字段,动态sql,

@TableId(type = IdType.AUTO)  // 主键自增
@TableField(fill = FieldFill.INSERT_UPDATE)       // 增加和删除操作时自动填充,需要设置填充规则 MetaObjectHandler
@TableField(updateStrategy = FieldStrategy.NEVER) // 更新规则,更新操作时不更新该字段
@Version     // 乐观锁   OptimisticLockerInterceptor
@TableLogic  // 逻辑删除 ISqlInjector
  1. shiro使用。MyRealm(继承AuthorizingRealm重写授权和认证方法)、DefaultWebSecurityManager、ShiroFilterFactoryBean(设置访问具体页面需要那些权限),shiro整合thymeleaf。
  2. 国际化实现。编写properties文件,添加配置,页面中读取,编写解析器
  3. 登录拦截器。编写拦截规则,设置拦截与不拦截的请求。
  4. list操作。将数组转为list Arrays.asList(),在列表元素中间添加逗号,String.join(“,”, list);
  5. thymeleaf。#dates.format(time,‘yyyy-MM-dd HH:mm:ss’) 或 th:value=“${time.toLocaleString()}” 日期格式转换,#strings.containsIgnoreCase(role.perms,‘emp:*’) 某字符串包含某字符串,忽略大小写
  6. thymeleaf-shiro。shiro:hasPermission=" ‘user:add’ " 拥有某权限才显示

此项目是在学习完SpringBoot、mybatis-plus之后开始构建的,由于本人没有企业级项目开发经验,此项目纯属个人练习搭建,水平有限,其中有些逻辑肯定还不是很完善,还望各位批评指教。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐