[spring] Spring MVC - CRUD 操作

[spring] Spring MVC - CRUD 操作

基础实现源自于这两篇笔记:

除了 Rest API 部分改成了 Controller 之外,其他没什么变化,还是使用 service --> DAO --> DB 这个实现方式,因此关于 CRUD 的部分——即 hibernate 实现的部分,这里不会过多涉及

也因此,这部分的代码实现应该还是挺快的,毕竟主要还是 HTML 模板+controller 实现

获取 employee

除了新增 HTML 模板之外,主要还是把 @RestController 换成 @Controller,其他大方向没什么变化,实现如下:

@Controller
@RequestMapping("/employees")
public class EmployeeController {
    private EmployeeService employeeService;

    @Autowired
    public EmployeeController (EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @GetMapping("/list")
    public String listEmployees (Model model) {
        // get employee from db
        List<Employee> employeeList = employeeService.findAll();

        // add employees to model
        model.addAttribute("employees", employeeList);

        return "list-employees";
    }
}

这里先丢一个非常简单的 UI,保证逻辑对,数据可以正常显示即可:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8" />
    <title>Employee Directory</title>
  </head>
  <body>
    <span th:text="${employees}" />

    <script src="http://localhost:35729/livereload.js"></script>
  </body>
</html>

结果如下:

在这里插入图片描述

数据可以正常显示

从 8080 端口重定向

现在直接访问 localhost:8080 会显示 white label 的问题

考虑到正常情况下都是会直接访问 80/8080 端口,这里做一个小小的优化。首先在 resources/static 下面创建一个 index.html 文件,代码如下

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <meta http-equiv="refresh" content="0; URL='employees/list'" />
  </head>
  <body>
    <script src="http://localhost:35729/livereload.js"></script>
  </body>
</html>

这个操作就是在访问 8080 端口时,直接重定向到 localhost/employees/list,实现效果如下:

在这里插入图片描述

更新的 bootstrap 代码如下:

<tbody>
  <tr th:each="employee: ${employees}">
    <td th:text="${employee.firstName}"></td>
    <td th:text="${employee.lastName}"></td>
    <td th:text="${employee.email}"></td>
  </tr>
</tbody>

这里的 bootstrap 是直接引用 cdn 的

添加 employee

这里会出现一个新的知识点,controller 部分实现如下:

    @GetMapping("/showFormForAdd")
    public String addEmployee (Model model) {
        Employee employee = new Employee();

        model.addAttribute("employee", employee);
        return "employees/employee-form";
    }

    @PostMapping("/save")
    public String saveEmployee(@ModelAttribute("employee") Employee employee) {
        employeeService.save(employee);

        // use a redirect to prevent duplicate submission
        return "redirect:/employees/list";
    }

⚠️:这里的 redirect:/employees/list,这里主要告知 spring mvc,一个新的 GET 请求会被建立,这样可以有效避免重复提交数据

HTML 模板的实现如下,首先是添加一个按钮,重定向到新的 employee-form 页面:

<a th:href="@{/employees/showFormForAdd}" class="btn btn-primary btn-sm mb-3">
  Add Employee
</a>

随后再是新建一个表单,用来保存用户信息:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8" />
    <title>Save Employee</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <div class="container">
      <h3>Employee Directory</h3>
      <hr />

      <p class="h4 mb-4">Save Employee</p>

      <form
        action="#"
        th:action="@{/employees/save}"
        autocomplete="off"
        th:object="${employee}"
        method="post"
      >
        <label for="firstName">First Name: </label>
        <input
          type="text"
          th:field="*{firstName}"
          id="firstName"
          class="form-control mb-4 w-25"
          placeholder="First Name"
        />

        <label for="lastName">Last Name: </label>
        <input
          type="text"
          th:field="*{lastName}"
          id="lastName"
          class="form-control mb-4 w-25"
          placeholder="Last Name"
        />

        <label for="email">Email: </label>
        <input
          type="email"
          th:field="*{email}"
          id="email"
          class="form-control mb-4 w-25"
          placeholder="Email"
        />

        <button type="submit" class="btn btn-info col-2">Save</button>
      </form>

      <br />

      <a th:href="@{/employees/list}">Back to Employee List</a>
    </div>

    <script src="http://localhost:35729/livereload.js"></script>
  </body>
</html>

最终实现效果如下:

在这里插入图片描述

更新 employee

这里基本可以复用添加 employee 部分的代码,主要也是因为 hibernate 在实现 save 的功能时,如果当前的 DAO 在数据库已经存在的话,就会实现更新,反之实现新增

因此这里只需要做一点的更新即可,首先是 controller 部分的更新:

    @GetMapping("/showFormForUpdate")
    public String showFormForUpdate(@RequestParam("employeeId") int id, Model model) {
        // get employee from the service
        Employee employee = employeeService.findById(id);

        // set employee in the model to populate the form
        model.addAttribute("employee", employee);

        // send data over to form
        return "employees/employee-form";
    }

随后时添加新的 update 按钮,这部分添加到循环输出 employee 信息里的最后一行:

<td>
  <a
    th:href="@{/employees/showFormForUpdate(employeeId=${employee.id})}"
    class="btn btn-info btn-sm"
  >
    Update
  </a>
</td>

最后是新增一个隐藏的 id,这样可以让 HTML 模板中的对象和 controller 中实现正确的 mapping,毕竟 id 对于更新来说事必要的,如果没有这个隐藏的 id 选项,那么 findById 无法找到正确的对象,所有的更新操作都有可能成为新增操作:

<form
  action="#"
  th:action="@{/employees/save}"
  autocomplete="off"
  th:object="${employee}"
  method="post"
>
  <!-- add hidden form field to handle the update -->
  <input type="hidden" th:field="*{id}" />
</form>

最终效果如下:

在这里插入图片描述

数据库中的信息:

在这里插入图片描述

删除 employee

这部分也非常的简单,首先在添加 update 按钮的旁边新增一个 delete:

<a
  th:href="@{/employees/delete(employeeId=${employee.id})}"
  class="btn btn-danger btn-sm"
  onclick="if (!(confirm('Are you sure you want to delete this employee?'))) return false"
>
  Delete
</a>

controller 的更新如下:

    @GetMapping("/delete")
    public String delete(@RequestParam("employeeId") int id) {
        employeeService.deleteById(id);

        return "redirect:/employees/list";
    }

最终结果:

在这里插入图片描述

在这里插入图片描述

这样 spring mvc 的 crud 操作就都实现完成了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值