-

开启 java 安全学习第一站,SpringBoot

创建第一个 SpringBoot 项目

可以官网导入创建,这里就直接 IJ 导入了,方便一些。

0x01 打开 IDEA,新建项目

注意到Spring Boot 官方不再支持 Spring Boot 的 2.x 版本了,之后全力维护 3.x;而 Spring Boot 3.x 对 JDK 版本的最低要求是 17!所以我们选不了 java8 语言版本,我可以替换 Server URL 为阿里的镜像站,这样就可以选了 https://start.aliyun.com/

image-20240704145203626

0x02 选择 SpringBoot 版本,配置依赖

这里 jdk8 的话—定要选 SpringBoot 小于3.0.0的版本,依赖先添加一个 Spring Web,也可以不添加

image-20240704144207546

创建完成后把 demo 目录删掉

image-20240704152735004

0x03 配置启动端口,并且测试

resources 文件夹下找到 application.properties 文件,设置启动端口为 8088

1
server.port=8088

编写一个控制类

在启动页面同一级目录下,创建 controller 文件夹

image-20240704145318600

编写

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.she11f.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloWorld {
@RequestMapping("/hello")
public String helloWorld() {
return "Hello World!";
}
}

其中:@RestController = @Controller + @ResponseBody

而@ResponseBody : 该注解用于将Controller 的方法返回对象,
通过适当的HttpMessageConverter转换为指定格式后,写入Response对象的body数据区。

@Controller 不用解释了

另外:@RequestMapping :用来处理请求地址映射的注解,可用于类或方法上。

也可以写作 GetMapping 、PostMapping、PutMapping 、DeleteMapping 、PatchMapping。
这些在后面的文章我们在详细说明。

然后直接启动,访问 127.0.0.1:8088/hello/hello

image-20240704151542993

也可以把程序打包成 jar 包,然后命令行启动。点击 Maven 生命周期里的 packageinstall

image-20240704151823540

然后在 target 目录下发现一个 jar 包就证明打包成功了。

还能 DIY 一下,更改启动时banner图案。到项目下的 resources 目录下新建一个banner.txt 即可:

图案可以到网站 https://www.bootschool.net/ascii 生成,拷贝到文件中即可!

image-20240704152336572

SpringBoot 运行原理

贴个链接吧,感觉这个对开发来说都很难理解,先学会如何用吧。 Spring Boot:最全SpringBoot启动流程原理分析(全网最全最完善)-腾讯云开发者社区-腾讯云 (tencent.com)

Yaml 语法

SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的

  • application.properties
    • 语法结构 :key=value
  • application.yml
    • 语法结构 :key:空格 value

配置文件的作用 :修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;

就比如我们在项目创建的时候修改过 tomcat 启动端口为 8088,就是在 **application.properties **文件中修改。

0x01 yaml概述

传统xml配置:

1
<server><port>8081<port></server>

yaml配置:

1
2
server:  
prot: 8080

说明:语法要求严格!

  • 空格不能省略
  • 以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。
  • 属性和值的大小写都是十分敏感的。

0x02 基本写法

对象、Map(键值对)

1
#对象、Map格式k:     v1:        v2:

在下一行来写对象的属性和值得关系,注意缩进;比如:

1
2
3
student:    
name: she11F
age: 3

对了,我用的这个博客 hexo 配置文件就是用的 yaml

行内写法

1
student: {name: qinjiang,age: 3}

数组( List、set )

用 - 值表示数组中的一个元素,比如:

1
2
3
4
pets:     
- cat
- dog
- pig

行内写法

1
pets: [cat,dog,pig]

yaml 修改端口号的话就是这样写

1
2
server:
port: 8082

我们删除 application.properties ,新建 application.yaml

Web开发

0x01 静态资源处理

  1. webjars 导入

    Webjars本质就是以jar包的方式引入我们的静态资源 , 我们以前要导入一个静态资源文件,直接导入即可。

    网站:https://www.webjars.org

    比如说要使用jQuery,选择 maven 坐标,我们只要要引入jQuery对应版本的pom依赖即可!

    image-20240705115740587

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.webjars.npm</groupId>
    <artifactId>github-com-jquery-jquery</artifactId>
    <version>3.6.0</version>
    </dependency>

    image-20240705124015306

    访问:只要是静态资源,SpringBoot就会去对应的路径寻找资源,我们这里访问:127.0.0.1:8088/webjars/jquery/3.4.1/jquery.js 就能看到 jquery 源码

  2. 静态资源映射规则

​ 可以在 resources 文件夹下建立 public,static,resources,templates 文件夹来存放静态文件,比如在 public 下创办 1.js

image-20240705124346698

​ 访问路径 127.0.0.1:8088/1.js,它就会自动去寻找

0x02 thymeleaf 模板引擎

模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,就是我们在后台封装一些数据。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。只不过呢,就是说不同模板引擎之间,他们可能这个语法有点不一样。其他的我就不介绍了,我主要来介绍一下SpringBoot 给我们推荐的 Thymeleaf 模板引擎,这模板引擎呢,是一个高级语言的模板引擎,他的这个语法更简单。而且呢,功能更强大。

jsp支持非常强大的功能,包括能写Java代码,但是呢,我们现在的这种情况,SpringBoot这个项目首先是以jar的方式,不是war,像第二,我们用的还是嵌入式的Tomcat,所以呢,他现在默认是不支持jsp的

Thymeleaf 官网:https://www.thymeleaf.org/

Thymeleaf 在Github 的主页:https://github.com/thymeleaf/thymeleaf

Spring官方文档:找到我们对应的版本

https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter

找到对应的pom依赖:可以适当点进源码看下本来的包!

1
2
3
4
5
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Maven会自动下载jar包,我们可以去看下下载的东西;

image-20240705170358101

使用:

我们只需要把我们的html页面放在类路径下的 templates 下,thymeleaf就可以帮我们自动渲染了。在 templates 文件夹下新建 index.html 文件

要使用thymeleaf,需要在html文件中导入命名空间的约束,方便提示。可以去官方文档的#3中看一下命名空间拿来过来

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

编写 html 页面

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<!--使用http://www.thymeleaf.org/thymeleaf-extras-spring,红色下划线消失-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>测试页面</title>
</head>
<body>
<h1>Test</h1>
<!--th:text就是将div中的内容设置为它指定的值,和之前学习的Vue一样-->
<div th:text="${msg}"></div>
</body>
</html>

templates 目录下所有页面,只能通过 controller 来跳转。创建一个 test.html,控制器里的映射必须是 test 才行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.she11f.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ThymeleafDemo {
@RequestMapping("/test")
public String test1(Model model){
//存入数据
model.addAttribute("msg","Hello,Thymeleaf");
//classpath:/templates/test.html
return "test";
}
}

访问 http://127.0.0.1:8088/test

image-20240705235010216

控制器页面

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

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Arrays;
import java.util.Map;

@Controller
public class ThymeleafDemo {
@RequestMapping("/test")
public String test2(Map<String,Object> map){
//存入数据
map.put("msg","<h1>Hello</h1>");
map.put("users", Arrays.asList("zhangsan","lisi"));
//classpath:/templates/test.html
return "test";
}
}

html 页面语法其实和 vue 差不多

image-20240706165839000

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body>
<h1>测试页面</h1>
<div th:text="${msg}"></div>
<!--不转义-->
<div th:utext="${msg}"></div>
<!--遍历数据-->
<!--th:each每次遍历都会生成当前这个标签:官网#9-->
<h4 th:each="user :${users}" th:text="${user}"></h4>
<h4>
<!--行内写法:官网#12-->
<span th:each="user:${users}">[[${user}]]&nbsp;</span>
</h4>
</body>
</html>

image-20240706102905126

员工管理系统搭建

素材来自于 链接:https://pan.baidu.com/s/1ITFMd_myJBYI3zv1N9w_Aw 提取码:z7x8

0x01 准备工作

先导入四个静态页面导入 templates 文件夹下,静态资源放入 static 文件夹

image-20240706153708264

暂时手动模拟数据库

编写 pojo 层

员工表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.she11f.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
//员工表
@Data
@NoArgsConstructor
public class Employee {

private Integer id;
private String lastName;
private String email;
private Integer gender; //性别 0 女, 1,男
private Department department;
private Date birth;

public Employee(Integer id, String lastName, String email, Integer gender, Department department) {
this.id = id;
this.lastName = lastName;
this.email = email;
this.gender = gender;
this.department = department;
this.birth = new Date();
}
}

部门表

1
2
3
4
5
6
7
8
9
10
11
12
package com.she11f.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//部门表
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
private int id; //部门id
private String departmentName; //部门名字
}

添加lombok依赖

1
2
3
4
5
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

编写dao层

部门 dao

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

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

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

//部门dao
@Repository
public class DepartmentDao {

//模拟数据库中的数据

private static Map<Integer, Department>departments = null;

static {
departments = new HashMap<Integer, Department>(); //创建一个部门表

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

//获取所有的部门信息
public Collection<Department> getDepartments(){
return departments.values();
}
//通过id得到部门
public Department getDepartmentById(Integer id){
return departments.get(id);
}
}

员工dao

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

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

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

//员工dao
@Repository //被string托管
public class EmployeeDao {

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

employees.put(1001,new Employee( 1001,"AA","1622840727@qq.com",1,new Department(101,"教学部")));
employees.put(1002,new Employee( 1002,"BB","2622840727@qq.com",0,new Department(102,"市场部")));
employees.put(1003,new Employee( 1003,"CC","4622840727@qq.com",1,new Department(103,"教研部")));
employees.put(1004,new Employee( 1004,"DD","5628440727@qq.com",0,new Department(104,"运营部")));
employees.put(1005,new Employee( 1005,"FF","6022840727@qq.com",1,new Department(105,"后勤部")));
}
//主键自增
private static Integer ininId = 1006;
//增加一个员工
public void save(Employee employee){
if(employee.getId() == null){
employee.setId(ininId++);
}
employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));
employees.put(employee.getId(),employee);
}
//查询全部的员工
public Collection<Employee>getALL(){
return employees.values();
}

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

//删除一个员通过id
public void delete(Integer id){
employees.remove(id);
}
}


0x02 首页实现

引入Thymeleaf

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

编写 MyMvcConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.she11f.config;

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

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

用 thymeleaf 语法更改静态资源路径

所有的静态资源路径都需要使用thymeleaf接管:@{},th:href,th:src

1
2
<link href="asserts/css/bootstrap.min.css" rel="stylesheet">
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">

application.yml 修改

1
2
3
4
# 关闭模板引擎的缓存
spring:
thymeleaf:
cache=false:

启动程序,打开 localhost:8088,首页设置成功

image-20240706165443669

0x03 登录+拦截器

先给登陆页面表单提交写一个 controller,登录页先换成 thymeleaf 语法。

1
<form class="form-signin" th:action="@{/user/login}" method="post">

// 这里面的所有 input 标签都需要加上一个name属性,不然拦截器得不到参数

编写 MyMvcConfig

1
registry.addViewController("/main.html").setViewName("dashboard");

编写 LoginController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Controller
public class LoginController {
@RequestMapping("/user/login")
public String login(
@RequestParam("username") String username ,
@RequestParam("password") String password,
Model model){
//具体的业务
if(!StringUtils.isEmpty(username)&&"123456".equals(password)){
return "redirect:/main.html";
}
else{
//告诉用户,你登录失败
model.addAttribute("msg","用户名或者密码错误!");
return "index";
}
}
}

测试成功登录

image-20240707232735922

登录失败的话,我们需要将后台信息输出到前台,可以在首页标题下面加上判断

1
2
3
<!--判断是否显示,使用if, ${}可以使用工具类,可以看thymeleaf的中文文档--> 
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}">
</p>

image-20240707233157803

接着添加拦截器,在 LoginController 页面添加 session

1
session.setAttribute("loginUser",username);

在 config 下自定义一个拦截器 LoginHandlerInterceptor

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

import org.springframework.web.servlet.HandlerInterceptor;

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

//自定义拦截器
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取 loginUser 信息进行判断
Object user = request.getSession().getAttribute("loginUser");
if(user == null){//未登录,返回登录页面
request.setAttribute("msg","没有权限,请先登录");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
//登录,放行
return true;
}
}
}

然后将拦截器注册到我们的 SpringMVC 配置类当中!

1
2
3
4
5
6
7
8
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册拦截器,及拦截请求和要剔除哪些请求!
// 我们还需要过滤静态资源文件,否则样式显示不出来
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index.html","/user/login","/","/css/*","/img/**","/js/**");
}

我们然后在后台主页,获取用户登录的信息

1
2
<!--后台主页显示登录用户的信息-->
[[${session.loginUser}]] <!--$取EL表达式-->

0x04 员工列表展示

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

  2. 添加 a 链接跳转

    1
    <a class="nav-link" th:href="@{/emps}">员工管理</a>
  3. list 移动至 emp 文件夹下

    image-20240709161950884

  4. 编写处理请求的controller

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

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

import java.util.Collection;

//员工列表
@Controller
public class EmployeeController {

@Autowired
EmployeeDao employeeDao;

@RequestMapping("/emps")
public String list(Model model){
Collection<Employee> employees = employeeDao.getALL();
model.addAttribute("emps",employees);
return "emp/list";
}
}

image-20240709162627133

拿一下数据顺便美化一下页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<thead>
<tr>
<th>id</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>department</th>
<th>birth</th>
</tr>
</thead>
<tbody>
<tr th:each="emp:${emps}">
<td th:text="${emp.getId()}"></td>
<td th:text="${emp.getLastName()}"></td>
<td th:text="${emp.getEmail()}"></td>
<td th:text="${emp.getGender()==0?'女':'男'}"></td>
<td th:text="${emp.department.getDepartmentName()}"></td>
<td th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
<td>
<button class="btn btn-sm btn-primary">编辑</button>
<button class="btn btn-sm btn-danger">删除</button>
</td>
</tr>
</tbody>

image-20240709163106518

0x05 添加员工

先修改跳转链接

1
<h2><a class="btn btn-sm btn-success" th:href="@{/emp}">添加员工</a></h2>

在员工控制器里加一条规则

1
2
3
4
@RequestMapping("/emp")
public String toAddPage(){
return "emp/add";
}

编写 add.html,复制 list.html 然后把表单部分换进来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<form th:action="@{/emp}" method="post" >
<div class="form-group" ><label>LastName</label>
<input class="form-control" placeholder="she11F" type="text" name="lastName">
</div>
<div class="form-group" ><label>Email</label>
<input class="form-control" placeholder="2097688176@qq.com" type="email" name="email">
</div>
<div class="form-group"><label>Gender</label><br/>
<div class="form-check form-check-inline">
<input class="form-check-input" name="gender" type="radio" value="1">
<label class="form-check-label"></label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" name="gender" type="radio" value="0">
<label class="form-check-label"></label>
</div>
</div>
<div class="form-group" ><label>department</label>
<select class="form-control" name="department.id">
<option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>
</select>
</div>
<div class="form-group" >
<label >Birth</label>
<input class="form-control" placeholder="2024/7/10" type="text" name="birth">
</div>
<button class="btn btn-primary" type="submit">添加</button>
</form>

image-20240710094545493

编写一个/emp post 控制器来实现表单提交

1
2
3
4
5
6
7
8
9
10
//员工添加功能
//接收前端传递的参数,自动封装成为对象[要求前端传递的参数名,和属性名一致]
@PostMapping("/emp")
public String addEmp(Employee employee){
//保存员工的信息
System.out.println(employee);
employeeDao.save(employee);
// 回到员工列表页面,可以使用redirect或者forward,就不会被视图解析器解析
return "redirect:/emps";
}

添加成功

image-20240710095254069

0x06 修改员工信息

修改跳转链接的位置

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

编写跳转控制器

1
2
3
4
5
6
7
8
9
10
11
//员工修改页面
@GetMapping("/emp/{id}")
public String toUpdateEmp(@PathVariable("id") Integer id,Model model){
Employee employee = employeeDao.getEmployeeById(id);
model.addAttribute("emp",employee);

//查询所有的部门信息
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("departments",departments);
return "emp/update";
}

编写 update 页面,复制 add 页面,修改其表单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<form th:action="@{/emp}" method="post" >
<input type="hidden" name="id" th:value="${emp.getId()}">
<div class="form-group" ><label>LastName</label>
<input th:value="${emp.getLastName()}" class="form-control" placeholder="kuangshen" type="text" name="lastName">
</div>
<div class="form-group" ><label>Email</label>
<input th:value="${emp.getEmail()}" class="form-control" placeholder="24736743@qq.com" type="email" name="email">
</div>
<div class="form-group"><label>Gender</label><br/>
<div class="form-check form-check-inline">
<input th:checked="${emp.getGender()==1}" class="form-check-input" name="gender" type="radio" value="1">
<label class="form-check-label"></label>
</div>
<div class="form-check form-check-inline">
<input th:checked="${emp.getGender()==0}" class="form-check-input" name="gender" type="radio" value="0">
<label class="form-check-label"></label>
</div>
</div>
<div class="form-group" ><label>department</label>
<select class="form-control" name="department.id">
<option th:selected="${dept.id==emp.getDepartment().getId()}" th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>
</select>
</div>
<div class="form-group" >
<label >Birth</label>
<input th:value="${#dates.format(emp.birth,'yyyy-MM-dd HH:mm')}" class="form-control" placeholder="2021-02-02" type="text" name="birth">
</div>
<button class="btn btn-primary" type="submit">修改</button>
</form>

image-20240710103207241

修改成功

image-20240710103405590

0x07 删除员工以及404页面实现

编写跳转

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

编写控制器

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

测试,成功删除员工。

新建 error 文件夹,把 404.html 移进去即可,访问不存在的路由,返回我们的 4040 页面

image-20240710104713268