原文: https://howtodoinjava.com/spring-boot2/crud-application-thymeleaf/

通过基于 Thymeleaf 和 spring mvc 支持的基于表单的 UI,学习构建支持 CRUD 操作的 Spring Boot Web 应用程序。

1. 概述

在本教程中,我们正在创建具有两个视图的 Web 应用程序

  • 列出所有员工视图 – 以表格形式在 UI 中从数据库显示所有员工。 此外,还有指向“更新”或“删除”任何员工的链接。 该界面还具有一个单独的选项,可以导航到“创建”员工界面。
    Spring Boot – CRUD 应用程序 - 图1
    列出所有员工的界面

  • 创建/更新员工视图 – 此界面用于添加新员工或编辑现有员工的详细信息。
    Spring Boot – CRUD 应用程序 - 图2
    添加员工的界面

此示例中有两个主要组件需要重点关注-MVC 控制器和 UI 视图。

2. Spring MVC 控制器

控制器类具有 URL 映射及其处理器方法。 所有 CRUD 操作都有处理器方法,包括 POST 操作,以处理表单提交以创建/更新员工的过程。

注意给定的处理器方法如何将模型数据绑定到视图; 并且它们以字符串格式返回视图名称,该视图名称由 HTML 文件中的视图解析器解析。

EmployeeMvcController.java

  1. import java.util.List;
  2. import java.util.Optional;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Controller;
  5. import org.springframework.ui.Model;
  6. import org.springframework.web.bind.annotation.PathVariable;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RequestMethod;
  9. import com.howtodoinjava.demo.entity.EmployeeEntity;
  10. import com.howtodoinjava.demo.exception.RecordNotFoundException;
  11. import com.howtodoinjava.demo.service.EmployeeService;
  12. @Controller
  13. @RequestMapping("/")
  14. public class EmployeeMvcController
  15. {
  16. @Autowired
  17. EmployeeService service;
  18. @RequestMapping
  19. public String getAllEmployees(Model model)
  20. {
  21. List<EmployeeEntity> list = service.getAllEmployees();
  22. model.addAttribute("employees", list);
  23. return "list-employees";
  24. }
  25. @RequestMapping(path = {"/edit", "/edit/{id}"})
  26. public String editEmployeeById(Model model, @PathVariable("id") Optional<Long> id)
  27. throws RecordNotFoundException
  28. {
  29. if (id.isPresent()) {
  30. EmployeeEntity entity = service.getEmployeeById(id.get());
  31. model.addAttribute("employee", entity);
  32. } else {
  33. model.addAttribute("employee", new EmployeeEntity());
  34. }
  35. return "add-edit-employee";
  36. }
  37. @RequestMapping(path = "/delete/{id}")
  38. public String deleteEmployeeById(Model model, @PathVariable("id") Long id)
  39. throws RecordNotFoundException
  40. {
  41. service.deleteEmployeeById(id);
  42. return "redirect:/";
  43. }
  44. @RequestMapping(path = "/createEmployee", method = RequestMethod.POST)
  45. public String createOrUpdateEmployee(EmployeeEntity employee)
  46. {
  47. service.createOrUpdateEmployee(employee);
  48. return "redirect:/";
  49. }
  50. }
  • getAllEmployees() – 返回所有员工的列表,并映射到路径/。 这是应用程序的默认视图。
  • editEmployeeById() – 用于添加新员工或编辑现有员工。 两种操作都使用相同的 HTML 视图。 如果上下文中有一个员工 ID,则将对该员工进行编辑-否则将创建一个新员工。
  • deleteEmployeeById() – 通过 ID 删除员工的简单 URL 请求。
  • createOrUpdateEmployee() – 此方法处理用于创建新雇员或更新雇员的 HTTP POST 请求。 创建或更新操作取决于模型中是否存在员工 ID。

3. Thymeleaf 模板

如前所述,我们在此示例中使用两个视图。

list-employees.html

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="x-ua-compatible" content="ie=edge">
  6. <title>All Employees</title>
  7. <meta name="viewport" content="width=device-width, initial-scale=1">
  8. <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
  9. <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css">
  10. </head>
  11. <body>
  12. <div class="container my-2">
  13. <div class="card">
  14. <div class="card-body">
  15. <div th:switch="${employees}" class="container my-5">
  16. <p class="my-5">
  17. <a href="/edit" class="btn btn-primary">
  18. <i class="fas fa-user-plus ml-2"> Add Employee </i></a>
  19. </p>
  20. <div class="col-md-10">
  21. <h2 th:case="null">No record found !!</h2>
  22. <div th:case="*">
  23. <table class="table table-striped table-responsive-md">
  24. <thead>
  25. <tr>
  26. <th>First Name</th>
  27. <th>Last Name</th>
  28. <th>Email</th>
  29. <th>Edit</th>
  30. <th>Delete</th>
  31. </tr>
  32. </thead>
  33. <tbody>
  34. <tr th:each="employee : ${employees}">
  35. <td th:text="${employee.firstName}"></td>
  36. <td th:text="${employee.lastName}"></td>
  37. <td th:text="${employee.email}"></td>
  38. <td>
  39. <a th:href="@{/edit/{id}(id=${employee.id})}"
  40. class="btn btn-primary">
  41. <i class="fas fa-user-edit ml-2"></i>
  42. </a>
  43. </td>
  44. <td>
  45. <a th:href="@{/delete/{id}(id=${employee.id})}"
  46. class="btn btn-primary">
  47. <i class="fas fa-user-times ml-2"></i>
  48. </a>
  49. </td>
  50. </tr>
  51. </tbody>
  52. </table>
  53. </div>
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. </body>
  60. </html>

add-edit-employee.html

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="utf-8">
  5. <meta http-equiv="x-ua-compatible" content="ie=edge">
  6. <title>Add Employee</title>
  7. <meta name="viewport" content="width=device-width, initial-scale=1">
  8. <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
  9. <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css">
  10. </head>
  11. <body>
  12. <div class="container my-5">
  13. <h3> Add Employee</h3>
  14. <div class="card">
  15. <div class="card-body">
  16. <div class="col-md-10">
  17. <form action="#" th:action="@{/createEmployee}" th:object="${employee}"
  18. method="post">
  19. <div class="row">
  20. <div class="form-group col-md-8">
  21. <label for="name" class="col-form-label">First Name</label>
  22. <input type="text" th:field="*{firstName}" class="form-control"
  23. id="firstName" placeholder="First Name" />
  24. </div>
  25. <div class="form-group col-md-8">
  26. <label for="name" class="col-form-label">Last Name</label>
  27. <input type="text" th:field="*{lastName}" class="form-control"
  28. id="lastName" placeholder="Last Name" />
  29. </div>
  30. <div class="form-group col-md-8">
  31. <label for="email" class="col-form-label">Email</label>
  32. <input type="text" th:field="*{email}" class="form-control"
  33. id="email" placeholder="Email Id" />
  34. </div>
  35. <div class="col-md-6">
  36. <input type="submit" class="btn btn-primary" value=" Submit ">
  37. </div>
  38. <input type="hidden" id="id" th:field="*{id}">
  39. </div>
  40. </form>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. </body>
  46. </html>

4. 实体和存储库

我们已经将EmployeeEntity类作为模型绑定到 UI。

EmployeeEntity.java

  1. import javax.persistence.Column;
  2. import javax.persistence.Entity;
  3. import javax.persistence.GeneratedValue;
  4. import javax.persistence.Id;
  5. import javax.persistence.Table;
  6. @Entity
  7. @Table(name="TBL_EMPLOYEES")
  8. public class EmployeeEntity {
  9. @Id
  10. @GeneratedValue(strategy = GenerationType.IDENTITY)
  11. private Long id;
  12. @Column(name="first_name")
  13. private String firstName;
  14. @Column(name="last_name")
  15. private String lastName;
  16. @Column(name="email", nullable=false, length=200)
  17. private String email;
  18. //Setters and getters
  19. @Override
  20. public String toString() {
  21. return "EmployeeEntity [id=" + id + ", firstName=" + firstName +
  22. ", lastName=" + lastName + ", email=" + email + "]";
  23. }
  24. }

为了将数据持久存储在数据库中,我们使用 H2(内存中)数据库,并使用 Spring 数据的CrudRepository接口。 它为简单的 CRUD 操作提供了开箱即用的内置方法。

EmployeeRepository.java

  1. import org.springframework.data.repository.CrudRepository;
  2. import org.springframework.stereotype.Repository;
  3. import com.howtodoinjava.demo.entity.EmployeeEntity;
  4. @Repository
  5. public interface EmployeeRepository
  6. extends CrudRepository<EmployeeEntity, Long> {
  7. }

请注意,使用两个 SQL 文件初始化了存储库,这两个 SQL 文件创建数据库表并向其中填充默认数据。

schema.sql

  1. DROP TABLE IF EXISTS TBL_EMPLOYEES;
  2. CREATE TABLE TBL_EMPLOYEES (
  3. id INT AUTO_INCREMENT PRIMARY KEY,
  4. first_name VARCHAR(250) NOT NULL,
  5. last_name VARCHAR(250) NOT NULL,
  6. email VARCHAR(250) DEFAULT NULL
  7. );

data.sql

  1. INSERT INTO
  2. TBL_EMPLOYEES (first_name, last_name, email)
  3. VALUES
  4. ('Lokesh', 'Gupta', 'howtodoinjava@gmail.com'),
  5. ('John', 'Doe', 'xyz@email.com');

5. 服务类

另一个重要的类是EmployeeService类,控制器通过该类与存储库进行交互。 它包含要执行的其他业务逻辑。

EmployeeService.java

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import java.util.Optional;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Service;
  6. import com.howtodoinjava.demo.entity.EmployeeEntity;
  7. import com.howtodoinjava.demo.exception.RecordNotFoundException;
  8. import com.howtodoinjava.demo.repository.EmployeeRepository;
  9. @Service
  10. public class EmployeeService {
  11. @Autowired
  12. EmployeeRepository repository;
  13. public List<EmployeeEntity> getAllEmployees()
  14. {
  15. List<EmployeeEntity> result = (List<EmployeeEntity>) repository.findAll();
  16. if(result.size() > 0) {
  17. return result;
  18. } else {
  19. return new ArrayList<EmployeeEntity>();
  20. }
  21. }
  22. public EmployeeEntity getEmployeeById(Long id) throws RecordNotFoundException
  23. {
  24. Optional<EmployeeEntity> employee = repository.findById(id);
  25. if(employee.isPresent()) {
  26. return employee.get();
  27. } else {
  28. throw new RecordNotFoundException("No employee record exist for given id");
  29. }
  30. }
  31. public EmployeeEntity createOrUpdateEmployee(EmployeeEntity entity)
  32. {
  33. if(entity.getId() == null)
  34. {
  35. entity = repository.save(entity);
  36. return entity;
  37. }
  38. else
  39. {
  40. Optional<EmployeeEntity> employee = repository.findById(entity.getId());
  41. if(employee.isPresent())
  42. {
  43. EmployeeEntity newEntity = employee.get();
  44. newEntity.setEmail(entity.getEmail());
  45. newEntity.setFirstName(entity.getFirstName());
  46. newEntity.setLastName(entity.getLastName());
  47. newEntity = repository.save(newEntity);
  48. return newEntity;
  49. } else {
  50. entity = repository.save(entity);
  51. return entity;
  52. }
  53. }
  54. }
  55. public void deleteEmployeeById(Long id) throws RecordNotFoundException
  56. {
  57. Optional<EmployeeEntity> employee = repository.findById(id);
  58. if(employee.isPresent())
  59. {
  60. repository.deleteById(id);
  61. } else {
  62. throw new RecordNotFoundException("No employee record exist for given id");
  63. }
  64. }
  65. }

6. 添加 Spring Boot 和 Thymeleaf Maven 依赖项

在 spring boot 项目中,我们只需要添加spring-boot-starter-thymeleaf依赖项,并使用默认配置为项目本身自动配置 thymeleaf。 它从/src/main/resources/templates文件夹中读取 HTML 模板。

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <parent>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-parent</artifactId>
  9. <version>2.1.5.RELEASE</version>
  10. <relativePath /> <!-- lookup parent from repository -->
  11. </parent>
  12. <groupId>com.howtodoinjava</groupId>
  13. <artifactId>demo</artifactId>
  14. <version>0.0.1-SNAPSHOT</version>
  15. <name>demo</name>
  16. <description>Demo project for Spring Boot</description>
  17. <properties>
  18. <java.version>1.8</java.version>
  19. </properties>
  20. <dependencies>
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-starter-web</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-data-jpa</artifactId>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.springframework.boot</groupId>
  31. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  32. </dependency>
  33. <dependency>
  34. <groupId>com.h2database</groupId>
  35. <artifactId>h2</artifactId>
  36. <scope>runtime</scope>
  37. </dependency>
  38. <dependency>
  39. <groupId>org.springframework.boot</groupId>
  40. <artifactId>spring-boot-starter-test</artifactId>
  41. <scope>test</scope>
  42. </dependency>
  43. </dependencies>
  44. </project>

7. Spring Boot thymeleaf Crud 教程演示

以 Spring Boot 应用程序的形式启动此应用程序,该应用程序将在嵌入式 tomcat 服务器中启动 Web 应用程序。

点击网址:http://localhost:8080/

验证是否使用data.sql文件中的两个默认员工详细信息渲染了屏幕。

玩应用程序。 创建几个新员工,编辑现有员工。 删除一些员工。

如果在上述 spring boot mvc 示例中遇到任何错误,请告诉我。

下载源码

学习愉快!