【编程不良人】快速入门SpringBoot学习笔记05---Thymeleaf使用及测试案例

1. Thymeleaf

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

Thymeleaf是一个用于web和独立环境的现代服务器端Java模板引擎。

Jsp也是Java模板引擎,Thymeleaf完全可以用来替代Jsp,在使用时Jsp和Thymeleaf不要混用

                                                                                                                --摘自官网Thymeleaf

   Thymeleaf是跟Velocity、FreeMarker类似的模板引擎,它可以完全替代JSP,相较与其他的模板引擎相比, Thymeleaf在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。注意:使用时必须要经过controller。

1.1 集成Thymeleaf模板

pom.xml引入依赖

  
  <!--引入thymeleaf依赖-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
  </dependency>

application.yml编写配置

  server:
    port: 8888
    servlet:
      context-path: /spring-boot-day7
  ​
  # 配置Thymeleaf
  spring:
    thymeleaf:
      prefix: classpath:/templates/ # 指定Thymeleaf前缀目录
      suffix: .html # 指定模板后缀是否开启Thymeleaf缓存,默认是true开启缓存
                    # 在开发过程中推荐使用false(类似jsp加载)

编写控制器测试

  package com.study.controller;
  ​
  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.RequestMapping;
  ​
  /**
   * @ClassName HelloController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/11 15:59
   * @Version 1.0
   */
  @Controller //一定要是@Controller,不能再使用@RestController注解
  @RequestMapping("hello")
  public class HelloController {
      @RequestMapping("hello")
      public String hello(){
          System.out.println("测试springboot与Thymeleaf的集成");
          return "index";// templates/index.html,最终封装成index.html进行返回
                         // 直接访问根路径(http://localhost:8888/spring-boot-day7/)加载出index.html,但无渲染效果
      }
  }

在templates目录中定义模板index.html

  <!DOCTYPE html>
  <html lang="en">
  <head>
      <meta charset="UTF-8">
      <title>测试SpringBoot与Thymeleaf的集成</title>
  </head>
  <body>
      <h1>Hello,Thymeleaf!</h1>
  </body>
  </html>

测试路径:直接访问根路径定位到templates/index.html

  http://localhost:8888/spring-boot-day7/

  http://localhost:8888/spring-boot-day7/hello/hello

1.2 模板基本语法

新建demo.html用于页面展示

使用Thymeleaf时必须在html页面中加入唯一的命名空间(namespace):Thymeleaf简写th,在xmlns:名字处写th

  <html lang="en" xmlns:th="http://www.thymeleaf.org">

注意:有的插件可以导入/提示命名空间!

初始的demo.html页面

  <!DOCTYPE html>
  <html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
      <meta charset="UTF-8">
      <title>用来测试Thymeleaf语法</title>
  </head>
  <body>
      <h1>测试Thymeleaf语法基本使用</h1>
  </body>
  </html>

新建控制器DemoController

  package com.study.controller;
  ​
  import org.springframework.stereotype.Controller;
  import org.springframework.ui.Model;
  import org.springframework.web.bind.annotation.RequestMapping;
  ​
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  ​
  /**
   * @ClassName DemoController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/13 20:36
   * @Version 1.0
   */
  @Controller
  @RequestMapping("demo")
  public class DemoController {
      @RequestMapping("demo")
      public String demo(HttpServletRequest request, Model model, HttpSession session){
          System.out.println("demo ok!");
          return "demo"; //templates/demo.html,最终封装成demo.html进行返回
      }
  }
  ​

测试路径:http://localhost:8888/spring-boot-day7/demo/demo

1.3 获取单个类型数据

DemoController

  
  package com.study.controller;
  ​
  import org.springframework.stereotype.Controller;
  import org.springframework.ui.Model;
  import org.springframework.web.bind.annotation.RequestMapping;
  ​
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  ​
  /**
   * @ClassName DemoController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/13 20:36
   * @Version 1.0
   */
  @Controller
  @RequestMapping("demo")
  public class DemoController {
      @RequestMapping("demo")
      //model底层封装的也是request作用域
      public String demo(HttpServletRequest request, Model model, HttpSession session){
          System.out.println("demo ok!");
          /**
           * 1.传递单个数据:String、Integer、解析超链接
           */
          String name = "小崔";
          request.setAttribute("name",name);
          Integer age = 27;
          model.addAttribute("age",age);
          String content = "<a href='http://www.baidu.com'>百度一下</a>";
          model.addAttribute("content",content);
          return "demo";
      }
  }

demo.html

  <h2>1.获取单个数据</h2>
  <!--
      th:text="${属性名}"获取request作用域数据:直接将获取到的数据以文本形式渲染到页面中
      th:utext="${属性名}"获取request作用域数据:先将获取到的数据解析成html标签,再以文本形式渲染到页面中
  -->
  <h3>String类型数据:<span th:text="${name}"/></h3>
  <h3>Integer类型数据:<span th:text="${age}"/></h3>
  <h3>超链接:<span th:utext="${content}"/></h3>
  <h3>输入框:</h3>
  <input type="text" name="username" th:value="${name}">
  <input type="text" name="age" th:value="${age}">

1.4 获取对象类型数据

新建对象User

  
  package com.study.entity;
  ​
  import java.util.Date;
  ​
  /**
   * @ClassName User
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/13 20:33
   * @Version 1.0
   */
  public class User {
      private Integer id;
      private String name;
      private Double salary;
      private Date birthday;
  ​
      public User() {
      }
  ​
      public User(Integer id, String name, Double salary, Date birthday) {
          this.id = id;
          this.name = name;
          this.salary = salary;
          this.birthday = birthday;
      }
  ​
      @Override
      public String toString() {
          return "User{" +
                  "id=" + id +
                  ", name='" + name + '\'' +
                  ", salary=" + salary +
                  ", birthday=" + birthday +
                  '}';
      }
  ​
      public Integer getId() {
          return id;
      }
  ​
      public void setId(Integer id) {
          this.id = id;
      }
  ​
      public String getName() {
          return name;
      }
  ​
      public void setName(String name) {
          this.name = name;
      }
  ​
      public Double getSalary() {
          return salary;
      }
  ​
      public void setSalary(Double salary) {
          this.salary = salary;
      }
  ​
      public Date getBirthday() {
          return birthday;
      }
  ​
      public void setBirthday(Date birthday) {
          this.birthday = birthday;
      }
  }

DemoController

  package com.study.controller;
  ​
  import com.study.entity.User;
  import org.springframework.stereotype.Controller;
  import org.springframework.ui.Model;
  import org.springframework.web.bind.annotation.RequestMapping;
  ​
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  import java.util.Arrays;
  import java.util.Date;
  import java.util.List;
  ​
  /**
   * @ClassName DemoController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/13 20:36
   * @Version 1.0
   */
  @Controller
  @RequestMapping("demo")
  public class DemoController {
      @RequestMapping("demo")
      //model底层封装的也是request作用域
      public String demo(HttpServletRequest request, Model model, HttpSession session){
          System.out.println("demo ok!");
          /**
           * 2.传递对象类型数据
           */
          User user = new User(1,"小崔",1234.56,new Date());
          model.addAttribute("user",user);
          return "demo";
      }
  }
  ​

demo.html

  <h2>2.获取对象类型数据</h2>
  <h3>
      user.id:<span th:text="${user.id}"/><br>
      user.name:<span th:text="${user.name}"/><br>
      user.salary:<span th:text="${user.salary}"/><br>
      <!--格式化日期:${#dates.format(格式化值,'格式化的格式')}},其中,dates.format为内置函数-->
      user.birthday:<span th:text="${#dates.format(user.birthday,'yyyy-MM-dd HH:mm:ss')}"/>
  </h3>

1.5 获取集合类型数据

DemoController

  
  package com.study.controller;
  ​
  import com.study.entity.User;
  import org.springframework.stereotype.Controller;
  import org.springframework.ui.Model;
  import org.springframework.web.bind.annotation.RequestMapping;
  ​
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  import java.util.Arrays;
  import java.util.Date;
  import java.util.List;
  ​
  /**
   * @ClassName DemoController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/13 20:36
   * @Version 1.0
   */
  @Controller
  @RequestMapping("demo")
  public class DemoController {
      @RequestMapping("demo")
      //model底层封装的也是request作用域
      public String demo(HttpServletRequest request, Model model, HttpSession session){
          System.out.println("demo ok!");
          /**
           * 3.传递集合类型数据
           */
          List<User> users = Arrays.asList(
                  new User(11,"熊大",1111.11,new Date()),
                  new User(22,"熊二",2222.22,new Date()),
                  new User(33,"光头强",3333.33,new Date())
          );
          model.addAttribute("users",users);
          return "demo";
      }
  }

demo.html

  <h2>3.获取集合类型数据</h2>
  <ul>
      <!--遍历数据:th:each="变量(current_element当前遍历元素),变量(state遍历状态对象):集合"-->
      <li th:each="user,state:${users}">
          state count: <span th:text="${state.count}"></span>
          state odd: <span th:text="${state.odd}"></span>
          state even: <span th:text="${state.even}"></span>
          state size: <span th:text="${state.size}"></span>
          id: <span th:text="${user.id}"></span>
          name: <span th:text="${user.name}"></span>
          salary: <span th:text="${user.salary}"></span>
          birthday: <span th:text="${#dates.format(user.birthday,'yyyy年MM月dd日')}"></span>
      </li>
  </ul>

补充:展示多条数据

  • 直接遍历集合

  
   <ul th:each="user:${users}">
     <li th:text="${user.id}"></li>
     <li th:text="${user.name}"></li>
     <li th:text="${user.age}"></li>
     <li th:text="${#dates.format(user.bir,'yyyy-MM-dd')}"></li>
  </ul>
  • 遍历时获取遍历状态

  
   <ul th:each="user,userStat:${users}">
     <li><span th:text="${userStat.count}"/>-<span th:text="${user.id}"/></li>   获取遍历次数  count 从1开始 index 从0开始
     <li><span th:text="${userStat.odd}"/>-<span th:text="${user.name}"/></li>   获取当前遍历是否是奇数行
     <li><span th:text="${userStat.even}"/>-<span th:text="${user.age}"/></li>   获取当前遍历是否是偶数行
     <li><span th:text="${userStat.size}"/>-<span th:text="${user.bir}"/></li>   获取当前集合的总条数
  </ul>

1.6 有条件的显示数据

demo.html

  <h2>4.有条件的展示数据</h2>
  <!-- th:if="${age>=25}" 作用:有条件的显示数据-->
  <div style="width: 100px;height: 100px;background: red" th:if="${age>25}">
      我是小红
  </div>
  <div style="width: 100px;height: 100px;background: blue" th:if="${age<=25}">
      我是小蓝
  </div>

补充运算符:

  gt:  great than(大于)      >
  ge:  great equal(大于等于)  >=
  eq:  equal(等于)           ==
  lt:  less than(小于)       <
  le:  less equal(小于等于)   <=
  ne:  not equal(不等于)     !=

1.7 传递session作用域数据

DemoControlleer

  
  package com.study.controller;
  ​
  import com.study.entity.User;
  import org.springframework.stereotype.Controller;
  import org.springframework.ui.Model;
  import org.springframework.web.bind.annotation.RequestMapping;
  ​
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  import java.util.Arrays;
  import java.util.Date;
  import java.util.List;
  ​
  /**
   * @ClassName DemoController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/13 20:36
   * @Version 1.0
   */
  @Controller
  @RequestMapping("demo")
  public class DemoController {
      @RequestMapping("demo")
      //model底层封装的也是request作用域
      public String demo(HttpServletRequest request, Model model, HttpSession session){
          System.out.println("demo ok!");
          /**
           * 5.向session作用域存储数据
           */
          session.setAttribute("username","猪猪侠");
          return "demo";
      }
  }

demo.html

  <h2>5.获取session作用域数据</h2>
  <span th:text="${session.username}"></span>

访问路径:http://localhost:8888/spring-boot-day7/demo/demo

  
  # 总结
  -  1.使用 th:text="${属性名}"  获取对应数据,获取数据时会将对应标签中数据清空,因此最好是空标签
  -  2.使用 th:utext="${属性名}" 获取对应的数据,可以将数据中html先解析在渲染到页面
  -  3.使用 th:value="${属性名}" 获取数据直接作为表单元素value属性

1.8 引入静态资源

使用thymeleaf模板时项目中的静态资源默认放在resources路径下的static目录中

demo.css

  h2{
      background: yellow;
  }

demo.js

  
  function test() {
      alert('test');
  }

demo.html

  
  <!DOCTYPE html>
  <html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
      <meta charset="UTF-8">
      <title>用来测试Thymeleaf语法</title>
  ​
      <!--th:href="@{/}",其中,@{/}用来获取应用名称-->
  ​
      <!--引入css资源-->
      <link rel="stylesheet" th:href="@{/demo.css}">
  ​
      <!--引入js资源-->
      <script th:src="@{/demo.js}"></script>
      <script>
          test();
          /**
           * 通过js代码获取应用名:
           *    通过Thymeleaf语法获取项目名,使用Thymeleaf内联表达式 [[thymeleaf]]
           */
          let contentPath = "[[@{/}]]";
          console.log("项目名",contentPath);
      </script>
  </head>
  <body>
      <h1>测试Thymeleaf语法基本使用</h1>
      <h2>1.获取单个数据</h2>
      <!--
          th:text="${属性名}"获取request作用域数据:直接将获取到的数据以文本形式渲染到页面中
          th:utext="${属性名}"获取request作用域数据:先将获取到的数据解析成html标签,再以文本形式渲染到页面中
      -->
      String类型数据:<span th:text="${name}"/><br>
      Integer类型数据:<span th:text="${age}"/><br>
      超链接:<span th:utext="${content}"/><br>
      输入框:<br>
      <input type="text" name="username" th:value="${name}"><br>
      <input type="text" name="age" th:value="${age}">
  ​
  ​
      <h2>2.获取对象类型数据</h2>
      user.id:<span th:text="${user.id}"/><br>
      user.name:<span th:text="${user.name}"/><br>
      user.salary:<span th:text="${user.salary}"/><br>
      <!--格式化日期:${#dates.format(格式化值,'格式化的格式')}},其中,dates.format为内置函数-->
      user.birthday:<span th:text="${#dates.format(user.birthday,'yyyy-MM-dd HH:mm:ss')}"/>
  ​
      <h2>3.获取集合类型数据</h2>
      <ul>
          <!--遍历数据:th:each="变量(current_element当前遍历元素),变量(state遍历状态对象):集合"-->
          <li th:each="user,state:${users}">
              state count: <span th:text="${state.count}"></span>
              state odd: <span th:text="${state.odd}"></span>
              state even: <span th:text="${state.even}"></span>
              state size: <span th:text="${state.size}"></span>
              id: <span th:text="${user.id}"></span>
              name: <span th:text="${user.name}"></span>
              salary: <span th:text="${user.salary}"></span>
              birthday: <span th:text="${#dates.format(user.birthday,'yyyy年MM月dd日')}"></span>
          </li>
      </ul>
  ​
      <h2>4.有条件的展示数据</h2>
      <!-- th:if="${age>=25}" 作用:有条件的显示数据-->
      <div style="width: 100px;height: 100px;background: red" th:if="${age>25}">
          我是小红
      </div>
      <div style="width: 100px;height: 100px;background: blue" th:if="${age<=25}">
          我是小蓝
      </div>
  ​
      <h2>5.获取session作用域数据</h2>
      <span th:text="${session.username}"></span>
  </body>
  </html>

或者

  
   <link rel="stylesheet" th:href="@{/css/index.css}">
   <script th:src="@{/js/jquery-min.js}"></script>

注意: @{/}代表通过thymeleaf语法动态获取应用名

在js代码中获取项目名:

  <script>
    const ctx = '[[@{/}]]';
  </script>

注意:[[书写thymeleaf语法]],这里[[ ]]是thymeleaf内嵌表达式。

最终效果:

1.9 最终项目结构

2. Thymeleaf测试案例

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

2.1 开发流程

  需求分析: 分析这个项目含有哪些功能模块
      用户模块:
          注册
          登录
          验证码
          安全退出
          真实用户
      员工模块:
          添加员工+上传头像
          展示员工列表+展示员工头像
          删除员工信息+删除员工头像
          更新员工信息+更新员工头像
  ​
  库表设计(概要设计): 1.分析系统有哪些表  2.分析表与表关系  3.确定表中字段(显性字段 隐性字段(业务字段))
      2张表 
          1.用户表 user
              id username realname password gender
          2.员工表 employee
              id name salary birthday  photo
      创建一个库: ems-thymeleaf
  ​
  详细设计:
      省略
  ​
  编码(环境搭建+业务代码开发)
      1.创建一个springboot项目 项目名字: ems-thymeleaf
      2.修改配置文件为 application.yml  pom.xml  2.5.0
      3.修改端口 8888  项目名: ems-thymeleaf
      4.springboot整合thymeleaf使用
          a.引入依赖:thymeleaf
          b.配置文件中指定thymeleaf相关配置
          c.编写控制器测试
      5.springboot整合mybatis
          a.引入依赖:mysql、druid、mybatis-springboot-stater
          b.配置文件中 
      6.导入项目页面
          static  存放静态资源
          templates 目录 存放模板文件
  ​
  测试
  上线部署
  维护
  发版
  ======================================================================
  ​
  用户相关:
  1.登录
  2.注册
  3.验证码
      1.验证码工具类

2.2 springboot整合thymeleaf

新建spring Initializr项目,引入Spring Web,项目命名为ems-thymeleaf

pom.xml引入thymeleaf依赖

  <!--引入Thymeleaf依赖-->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
      <version>2.7.0</version>
  </dependency>

修改application.properties为application.yml,添加如下配置:

  
  # 公共配置
  server:
    port: 8888
    servlet:
      context-path: /ems-thymeleaf
  ​
  # Thymeleaf配置
  spring:
    thymeleaf:
      cache: false
      prefix: classpath:/templates/
      suffix: .html

新建demo.html

  
  <!DOCTYPE html>
  <html lang="en" xmlns="http://www.thymeleaf.org">
  <head>
      <meta charset="UTF-8">
      <title>测试Thymeleaf</title>
  </head>
  <body>
      <h1>测试Thymeleaf</h1>
      <h4>获取数据:<span th:text="${msg}"></span></h4>
  </body>
  </html>

DemoController

  
  package com.study.controller;
  ​
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.stereotype.Controller;
  import org.springframework.ui.Model;
  import org.springframework.web.bind.annotation.RequestMapping;
  ​
  /**
   * @ClassName DemoController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 9:45
   * @Version 1.0
   */
  @Controller
  @RequestMapping("demo")
  public class DemoController {
      private static final Logger log = LoggerFactory.getLogger(DemoController.class);
      
      @RequestMapping("demo")
      public String demo(Model model){
          log.debug("demo ok");
          model.addAttribute("msg","hello,Thymeleaf!");
          return "demo";
      }
  }

启动项目,访问路径:http://localhost:8888/ems-thymeleaf/demo/demo

2.3 springboot整合mybatis

pom.xml引入依赖:mysql、druid、mybatis-spring-boot-starter

  <!--mysql-->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.38</version>
  </dependency>
  ​
  <!--druid-->
  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.4</version>
  </dependency>
  ​
  <!--mybatis-spring-boot-starter-->
  <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.2.0</version>
  </dependency>

application.yml引入配置

  # 公共配置
  server:
    port: 8888
    servlet:
      context-path: /ems-thymeleaf
  ​
  # Thymeleaf配置
  spring:
    thymeleaf:
      cache: false
      prefix: classpath:/templates/
      suffix: .html
  ​
  # 配置数据源
    datasource:
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/ems-thymeleaf?characterEncoding=UTF-8
      username: root
      password: 123456
  ​
  # 配置mybatis
  mybatis:
    mapper-locations: classpath:com/study/mapper/*.xml
    type-aliases-package: com.study.entity
  ​
  # 配置日志
  logging:
    level:
      root: info
      com.study: debug

启动类添加注解扫描

  
  package com.study;
  ​
  import org.mybatis.spring.annotation.MapperScan;
  import org.springframework.boot.SpringApplication;
  import org.springframework.boot.autoconfigure.SpringBootApplication;
  ​
  @SpringBootApplication
  @MapperScan("com.study.dao")
  public class EmsThymeleafApplication {
  ​
      public static void main(String[] args) {
          SpringApplication.run(EmsThymeleafApplication.class, args);
      }
  }

重新启动一下项目,运行不报错即可。

2.4 导入项目页面(静态资源)

在static目录下导入css、img、js等静态资源,导入之后Rebuild一下项目

新建MVC配置类:不用单独开发controller来访问html页面

  
  package com.study.config;
  ​
  import org.springframework.context.annotation.Configuration;
  import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
  import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  ​
  /**
   * @ClassName MvcConfig
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 10:35
   * @Version 1.0
   */
  @Configuration
  public class MvcConfig implements WebMvcConfigurer {
      @Override
      //通过在这里面配置,不需要再为每一个访问thymeleaf模板页面单独开发一个controller请求了
      public void addViewControllers(ViewControllerRegistry registry) {
          //ViewController: 请求路径,ViewName: 跳转视图
          registry.addViewController("login").setViewName("login");
          registry.addViewController("register").setViewName("regist");//注意与HTML页面对应
      }
  }

启动项目,访问页面:

(1)注册页面:http://localhost:8888/ems-thymeleaf/register

 (2)登录页面:http://localhost:8888/ems-thymeleaf/login

2.5 验证码

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

验证码工具类

  
  package com.study.utils;
  ​
  import javax.imageio.ImageIO;
  import java.awt.*;
  import java.awt.geom.AffineTransform;
  import java.awt.image.BufferedImage;
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.util.Arrays;
  import java.util.Random;
  ​
  /**
   *@创建人  cx
   *@创建时间  2018/11/27 17:36
   *@描述   验证码生成
   */
  public class VerifyCodeUtils{
      //使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
      public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
      private static Random random = new Random();
  ​
      /**
       * 使用系统默认字符源生成验证码
       * @param verifySize    验证码长度
       * @return
       */
      public static String generateVerifyCode(int verifySize){
          return generateVerifyCode(verifySize, VERIFY_CODES);
      }
      /**
       * 使用指定源生成验证码
       * @param verifySize    验证码长度
       * @param sources   验证码字符源
       * @return
       */
      public static String generateVerifyCode(int verifySize, String sources){
          if(sources == null || sources.length() == 0){
              sources = VERIFY_CODES;
          }
          int codesLen = sources.length();
          Random rand = new Random(System.currentTimeMillis());
          StringBuilder verifyCode = new StringBuilder(verifySize);
          for(int i = 0; i < verifySize; i++){
              verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));
          }
          return verifyCode.toString();
      }
  ​
      /**
       * 生成随机验证码文件,并返回验证码值
       * @param w
       * @param h
       * @param outputFile
       * @param verifySize
       * @return
       * @throws IOException
       */
      public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{
          String verifyCode = generateVerifyCode(verifySize);
          outputImage(w, h, outputFile, verifyCode);
          return verifyCode;
      }
  ​
      /**
       * 输出随机验证码图片流,并返回验证码值
       * @param w
       * @param h
       * @param os
       * @param verifySize
       * @return
       * @throws IOException
       */
      public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{
          String verifyCode = generateVerifyCode(verifySize);
          outputImage(w, h, os, verifyCode);
          return verifyCode;
      }
  ​
      /**
       * 生成指定验证码图像文件
       * @param w
       * @param h
       * @param outputFile
       * @param code
       * @throws IOException
       */
      public static void outputImage(int w, int h, File outputFile, String code) throws IOException{
          if(outputFile == null){
              return;
          }
          File dir = outputFile.getParentFile();
          if(!dir.exists()){
              dir.mkdirs();
          }
          try{
              outputFile.createNewFile();
              FileOutputStream fos = new FileOutputStream(outputFile);
              outputImage(w, h, fos, code);
              fos.close();
          } catch(IOException e){
              throw e;
          }
      }
  ​
      /**
       * 输出指定验证码图片流
       * @param w
       * @param h
       * @param os
       * @param code
       * @throws IOException
       */
      public static void outputImage(int w, int h, OutputStream os, String code) throws IOException{
          int verifySize = code.length();
          BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
          Random rand = new Random();
          Graphics2D g2 = image.createGraphics();
          g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
          Color[] colors = new Color[5];
          Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN,
                  Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
                  Color.PINK, Color.YELLOW };
          float[] fractions = new float[colors.length];
          for(int i = 0; i < colors.length; i++){
              colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
              fractions[i] = rand.nextFloat();
          }
          Arrays.sort(fractions);
          g2.setColor(Color.GRAY);// 设置边框色
          g2.fillRect(0, 0, w, h);
          Color c = getRandColor(200, 250);
          g2.setColor(c);// 设置背景色
          g2.fillRect(0, 2, w, h-4);
          //绘制干扰线
          Random random = new Random();
          g2.setColor(getRandColor(160, 200));// 设置线条的颜色
          for (int i = 0; i < 20; i++) {
              int x = random.nextInt(w - 1);
              int y = random.nextInt(h - 1);
              int xl = random.nextInt(6) + 1;
              int yl = random.nextInt(12) + 1;
              g2.drawLine(x, y, x + xl + 40, y + yl + 20);
          }
  ​
          // 添加噪点
          float yawpRate = 0.05f;// 噪声率
          int area = (int) (yawpRate * w * h);
          for (int i = 0; i < area; i++) {
              int x = random.nextInt(w);
              int y = random.nextInt(h);
              int rgb = getRandomIntColor();
              image.setRGB(x, y, rgb);
          }
          shear(g2, w, h, c);// 使图片扭曲
          g2.setColor(getRandColor(100, 160));
          int fontSize = h-4;
          Font font = new Font("Algerian", Font.ITALIC, fontSize);
          g2.setFont(font);
          char[] chars = code.toCharArray();
          for(int i = 0; i < verifySize; i++){
              AffineTransform affine = new AffineTransform();
              affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2);
              g2.setTransform(affine);
              g2.drawChars(chars, i, 1, ((w-10) / verifySize) * i + 5, h/2 + fontSize/2 - 10);
          }
          g2.dispose();
          ImageIO.write(image, "jpg", os);
      }
  ​
      private static Color getRandColor(int fc, int bc) {
          if (fc > 255)
              fc = 255;
          if (bc > 255)
              bc = 255;
          int r = fc + random.nextInt(bc - fc);
          int g = fc + random.nextInt(bc - fc);
          int b = fc + random.nextInt(bc - fc);
          return new Color(r, g, b);
      }
  ​
      private static int getRandomIntColor() {
          int[] rgb = getRandomRgb();
          int color = 0;
          for (int c : rgb) {
              color = color << 8;
              color = color | c;
          }
          return color;
      }
  ​
      private static int[] getRandomRgb() {
          int[] rgb = new int[3];
          for (int i = 0; i < 3; i++) {
              rgb[i] = random.nextInt(255);
          }
          return rgb;
      }
  ​
      private static void shear(Graphics g, int w1, int h1, Color color) {
          shearX(g, w1, h1, color);
          shearY(g, w1, h1, color);
      }
  ​
      private static void shearX(Graphics g, int w1, int h1, Color color) {
          int period = random.nextInt(2);
          boolean borderGap = true;
          int frames = 1;
          int phase = random.nextInt(2);
          for (int i = 0; i < h1; i++) {
              double d = (double) (period >> 1)
                      * Math.sin((double) i / (double) period
                      + (6.2831853071795862D * (double) phase)
                      / (double) frames);
              g.copyArea(0, i, w1, 1, (int) d, 0);
              if (borderGap) {
                  g.setColor(color);
                  g.drawLine((int) d, i, 0, i);
                  g.drawLine((int) d + w1, i, w1, i);
              }
          }
  ​
      }
  ​
      private static void shearY(Graphics g, int w1, int h1, Color color) {
          int period = random.nextInt(40) + 10; // 50;
          boolean borderGap = true;
          int frames = 20;
          int phase = 7;
          for (int i = 0; i < w1; i++) {
              double d = (double) (period >> 1)
                      * Math.sin((double) i / (double) period
                      + (6.2831853071795862D * (double) phase)
                      / (double) frames);
              g.copyArea(i, 0, 1, h1, 0, (int) d);
              if (borderGap) {
                  g.setColor(color);
                  g.drawLine(i, (int) d, i, 0);
                  g.drawLine(i, (int) d + h1, i, h1);
              }
          }
      }
  }

添加控制器UserController

  
  package com.study.controller;
  ​
  import com.study.utils.VerifyCodeUtils;
  import com.sun.deploy.net.HttpResponse;
  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.RequestMapping;
  ​
  import javax.servlet.ServletOutputStream;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  import java.io.IOException;
  ​
  /**
   * @ClassName UserController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 11:53
   * @Version 1.0
   */
  @Controller
  @RequestMapping("user")
  public class UserController {
      /**
       * @MethodName generateImageCode
       * @Description 生成图片验证码 
       * @param: session
       * @param: response  
       * @Author Jiangnan Cui
       * @Date 2022/6/27 12:08
       */
      @RequestMapping("generateImageCode")
      public void generateImageCode(HttpSession session, HttpServletResponse response) throws IOException {
          //1.生成4位随机数
          String code = VerifyCodeUtils.generateVerifyCode(4);
          //2.保存到session作用域
          session.setAttribute("code",code);
          //3.设置响应类型
          response.setContentType("image/png");
          //4.获得输出流
          ServletOutputStream sos = response.getOutputStream();
          //5.根据随机数生成图片
          VerifyCodeUtils.outputImage(220,60,sos,code);
      }
  }
  ​

register.html

  
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html xmlns:th="http://www.thymeleaf.org">
      <head>
          <title>regist</title>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />
      </head>
      <body>
          <div id="wrap">
              <div id="top_content">
                      <div id="header">
                          <div id="rightheader">
                              <p>
                                  2009/11/20
                                  <br />
                              </p>
                          </div>
                          <div id="topheader">
                              <h1 id="title">
                                  <a href="#">main</a>
                              </h1>
                          </div>
                          <div id="navigation">
                          </div>
                      </div>
                  <div id="content">
                      <p id="whereami">
                      </p>
                      <h1>
                          注册
                      </h1>
                      <form th:action="@{/user/register}" method="post">
                          <table cellpadding="0" cellspacing="0" border="0"
                              class="form_table">
                              <tr>
                                  <td valign="middle" align="right">
                                      用户名:
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="text" class="inputgri" name="username" />
                                  </td>
                              </tr>
                              <tr>
                                  <td valign="middle" align="right">
                                      真实姓名:
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="text" class="inputgri" name="realname" />
                                  </td>
                              </tr>
                              <tr>
                                  <td valign="middle" align="right">
                                      密码:
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="password" class="inputgri" name="password" />
                                  </td>
                              </tr>
                              <tr>
                                  <td valign="middle" align="right">
                                      性别:
                                  </td>
                                  <td valign="middle" align="left">
                                      男
                                      <input type="radio" class="inputgri" name="gender" value="1" checked="checked"/>
                                      女
                                      <input type="radio" class="inputgri" name="gender" value="0"/>
                                  </td>
                              </tr>
                              
                              <tr>
                                  <td valign="middle" align="right">
                                      验证码:
                                      <img id="num" th:src="@{/user/generateImageCode}" />
                                      <a href="javascript:;" οnclick="changeImageCode()">换一张</a>
                                      <script>
                                          function changeImageCode(){
                                              document.getElementById('num').src = '[[@{/user/generateImageCode}]]?'+(new Date()).getTime()
                                          }
                                      </script>
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="text" class="inputgri" name="code" />
                                  </td>
                              </tr>
                          </table>
                          <p>
                              <input type="submit" class="button" value="立即注册 &raquo;" />
                              <a href="login.html">已有账号,返回登录</a>
                          </p>
                      </form>
                  </div>
              </div>
              <div id="footer">
                  <div id="footer_bg">
                  ABC@126.com
                  </div>
              </div>
          </div>
      </body>
  </html>
  ​

测试路径

(1)http://localhost:8888/ems-thymeleaf/user/generateImageCode

(2)http://localhost:8888/ems-thymeleaf/register

2.6 用户注册

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

创建数据库ems-thymeleaf、表user

create database if not exists `ems-thymeleaf`;
use `ems-thymeleaf`;
create table if not exists `user`(
    id int(20) not null auto_increment comment '用户ID',
    username varchar(100) not null comment '用户名',
    realname varchar(100) comment '真实姓名',
    password varchar(100) comment '密码',
    gender boolean comment '性别',
    primary key(id)
)engine=innodb charset=utf8;

新建实体类User

  
  package com.study.entity;
  ​
  /**
   * @ClassName User
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 15:49
   * @Version 1.0
   */
  public class User {
      private Integer id;
      private String username;
      private String realname;
      private String password;
      private Boolean gender;
  ​
      public User() {
      }
  ​
      public User(Integer id, String username, String realname, String password, Boolean gender) {
          this.id = id;
          this.username = username;
          this.realname = realname;
          this.password = password;
          this.gender = gender;
      }
  ​
      @Override
      public String toString() {
          return "User{" +
                  "id=" + id +
                  ", username='" + username + '\'' +
                  ", realname='" + realname + '\'' +
                  ", password='" + password + '\'' +
                  ", gender=" + gender +
                  '}';
      }
  ​
      public Integer getId() {
          return id;
      }
  ​
      public void setId(Integer id) {
          this.id = id;
      }
  ​
      public String getUsername() {
          return username;
      }
  ​
      public void setUsername(String username) {
          this.username = username;
      }
  ​
      public String getRealname() {
          return realname;
      }
  ​
      public void setRealname(String realname) {
          this.realname = realname;
      }
  ​
      public String getPassword() {
          return password;
      }
  ​
      public void setPassword(String password) {
          this.password = password;
      }
  ​
      public Boolean getGender() {
          return gender;
      }
  ​
      public void setGender(Boolean gender) {
          this.gender = gender;
      }
  }
  ​

创建UserDAO

  
  package com.study.dao;
  ​
  import com.study.entity.User;
  ​
  /**
   * @ClassName UserDAO
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 16:02
   * @Version 1.0
   */
  public interface UserDAO {
      /**
       * @MethodName findByUserName
       * @Description 根据用户名查找用户
       * @param: username
       * @return: com.study.entity.User
       * @Author Jiangnan Cui
       * @Date 2022/6/27 16:03
       */
      User findByUserName(String username);
  ​
      /**
       * @MethodName register
       * @Description 用户注册
       * @param: user
       * @Author Jiangnan Cui
       * @Date 2022/6/27 16:03
       */
      void register(User user);
  }
  ​

创建UserDAOMapper

  
  <?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.study.dao.UserDAO">
      <!--findByUserName-->
      <select id="findByUserName" parameterType="String" resultType="User">
          select
              id,username,realname,password,gender
          from `user`
          where username=#{username}
      </select>
  ​
      <!--register-->
      <insert id="register" parameterType="User" useGeneratedKeys="true" keyProperty="id">
          insert into `user` values(#{id},#{username},#{realname},#{password},#{gender})
      </insert>
  ​
  </mapper>

创建UserService

  package com.study.service;
  ​
  import com.study.entity.User;
  ​
  /**
   * @ClassName UserService
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 15:48
   * @Version 1.0
   */
  public interface UserService {
      /**
       * @MethodName register
       * @Description 用户注册
       * @param: user
       * @Author Jiangnan Cui
       * @Date 2022/6/27 15:50
       */
      void register(User user);
  }

创建UserServiceImpl

  
  package com.study.service;
  ​
  import com.study.dao.UserDAO;
  import com.study.entity.User;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  import org.springframework.util.DigestUtils;
  import org.springframework.util.ObjectUtils;
  import java.nio.charset.StandardCharsets;
  ​
  /**
   * @ClassName UserServiceImpl
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 16:14
   * @Version 1.0
   */
  @Service
  @Transactional
  public class UserServiceImpl implements UserService{
      //业务逻辑层调用数据访问层
      private UserDAO userDAO;
      @Autowired
      public UserServiceImpl(UserDAO userDAO) {
          this.userDAO = userDAO;
      }
  ​
      /**
       * @MethodName register
       * @Description
       * @param: user
       * @Author Jiangnan Cui
       * @Date 2022/6/27 16:22
       */
      @Override
      public void register(User user) {
          //1.根据用户名从数据库中查询是否存在已经注册的用户
          User userDB = userDAO.findByUserName(user.getUsername());
          //2.判断该用户是否存在
          if(!ObjectUtils.isEmpty(userDB))
              throw new RuntimeException("当前用户已被注册!");//不为空时抛出异常
          //3.为空时表明用户不存在,继续注册用户
          //对明文密码进行加密:相同字符串多次使用md5加密后结果一致
          String newPassword = DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8));
          user.setPassword(newPassword);
          userDAO.register(user);
      }
  }
  ​

新建UserController

  
  package com.study.controller;
  ​
  import com.study.entity.User;
  import com.study.service.UserService;
  import com.study.utils.VerifyCodeUtils;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.RequestMapping;
  import javax.servlet.ServletOutputStream;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  import java.io.IOException;
  ​
  /**
   * @ClassName UserController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 11:53
   * @Version 1.0
   */
  @Controller
  @RequestMapping("user")
  public class UserController {
      //新建日志对象
      private static final Logger log = LoggerFactory.getLogger(UserController.class);
  ​
      /**
       * @MethodName generateImageCode
       * @Description 生成图片验证码
       * @param: session
       * @param: response
       * @Author Jiangnan Cui
       * @Date 2022/6/27 12:08
       */
      @RequestMapping("generateImageCode")
      public void generateImageCode(HttpSession session, HttpServletResponse response) throws IOException {
          //1.生成4位随机数
          String code = VerifyCodeUtils.generateVerifyCode(4);
          //2.保存到session作用域
          session.setAttribute("code",code);
          //3.设置响应类型
          response.setContentType("image/png");
          //4.获得输出流
          ServletOutputStream sos = response.getOutputStream();
          //5.根据随机数生成图片
          VerifyCodeUtils.outputImage(220,60,sos,code);
      }
  ​
      private UserService userService;
      @Autowired
      public UserController(UserService userService) {
          this.userService = userService;
      }
  ​
      /**
       * @MethodName register
       * @Description 用户注册
       * @param: user
       * @param: code
       * @param: session
       * @return: java.lang.String
       * @Author Jiangnan Cui
       * @Date 2022/6/27 15:57
       */
      @RequestMapping("register")
      public String register(User user,String code,HttpSession session){
          log.debug("用户名:{},真实姓名:{},密码:{},性别:{}",
                  user.getUsername(),user.getRealname(),user.getPassword(),user.getGender());
          log.debug("用户输入的验证码: {}",code);
  ​
          try {
              //1.判断用户输入验证码和session中的验证码是否一致
              String sessionCode = session.getAttribute("code").toString();
              if(!sessionCode.equalsIgnoreCase(code))
                  throw new RuntimeException("验证码输入错误!");
              //2.注册用户
              userService.register(user);
          } catch (RuntimeException e) {
              e.printStackTrace();
              return "redirect:/register";//注册失败回到注册
          }
          return "redirect:/login";//注册成功转到登录
      }
  }
  ​

访问路径:http://localhost:8888/ems-thymeleaf/register,进行注册,成功跳转到登录页面,失败回到注册页面!

2.7 用户登录

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

在UserService添加登录方法

  /**
   * @MethodName login
   * @Description 用户登录
   * @param: username
   * @param: password
   * @return: com.study.entity.User
   * @Author Jiangnan Cui
   * @Date 2022/6/27 17:02
   */
  User login(String username,String password);

在UserServiceImpl实现登录方法

  /**
   * @MethodName login
   * @Description 用户登录
   * @param: username
   * @param: password
   * @return: com.study.entity.User
   * @Author Jiangnan Cui
   * @Date 2022/6/27 17:03
   */
  @Override
  public User login(String username, String password) {
      //1.根据用户名查询用户
      User user = userDAO.findByUserName(username);
      //2.判断用户是否存在,存在执行登录;不存在,抛出异常
      if(ObjectUtils.isEmpty(user))
          throw new RuntimeException("用户名不存在!");
      //3.在用户存在的前提下,比较密码是否正确,正确执行登录;不正确,抛出异常
      //密码加密
      String passwordSecret = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));
      if(!user.getPassword().equals(passwordSecret))
          throw new RuntimeException("密码错误!");
      return user;
  }

UserController添加登录方法

  /**
   * @MethodName login
   * @Description 用户登录
   * @param: username
   * @param: password
   * @param: session
   * @return: java.lang.String
   * @Author Jiangnan Cui
   * @Date 2022/6/27 17:11
   */
  @RequestMapping("login")
  public String login(String username,String password,HttpSession session){
      log.debug("本次登录的用户名为:{}",username);
      log.debug("本次登录的密码为:{}",password);
      try {
          //1.调用业务逻辑层进行登录
          User user = userService.login(username, password);
          //2.保存用户信息供页面调用
          session.setAttribute("user",user);
      } catch (Exception e) {
          e.printStackTrace();
          return "redirect:/login";//登录失败回到登录页面
      }
      return "redirect:/employee/lists";//登录成功,跳转到查询所有员工信息控制器路径
  }

添加EmpployeeController

  
  package com.study.controller;
  ​
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.springframework.stereotype.Controller;
  import org.springframework.ui.Model;
  import org.springframework.web.bind.annotation.RequestMapping;
  ​
  /**
   * @ClassName EmployeeController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 17:15
   * @Version 1.0
   */
  @Controller
  @RequestMapping("employee")
  public class EmployeeController {
      private static final Logger log = LoggerFactory.getLogger(EmployeeController.class);
  ​
      @RequestMapping("lists")
      public String list(Model model){
          log.debug("查询所有员工信息");
          return "emplist";
      }
  ​
  }
  ​

login.html

  
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html xmlns:th="http://www.thymeleaf.org">
      <head>
          <title>login</title>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <link rel="stylesheet" type="text/css"
              href="css/style.css" />
      </head>
  ​
      <body>
          <div id="wrap">
              <div id="top_content">
                      <div id="header">
                          <div id="rightheader">
                              <p>
                                  2009/11/20
                                  <br />
                              </p>
                          </div>
                          <div id="topheader">
                              <h1 id="title">
                                  <a href="#">main</a>
                              </h1>
                          </div>
                          <div id="navigation">
                          </div>
                      </div>
                  <div id="content">
                      <p id="whereami">
                      </p>
                      <h1>
                          欢迎进入,请登录!
                      </h1>
                      <form th:action="@{/user/login}" method="post">
                          <table cellpadding="0" cellspacing="0" border="0"
                              class="form_table">
                              <tr>
                                  <td valign="middle" align="right">
                                      用户名:
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="text" class="inputgri" name="username" />
                                  </td>
                              </tr>
                              <tr>
                                  <td valign="middle" align="right">
                                      密码:
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="password" class="inputgri" name="password" />
                                  </td>
                              </tr>
                          </table>
                          <p>
                              <input type="submit" class="button" value="点我登录 &raquo;" />
                              &nbsp;&nbsp;
                              <a href="regist.html">还没有账号,立即注册</a>
                          </p>
                      </form>
                  </div>
              </div>
              <div id="footer">
                  <div id="footer_bg">
                      ABC@126.com
                  </div>
              </div>
          </div>
      </body>
  </html>
  ​

emplists.html

  
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html xmlns:th="http://www.thymeleaf.org">
      <head>
          <title>emplist</title>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />
      </head>
      <body>
          <div id="wrap">
              <div id="top_content"> 
                  <div id="header">
                      <div id="rightheader">
                          <p>
                              2009/11/20 
                              <br />
                              <a th:if="${session.user!=null}" th:href="@{/user/logout}">安全退出</a>
                              <a th:if="${session.user==null}" th:href="@{/login}">点我登录</a>
                          </p>
                      </div>
                      <div id="topheader">
                          <h1 id="title">
                              <a href="#">main</a>
                          </h1>
                      </div>
                      <div id="navigation">
                      </div>
                  </div>
                  <div id="content">
                      <p id="whereami">
                      </p>
                      <h1>
                          欢迎 <span th:if="${session.user!=null}" th:text="${session.user.username}"></span>
                              <span th:if="${session.user==null}" >游客</span>!
                      </h1>
                      <table class="table">
                          <tr class="table_header">
                              <td>
                                  编号
                              </td>
                              <td>
                                  姓名
                              </td>
                              <td>
                                  头像
                              </td>
                              <td>
                                  工资
                              </td>
                              <td>
                                  生日
                              </td>
                              <td>
                                  操作
                              </td>
                          </tr>
                          <tr th:each="employee,state:${employeeList}"  th:class="${state.odd?'row1':'row2'}">
                              <td>
                                  <span th:text="${employee.id}"></span>
                              </td>
                              <td>
                                  <span th:text="${employee.name}"></span>
                              </td>
                              <td>
                                  <img th:src="@{/}+${employee.photo}" width="60">
                              </td>
                              <td>
                                  <span th:text="${employee.salary}"></span>
                              </td>
                              <td>
                                  <span th:text="${#dates.format(employee.birthday,'yyyy/MM/dd')}"></span>
                              </td>
                              <td>
                                  <a href="javascript:;" th:οnclick="'deleteEmployee('+${employee.id}+')'">删除</a>
  <!--                                <a th:href="@{/employee/detail?id=}+${employee.id}+'&name='+${employee.name}">更新</a>-->
  <!--                                <a th:href="@{/employee/detail(id=${employee.id},name=${employee.name})}">更新</a>-->
                                  <a th:href="@{/employee/detail(id=${employee.id})}">更新</a>
  ​
                              </td>
                          </tr>
                          <script>
                              function deleteEmployee(id){
                                  console.log(id);
                                  if(window.confirm('确定要删除这条记录吗?')){
                                      location.href='[[@{/employee/delete?id=}]]'+id;
                                  }
                              }
                          </script>
                      </table>
                      <p>
                          <input type="button" class="button" value="添加" οnclick="addEmp()"/>
                          <script>
                              function addEmp(){
                                  location.href = '[[@{/addEmp}]]';
                              }
                          </script>
                      </p>
                  </div>
              </div>
              <div id="footer">
                  <div id="footer_bg">
                  ABC@126.com
                  </div>
              </div>
          </div>
      </body>
  </html>
  ​

测试路径:http://localhost:8888/ems-thymeleaf/login,登录成功跳转到员工列表页面,登录失败回到登录页面。

2.8 员工列表

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

创建employee表

create table if not exists `employee`(
    id int(20) not null auto_increment comment '员工ID',
    name varchar(100) not null comment '姓名',
    salary double not null comment '工资',
    birthday datetime not null comment '生日',
    photo varchar(100) not null comment '头像',
    primary key(id)
)engine=innodb charset=utf8;

新建实体类Employee

  
  package com.study.entity;
  ​
  import java.util.Date;
  ​
  /**
   * @ClassName Employee
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 18:11
   * @Version 1.0
   */
  public class Employee {
      private Integer id;
      private String name;
      private Double salary;
      private Date birthday;
      private String photo;
  ​
      public Employee() {
      }
  ​
      public Employee(Integer id, String name, Double salary, Date birthday, String photo) {
          this.id = id;
          this.name = name;
          this.salary = salary;
          this.birthday = birthday;
          this.photo = photo;
      }
  ​
      public Integer getId() {
          return id;
      }
  ​
      public void setId(Integer id) {
          this.id = id;
      }
  ​
      public String getName() {
          return name;
      }
  ​
      public void setName(String name) {
          this.name = name;
      }
  ​
      public Double getSalary() {
          return salary;
      }
  ​
      public void setSalary(Double salary) {
          this.salary = salary;
      }
  ​
      public Date getBirthday() {
          return birthday;
      }
  ​
      public void setBirthday(Date birthday) {
          this.birthday = birthday;
      }
  ​
      public String getPhoto() {
          return photo;
      }
  ​
      public void setPhoto(String photo) {
          this.photo = photo;
      }
  ​
      @Override
      public String toString() {
          return "Employee{" +
                  "id=" + id +
                  ", name='" + name + '\'' +
                  ", salary=" + salary +
                  ", birthday=" + birthday +
                  ", photo='" + photo + '\'' +
                  '}';
      }
  }
  ​

新建EmployeeDAO

  
  package com.study.dao;
  ​
  import com.study.entity.Employee;
  ​
  import java.util.List;
  ​
  /**
   * @ClassName EmployeeDAO
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 18:23
   * @Version 1.0
   */
  public interface EmployeeDAO {
      /**
       * @MethodName lists
       * @Description 员工列表
       * @return: java.util.List<com.study.entity.Employee>
       * @Author Jiangnan Cui
       * @Date 2022/6/27 18:24
       */
      List<Employee> lists();
  }
  ​

新建EmployeeDAOMapper

  
  <?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.study.dao.EmployeeDAO">
      <!--lists-->
      <select id="lists" resultType="Employee">
          select
              id,name,salary,birthday,photo
          from employee
      </select>
  </mapper>

新建EmployeeService

  
  package com.study.service;
  ​
  import com.study.entity.Employee;
  ​
  import java.util.List;
  ​
  /**
   * @ClassName EmployeeService
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 18:26
   * @Version 1.0
   */
  public interface EmployeeService {
      /**
       * @MethodName lists
       * @Description 员工列表
       * @return: java.util.List<com.study.entity.Employee>
       * @Author Jiangnan Cui
       * @Date 2022/6/27 18:27
       */
      List<Employee> lists();
  }
  ​

新建EmployeeServiceImpl

  package com.study.service;
  ​
  import com.study.dao.EmployeeDAO;
  import com.study.entity.Employee;
  import org.springframework.beans.factory.annotation.Autowired;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  ​
  import java.util.List;
  ​
  /**
   * @ClassName EmployeeServiceImpl
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 18:27
   * @Version 1.0
   */
  @Service
  @Transactional
  public class EmployeeServiceImpl implements EmployeeService{
      //业务逻辑层调用数据访问层
      private EmployeeDAO employeeDAO;
      @Autowired
      public EmployeeServiceImpl(EmployeeDAO employeeDAO) {
          this.employeeDAO = employeeDAO;
      }
  ​
      /**
       * @MethodName lists
       * @Description 员工列表
       * @return: java.util.List<com.study.entity.Employee>
       * @Author Jiangnan Cui
       * @Date 2022/6/27 18:29
       */
      @Override
      public List<Employee> lists() {
          return employeeDAO.lists();
      }
  }
  ​

完善EmployeeController

  
  package com.study.controller;
  ​
  import com.study.entity.Employee;
  import com.study.service.EmployeeService;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  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.List;
  ​
  /**
   * @ClassName EmployeeController
   * @Description TODO
   * @Author Jiangnan Cui
   * @Date 2022/6/27 17:15
   * @Version 1.0
   */
  @Controller
  @RequestMapping("employee")
  public class EmployeeController {
      //日志对象
      private static final Logger log = LoggerFactory.getLogger(EmployeeController.class);
  ​
      //控制层调用业务逻辑层
      private EmployeeService employeeService;
      @Autowired
      public EmployeeController(EmployeeService employeeService) {
          this.employeeService = employeeService;
      }
  ​
      /**
       * @MethodName list
       * @Description 员工列表
       * @param: model
       * @return: java.lang.String
       * @Author Jiangnan Cui
       * @Date 2022/6/27 18:04
       */
      @RequestMapping("lists")
      public String list(Model model){
          log.debug("查询所有员工信息");
          List<Employee> employeeList = employeeService.lists();
          model.addAttribute("employeeList",employeeList);
          return "emplist";
      }
  }

测试路径:http://localhost:8888/ems-thymeleaf/employee/lists

2.9 添加员工

完善EmployeDAO

  /**
   * @MethodName addEmp
   * @Description 保存员工信息
   * @param: employee
   * @Author Jiangnan Cui
   * @Date 2022/6/27 20:11
   */
  void addEmp(Employee employee);

完善EmpDAOMapper

  <!--addEmp-->
  <insert id="addEmp" parameterType="Employee" useGeneratedKeys="true" keyProperty="id">
      insert into employee values(#{id},#{name},#{salary},#{birthday},#{photo})
  </insert>

完善EmployeeService

  /**
   * @MethodName addEmp
   * @Description
   * @param: employee
   * @Author Jiangnan Cui
   * @Date 2022/6/27 20:12
   */
  void addEmp(Employee employee);

完善EmpEmployeeServiceImpl

  /**
   * @MethodName addEmp
   * @Description 添加员工信息
   * @param: employee
   * @Author Jiangnan Cui
   * @Date 2022/6/27 20:13
   */
  @Override
  public void addEmp(Employee employee) {
      employeeDAO.addEmp(employee);
  }

EmployeeController

  //定义文件路径
  @Value("${photo.file.dir}")
  private String realpath;
  ​
  /**
   * @MethodName uploadPhoto
   * @Description 上传头像
   * @param: img
   * @param: originalFileName
   * @return: java.lang.String
   * @Author Jiangnan Cui
   * @Date 2022/6/27 20:23
   */
  private String uploadPhoto(MultipartFile img,String originalFileName) throws IOException {
      String fileNamePrefix = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
      String fileNameSuffix = originalFileName.substring(originalFileName.lastIndexOf("."));
      String newFileName = fileNamePrefix + fileNameSuffix;
      img.transferTo(new File(realpath,newFileName));
      return newFileName;
  }
  ​
  /**
   * @MethodName addEmp
   * @Description 添加员工信息
   * @param: employee
   * @param: img
   * @return: java.lang.String
   * @Author Jiangnan Cui
   * @Date 2022/6/27 20:15
   */
  @RequestMapping("addEmp")
  public String addEmp(Employee employee, MultipartFile img) throws IOException {
      log.debug("姓名:{},工资:{},生日:{}",employee.getName(),employee.getSalary(),employee.getBirthday());
      //获得图片原始文件名
      String originalFilename = img.getOriginalFilename();
      log.debug("头像名称:{}",originalFilename);
      log.debug("头像大小:{}",img.getSize());
      log.debug("上传路径:{}",realpath);
  ​
      //1.处理头像的上传
      String newFileName = uploadPhoto(img, originalFilename);
      //2.保存员工信息
      employee.setPhoto(newFileName);//保存头衔名字
      employeeService.addEmp(employee);
      return "redirect:/employee/lists";//保存成功跳转到员工列表
  }

application.yml添加文件上传配置

  
  # 公共配置
  server:
    port: 8888
    servlet:
      context-path: /ems-thymeleaf
  ​
  # Thymeleaf配置
  spring:
    thymeleaf:
      cache: false
      prefix: classpath:/templates/
      suffix: .html
  ​
  # 配置数据源
    datasource:
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/ems-thymeleaf?characterEncoding=UTF-8
      username: root
      password: 123456
    # 暴露哪些资源可以通过项目名直接访问
    web:
      resources:
        static-locations: classpath:/static/,file:${photo.file.dir}
  ​
  # 配置mybatis
  mybatis:
    mapper-locations: classpath:com/study/mapper/*.xml
    type-aliases-package: com.study.entity
  ​
  # 配置日志
  logging:
    level:
      root: info
      com.study: debug
  ​
  # 指定文件上传位置
  photo:
    file:
      dir: D:\Software_Development\IDEA_code\SpringBoot\ems-thymeleaf\photos
  ​

完善MvcConfig

  
  @Configuration
  public class MvcConfig implements WebMvcConfigurer {
      @Override
      //通过在这里面配置,不需要再为每一个访问thymeleaf模板页面单独开发一个controller请求了
      public void addViewControllers(ViewControllerRegistry registry) {
          //ViewController: 请求路径,ViewName: 跳转视图
          registry.addViewController("login").setViewName("login");
          registry.addViewController("register").setViewName("regist");
          registry.addViewController("addEmp").setViewName("addEmp");
      }
  }

addEmp.html

  
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html xmlns:th="http://www.thymealf.org">
      <head>
          <title>添加员工信息</title>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <link rel="stylesheet" type="text/css"
              href="css/style.css" />
      </head>
  ​
      <body>
          <div id="wrap">
              <div id="top_content">
                      <div id="header">
                          <div id="rightheader">
                              <p>
                                  2009/11/20
                                  <br />
                              </p>
                          </div>
                          <div id="topheader">
                              <h1 id="title">
                                  <a href="#">main</a>
                              </h1>
                          </div>
                          <div id="navigation">
                          </div>
                      </div>
                  <div id="content">
                      <p id="whereami">
                      </p>
                      <h1>
                          添加员工信息:
                      </h1>
                      <form th:action="@{/employee/addEmp}" method="post" enctype="multipart/form-data">
                          <table cellpadding="0" cellspacing="0" border="0"
                              class="form_table">
                              <tr>
                                  <td valign="middle" align="right">
                                      姓名:
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="text" class="inputgri" name="name" />
                                  </td>
                              </tr>
                              <tr>
                                  <td valign="middle" align="right">
                                      头像:
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="file" width="" name="img" />
                                  </td>
                              </tr>
                              <tr>
                                  <td valign="middle" align="right">
                                      工资:
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="text" class="inputgri" name="salary" />
                                  </td>
                              </tr>
                              <tr>
                                  <td valign="middle" align="right">
                                      生日:
                                  </td>
                                  <td valign="middle" align="left">
                                      <input type="text" class="inputgri" name="birthday" />
                                  </td>
                              </tr>
                          </table>
                          <p>
                              <input type="submit" class="button" value="确认添加" />
                              <input type="submit" class="button" value="返回列表" />
                          </p>
                      </form>
                  </div>
              </div>
              <div id="footer">
                  <div id="footer_bg">
                      ABC@126.com
                  </div>
              </div>
          </div>
      </body>
  </html>
  ​

访问路径:http://localhost:8888/ems-thymeleaf/employee/lists,添加员工信息

2.10 更新员工信息

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

完善EmployeeController

 /**
  * @MethodName detail
  * @Description 根据id查询员工详细信息
  * @param: id
  * @param: model
  * @return: java.lang.String
  * @Author Jiangnan Cui
  * @Date 7:05 2022/6/29
  */
 @RequestMapping("detail")
 public String detail(Integer id,Model model){
     log.debug("当前查询员工id:{}",id);
     //根据id查询员工详细信息
     Employee employee = employeeService.findById(id);
     model.addAttribute("employee",employee);
     return "updateEmp";//查询到的员工信息显示在更新页面
 }
 ​
 /**
  * @MethodName updateEmp
  * @Description 更新员工信息
  * @param: employee
  * @return: java.lang.String
  * @Author Jiangnan Cui
  * @Date 7:15 2022/6/29
  */
 @RequestMapping("updateEmp")
 public String updateEmp(Employee employee,MultipartFile img) throws IOException {
     //1.判断是否更新头像 为空时说明头像未更新,
     boolean notEmpty = !img.isEmpty();
     log.debug("是否更新了头像:{}",notEmpty);
     //不为空时说明头像更新了:需要删除老的头像,重新上传新的头像
     if(notEmpty){
         //1.根据id查询原始头像
         String oldPhoto = employeeService.findById(employee.getId()).getPhoto();
         //2.删除老的头像
         File file = new File(realpath,oldPhoto);
         if(file.exists())
             file.delete();
         //3.处理新的头像上传
         String originalFilename = img.getOriginalFilename();
         String newFileName = uploadPhoto(img, originalFilename);
         //4.修改员工新的头像名称
         employee.setPhoto(newFileName);
     }
     //为空时说明头像未更新,只需要更新基本信息即可
     employeeService.updateEmp(employee);
     //更新成功后跳转到员工列表页面
     return "redirect:/employee/lists";
 }

完善updateEmp.html

 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html xmlns:th="http://www.thymeleaf.org">
     <head>
         <title>更新员工信息</title>
         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
         <link rel="stylesheet" type="text/css"
             th:href="@{/css/style.css}" />
     </head>
 ​
     <body>
         <div id="wrap">
             <div id="top_content">
                     <div id="header">
                         <div id="rightheader">
                             <p>
                                 2009/11/20
                                 <br />
                             </p>
                         </div>
                         <div id="topheader">
                             <h1 id="title">
                                 <a href="#">main</a>
                             </h1>
                         </div>
                         <div id="navigation">
                         </div>
                     </div>
                 <div id="content">
                     <p id="whereami">
                     </p>
                     <h1>
                         更新员工信息:
                     </h1>
                     <form th:action="@{/employee/updateEmp}" method="post" enctype="multipart/form-data">
                         <table cellpadding="0" cellspacing="0" border="0"
                             class="form_table">
                             <tr>
                                 <td valign="middle" align="right">
                                     编号:
                                 </td>
                                 <td valign="middle" align="left">
                                     <span th:text="${employee.id}"></span>
                                     <input type="hidden" name="id" th:value="${employee.id}">
                                 </td>
                             </tr>
                             <tr>
                                 <td valign="middle" align="right">
                                     姓名:
                                 </td>
                                 <td valign="middle" align="left">
                                     <input type="text" class="inputgri" name="name" th:value="${employee.name}"/>
                                 </td>
                             </tr>
                             <tr>
                                 <td valign="middle" align="right">
                                     当前头像:
                                 </td>
                                 <td valign="middle" align="left">
                                     <img th:src="@{/}+${employee.photo}" width="60">
                                     <input type="hidden" th:value="${employee.photo}" name="photo">
                                 </td>
                             </tr>
                             <tr>
                                 <td valign="middle" align="right">
                                     选择新头像:
                                 </td>
                                 <td valign="middle" align="left">
                                     <input type="file" name="img" />
                                 </td>
                             </tr>
                             <tr>
                                 <td valign="middle" align="right">
                                     工资:
                                 </td>
                                 <td valign="middle" align="left">
                                     <input type="text" class="inputgri" name="salary" th:value="${employee.salary}"/>
                                 </td>
                             </tr>
                             <tr>
                                 <td valign="middle" align="right">
                                     生日:
                                 </td>
                                 <td valign="middle" align="left">
                                     <input type="text" class="inputgri" name="birthday" th:value="${#dates.format(employee.birthday,'yyyy/MM/dd')}"/>
                                 </td>
                             </tr>
                         </table>
                         <p>
                             <input type="submit" class="button" value="更新" />
                             <input type="button" class="button" value="返回列表" />
                         </p>
                     </form>
                 </div>
             </div>
             <div id="footer">
                 <div id="footer_bg">
                     ABC@126.com
                 </div>
             </div>
         </div>
     </body>
 </html>
 ​

完善EmployeeService

 /**
  * @MethodName findById
  * @Description 根据id查询员工详细信息
  * @param: id
  * @return: com.study.entity.Employee
  * @Author Jiangnan Cui
  * @Date 7:03 2022/6/29
  */
 Employee findById(Integer id);
 ​
 /**
  * @MethodName updateEmp
  * @Description 更新员工信息
  * @param: employee
  * @Author Jiangnan Cui
  * @Date 7:44 2022/6/29
  */
 void updateEmp(Employee employee);

完善EmployeeServiceImpl

 /**
  * @MethodName findById
  * @Description 根据id查询员工信息
  * @param: id
  * @return: com.study.entity.Employee
  * @Author Jiangnan Cui
  * @Date 7:03 2022/6/29
  */
 @Override
 public Employee findById(Integer id) {
     return employeeDAO.findById(id);
 }
 ​
 /**
  * @MethodName updateEmp
  * @Description 更新员工信息
  * @param: employee
  * @Author Jiangnan Cui
  * @Date 7:45 2022/6/29
  */
 @Override
 public void updateEmp(Employee employee) {
     employeeDAO.updateEmp(employee);
 }

完善EmployeeDAO

 /**
  * @MethodName findById
  * @Description 根据id查询员工详细信息
  * @param: id
  * @return: com.study.entity.Employee
  * @Author Jiangnan Cui
  * @Date 7:04 2022/6/29
  */
 Employee findById(Integer id);
 ​
 /**
  * @MethodName updateEmp
  * @Description 更新员工信息
  * @param: employee
  * @Author Jiangnan Cui
  * @Date 7:47 2022/6/29
  */
 void updateEmp(Employee employee);

完善EmployeeDAOMapper

     <!--findById-->
     <select id="findById" parameterType="Integer" resultType="Employee">
         select
             id,name,salary,birthday,photo
         from employee
         where id=#{id}
     </select>
 ​
     <!--updateEmp-->
     <update id="updateEmp" parameterType="Employee">
         update employee
         set name=#{name},salary=#{salary},birthday=#{birthday},photo=#{photo}
         where id=#{id}
     </update>

测试路径:http://localhost:8888/ems-thymeleaf/employee/lists

(1)点击更新,进行员工信息更新

(2)填写要修改的员工信息,修改完成后,点击更新

(3)更新后的员工信息

2.11 删除员工信息

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

完善EmpController

 /**
  * @MethodName deleteEmp
  * @Description 删除员工信息
  * @param: id
  * @return: java.lang.String
  * @Author Jiangnan Cui
  * @Date 8:43 2022/6/29
  */
 @RequestMapping("deleteEmp")
 public String deleteEmp(Integer id){
     log.debug("删除的员工id:{}",id);
     //1.删除数据
     String photo = employeeService.findById(id).getPhoto();
     employeeService.deleteEmp(id);
     //2.删除头像
     File file = new File(realpath,photo);
     if(file.exists())
         file.delete();
     return "redirect:/employee/lists";//删除成功后跳转到员工列表
 }

完善emplist.html

 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html xmlns:th="http://www.thymeleaf.org">
     <head>
         <title>emplist</title>
         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
         <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />
     </head>
     <body>
         <div id="wrap">
             <div id="top_content"> 
                 <div id="header">
                     <div id="rightheader">
                         <p>
                             2009/11/20 
                             <br />
                             <a th:if="${session.user!=null}" th:href="@{/user/logout}">安全退出</a>
                             <a th:if="${session.user==null}" th:href="@{/login}">点我登录</a>
                         </p>
                     </div>
                     <div id="topheader">
                         <h1 id="title">
                             <a href="#">main</a>
                         </h1>
                     </div>
                     <div id="navigation">
                     </div>
                 </div>
                 <div id="content">
                     <p id="whereami">
                     </p>
                     <h1>
                         欢迎 <span th:if="${session.user!=null}" th:text="${session.user.username}"></span>
                             <span th:if="${session.user==null}" >游客</span>!
                     </h1>
                     <table class="table">
                         <tr class="table_header">
                             <td>
                                 编号
                             </td>
                             <td>
                                 姓名
                             </td>
                             <td>
                                 头像
                             </td>
                             <td>
                                 工资
                             </td>
                             <td>
                                 生日
                             </td>
                             <td>
                                 操作
                             </td>
                         </tr>
                         <tr th:each="employee,state:${employeeList}"  th:class="${state.odd?'row1':'row2'}">
                             <td>
                                 <span th:text="${employee.id}"></span>
                             </td>
                             <td>
                                 <span th:text="${employee.name}"></span>
                             </td>
                             <td>
                                 <img th:src="@{/}+${employee.photo}" width="60">
                             </td>
                             <td>
                                 <span th:text="${employee.salary}"></span>
                             </td>
                             <td>
                                 <span th:text="${#dates.format(employee.birthday,'yyyy/MM/dd')}"></span>
                             </td>
                             <td>
                                 <a href="javascript:;" th:οnclick="'deleteEmployee('+${employee.id}+')'">删除</a>
 <!--                                <a th:href="@{/employee/detail?id=}+${employee.id}+'&name='+${employee.name}">更新</a>-->
 <!--                                <a th:href="@{/employee/detail(id=${employee.id},name=${employee.name})}">更新</a>-->
                                 <a th:href="@{/employee/detail(id=${employee.id})}">更新</a>
 ​
                             </td>
                         </tr>
                         <script>
                             function deleteEmployee(id){
                                 console.log(id);
                                 if(window.confirm('确定要删除这条记录吗?')){
                                     location.href='[[@{/employee/deleteEmp?id=}]]'+id;
                                 }
                             }
                         </script>
                     </table>
                     <p>
                         <input type="button" class="button" value="添加" οnclick="addEmp()"/>
                         <script>
                             function addEmp(){
                                 location.href = '[[@{/addEmp}]]';
                             }
                         </script>
                     </p>
                 </div>
             </div>
             <div id="footer">
                 <div id="footer_bg">
                 ABC@126.com
                 </div>
             </div>
         </div>
     </body>
 </html>
 ​

完善EmpService

 /**
  * @MethodName deleteEmp
  * @Description 删除员工信息
  * @param: id
  * @Author Jiangnan Cui
  * @Date 8:48 2022/6/29
  */
 void deleteEmp(Integer id);

完善EmpServiceImpl

 /**
  * @MethodName deleteEmp
  * @Description 删除员工信息
  * @param: id
  * @Author Jiangnan Cui
  * @Date 8:49 2022/6/29
  */
 @Override
 public void deleteEmp(Integer id) {
     employeeDAO.deleteEmp(id);
 }

完善EmployeeDAO

 /**
  * @MethodName deleteEmp
  * @Description 删除员工信息
  * @param: id
  * @Author Jiangnan Cui
  * @Date 8:49 2022/6/29
  */
 void deleteEmp(Integer id);

完善EmployeeDAOMapper

 <!--deleteEmp-->
 <delete id="deleteEmp" parameterType="Integer">
     delete from employee where id=#{id}
 </delete>

测试路径:http://localhost:8888/ems-thymeleaf/employee/lists,点击删除的同时,员工信息删除且photos中的头像图片也删除。

2.12 安全退出

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili

完善UserController

 /**
  * @MethodName logout
  * @Description 安全退出
  * @return: java.lang.String
  * @Author Jiangnan Cui
  * @Date 14:08 2022/6/29
  */
 @RequestMapping("logout")
 public String logout(HttpSession session){
     session.invalidate();//session失效
     return "redirect:/login";//跳转到登录页面
 }

完善emplist.html

 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html xmlns:th="http://www.thymeleaf.org">
     <head>
         <title>emplist</title>
         <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
         <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />
     </head>
     <body>
         <div id="wrap">
             <div id="top_content"> 
                 <div id="header">
                     <div id="rightheader">
                         <p>
                             2009/11/20 
                             <br />
                             <a th:if="${session.user!=null}" th:href="@{/user/logout}">安全退出</a>
                             <a th:if="${session.user==null}" th:href="@{/login}">点我登录</a>
                         </p>
                     </div>
                     <div id="topheader">
                         <h1 id="title">
                             <a href="#">main</a>
                         </h1>
                     </div>
                     <div id="navigation">
                     </div>
                 </div>
                 <div id="content">
                     <p id="whereami">
                     </p>
                     <h1>
                         欢迎 <span th:if="${session.user!=null}" th:text="${session.user.username}"></span>
                             <span th:if="${session.user==null}" >游客</span>!
                     </h1>
                     <table class="table">
                         <tr class="table_header">
                             <td>
                                 编号
                             </td>
                             <td>
                                 姓名
                             </td>
                             <td>
                                 头像
                             </td>
                             <td>
                                 工资
                             </td>
                             <td>
                                 生日
                             </td>
                             <td>
                                 操作
                             </td>
                         </tr>
                         <tr th:each="employee,state:${employeeList}"  th:class="${state.odd?'row1':'row2'}">
                             <td>
                                 <span th:text="${employee.id}"></span>
                             </td>
                             <td>
                                 <span th:text="${employee.name}"></span>
                             </td>
                             <td>
                                 <img th:src="@{/}+${employee.photo}" width="60">
                             </td>
                             <td>
                                 <span th:text="${employee.salary}"></span>
                             </td>
                             <td>
                                 <span th:text="${#dates.format(employee.birthday,'yyyy/MM/dd')}"></span>
                             </td>
                             <td>
                                 <a href="javascript:;" th:οnclick="'deleteEmployee('+${employee.id}+')'">删除</a>
 <!--                                <a th:href="@{/employee/detail?id=}+${employee.id}+'&name='+${employee.name}">更新</a>-->
 <!--                                <a th:href="@{/employee/detail(id=${employee.id},name=${employee.name})}">更新</a>-->
                                 <a th:href="@{/employee/detail(id=${employee.id})}">更新</a>
 ​
                             </td>
                         </tr>
                         <script>
                             function deleteEmployee(id){
                                 console.log(id);
                                 if(window.confirm('确定要删除这条记录吗?')){
                                     location.href='[[@{/employee/deleteEmp?id=}]]'+id;
                                 }
                             }
                         </script>
                     </table>
                     <p>
                         <input type="button" class="button" value="添加" οnclick="addEmp()"/>
                         <script>
                             function addEmp(){
                                 location.href = '[[@{/addEmp}]]';
                             }
                         </script>
                     </p>
                 </div>
             </div>
             <div id="footer">
                 <div id="footer_bg">
                 ABC@126.com
                 </div>
             </div>
         </div>
     </body>
 </html>
 ​

测试路径:http://localhost:8888/ems-thymeleaf/employee/lists

(1)未登录

(2)登录后

(3)安全登出后,需要重新登录

2.13 完整项目结构

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值