准备工作
Step1、创建工程
File
-New
-Project
,默认Next
![](6-1-RESTful 案例/e4b675de2d65746504452b23ea0e6b4e.png)
填写项目工程基本信息,点击FINISH
![](6-1-RESTful 案例/8df7b0e8cc57760f56b7883a302a33a5.png)
Step2、完善 POM
修改打包方式为war
,并引入相关依赖
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
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.vectorx</groupId> <artifactId>SpringMVC_RESTful</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging>
<properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties>
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.16</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.11</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.thymeleaf</groupId> <artifactId>thymeleaf-spring5</artifactId> <version>3.0.15.RELEASE</version> </dependency> </dependencies> </project>
|
Step3、web.xml
File
-Project Structure
-Modules
,在Deployment Descriptors
中点击+
号添加Deployment Descriptor Location
,默认路径中不带src\main\webapp\
,需要手动添加
![](6-1-RESTful 案例/42a6e012a4ab56d9fe43e6eb26c4b971.png)
在web.xml
中添加两个过滤器和一个前端控制器:
- 编码过滤器:
CharacterEncodingFilter
(注意顺序)
- 处理
PUT
和DELETE
的请求过滤器:HiddenHttpMethodFilter
- 前端控制器:
DispatcherServlet
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
| <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<filter> <filter-name>HiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>HiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
<servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springMVC.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
|
Step4、SpringMVC 配置文件
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
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.vectorx.restful"></context:component-scan>
<bean id="ThymeleafViewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver"> <property name="order" value="1"></property> <property name="characterEncoding" value="UTF-8"></property> <property name="templateEngine"> <bean class="org.thymeleaf.spring5.SpringTemplateEngine"> <property name="templateResolver"> <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver"> <property name="prefix" value="/WEB-INF/templates/"></property> <property name="suffix" value=".html"></property> <property name="templateMode" value="HTML5"></property> <property name="characterEncoding" value="UTF-8"></property> </bean> </property> </bean> </property> </bean>
<mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<mvc:annotation-driven/> </beans>
|
Step5、创建 Controller、Dao、Bean
EmployeeController
1 2 3 4 5 6
| @Controller @RequestMapping("/employeeController") public class EmployeeController { @Autowired private EmployeeDao employeeDao; }
|
EmployeeDao
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
| public interface EmployeeDao {
void save(Employee employee);
void deleteById(Integer id);
List<Employee> getAll();
Employee getById(Integer id); }
|
EmployeeDaoImpl
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
| @Repository public class EmployeeDaoImpl implements EmployeeDao { private static Map<Integer, Employee> employeeMap; private static Integer initId = 1000;
static { employeeMap = new HashMap<>(); employeeMap.put(++initId, new Employee(initId, "张三", "zhangsan@qq.com", 1)); employeeMap.put(++initId, new Employee(initId, "李四", "lisi@qq.com", 0)); employeeMap.put(++initId, new Employee(initId, "王五", "wangwu@qq.com", 0)); employeeMap.put(++initId, new Employee(initId, "赵六", "zhaoliu@qq.com", 1)); }
@Override public void save(Employee employee) { if (employee.getId() == null) { employee.setId(++initId); } employeeMap.put(employee.getId(), employee); }
@Override public void deleteById(Integer id) { employeeMap.remove(id); }
@Override public List<Employee> getAll() { return new ArrayList<>(employeeMap.values()); }
@Override public Employee getById(Integer id) { return employeeMap.get(id); } }
|
Employee
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 57 58 59
| public class Employee { private Integer id; private String lastName; private String email; private Integer gender;
public Employee() { }
public Employee(Integer id, String lastName, String email, Integer gender) { this.id = id; this.lastName = lastName; this.email = email; this.gender = gender; }
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Integer getGender() { return gender; }
public void setGender(Integer gender) { this.gender = gender; }
@Override public String toString() { return "Employee{" + "id=" + id + ", lastName='" + lastName + '\'' + ", email='" + email + '\'' + ", gender='" + gender + '\'' + '}'; } }
|
功能清单
功能 |
URL路径 |
请求方式 |
访问首页 |
/ |
GET |
查询所有员工 |
/employee |
GET |
删除员工 |
/employee/1 |
DELETE |
跳转到添加员工页面 |
/toAdd |
GET |
添加员工 |
/employee |
POST |
跳转到修改员工页面 |
/employee/2 |
GET |
修改员工 |
/employee |
PUT |
访问首页
index.html
1 2 3 4 5 6 7 8 9 10 11
| <!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>首页</title> </head> <body> <h1>首页</h1> <a th:href="@{/employeeController/employee}">查看员工信息</a> </body> </html>
|
测试
![](6-1-RESTful 案例/87ba9f5c5fc77b8dec00e7e5fd860828.png)
列表功能
EmployeeController.java
1 2 3 4 5 6
| @GetMapping("/employee") public String getAllEmployee(Model model) { List<Employee> employeeList = employeeDao.getAll(); model.addAttribute("employeeList", employeeList); return "employeelist"; }
|
employeelist.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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| <!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>员工信息</title> <style type="text/css"> table { width: 50%; border: 1px black solid; border-collapse: collapse; vertical-align: middle; text-align: center; } tbody tr:nth-child(odd) { background-color: rgb(211, 216, 188); } th, td { border: 1px black solid; } </style> </head> <body> <table> <tr> <th colspan="5">员工信息</th> </tr> <tr> <th>ID</th> <th>姓名</th> <th>邮箱</th> <th>性别</th> <th>操作</th> </tr> <tr th:each="employee : ${employeeList}"> <td th:text="${employee.id}"></td> <td th:text="${employee.lastName}"></td> <td th:text="${employee.email}"></td> <td th:text="${employee.gender == 1 ? '男' : '女'}"></td> <td> <a href="">修改</a> <a href="">删除</a> </td> </tr> </table> </body> </html>
|
效果
![](6-1-RESTful 案例/46e6b9f63575fcd862294a53f1533a98.png)
删除功能
在webapp
下新建static/css
和static/js
,用来放置css
文件和js
文件
- 引入
static/js/vue.js
static/css/employeelist.css
作为外部样式文件
static/js/employeelist.js
作为外部js
文件
employeelist.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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| <!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>员工信息</title> <link th:href="@{/static/css/employeelist.css}" rel="stylesheet" type="text/css" /> </head> <body> <table id="employeeTable"> <tr> <th colspan="5">员工信息</th> </tr> <tr> <th>ID</th> <th>姓名</th> <th>邮箱</th> <th>性别</th> <th>操作</th> </tr> <tr th:each="employee : ${employeeList}"> <td th:text="${employee.id}"></td> <td th:text="${employee.lastName}"></td> <td th:text="${employee.email}"></td> <td th:text="${employee.gender == 1 ? '男' : '女'}"></td> <td> <a href="">修改</a> <a @click="deleteEmployee" th:href="@{'/employeeController/employee/'+${employee.id}}" >删除</a > </td> </tr> </table> <form method="post" id="deleteForm"> <input type="hidden" name="_method" value="delete" /> </form> <script type="text/javascript" th:src="@{/static/js/vue.js}"></script> <script type="text/javascript" th:src="@{/static/js/employeelist.js}" ></script> </body> </html>
|
employeelist.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| table { width: 50%; border: 1px black solid; border-collapse: collapse; vertical-align: middle; text-align: center; }
tbody tr:nth-child(odd) { background-color: rgb(211, 216, 188); }
th, td { border: 1px black solid; }
|
employeelist.js
1 2 3 4 5 6 7 8 9 10 11 12 13
| var vue = new Vue({ el: "#employeeTable", methods: { deleteEmployee: function (event) { if (confirm("确认删除吗?")) { var deleteForm = document.getElementById("deleteForm"); deleteForm.action = event.target.href; deleteForm.submit(); } event.preventDefault(); }, }, });
|
SpringMVC 配置文件
1 2
| <mvc:default-servlet-handler/>
|
效果
![](6-1-RESTful 案例/7cf392da7ac1f75a384239340f2c9dbb.gif)
添加功能
employeelist.html
1 2 3 4 5 6 7 8 9
| <tr> <th>ID</th> <th>姓名</th> <th>邮箱</th> <th>性别</th> <th>操作 <a th:href="@{/employeeController/toAdd}">添加</a><br /></th> </tr>
|
employeeadd.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>添加员工</title> </head> <body> <h1>添加员工</h1> <form th:action="@{/employeeController/employee}" method="post"> 姓名:<input type="text" name="lastName" /><br /> 邮箱:<input type="text" name="email" /><br /> 性别:<input type="radio" name="gender" value="1" />男 <input type="radio" name="gender" value="0" />女<br /> <input type="submit" value="添加" /> </form> </body> </html>
|
EmployeeController.java
1 2 3 4 5 6 7 8 9 10
| @GetMapping("/toAdd") public String toAdd() { return "employeeadd"; }
@PostMapping("/employee") public String addEmployee(Employee employee) { employeeDao.save(employee); return "redirect:/employeeController/employee"; }
|
效果
![](6-1-RESTful 案例/c5479d3fe399543dafd340fe12efd030.gif)
修改功能
employeelist.html
1 2 3
| <a th:href="@{/employeeController/employee/}+${employee.id}">修改</a>
|
employeeedit.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 29 30 31 32 33 34 35 36 37
| <!doctype html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>修改员工</title> </head> <body> <h1>修改员工</h1> <form th:action="@{/employeeController/employee}" method="post"> <input type="hidden" name="_method" th:value="put" /> <input type="hidden" name="id" th:value="${employee.id}" /> 姓名:<input type="text" name="lastName" th:value="${employee.lastName}" /><br /> 邮箱:<input type="text" name="email" th:value="${employee.email}" /><br /> 性别:<input type="radio" name="gender" value="1" th:field="${employee.gender}" />男 <input type="radio" name="gender" value="0" th:field="${employee.gender}" />女<br /> <input type="submit" value="修改" /> </form> </body> </html>
|
EmployeeController.java
1 2 3 4 5 6 7 8 9 10 11 12
| @GetMapping("/employee/{id}") public String getEmployeeById(@PathVariable("id") Integer id, Model model) { Employee employee = employeeDao.getById(id); model.addAttribute("employee", employee); return "employeeedit"; }
@PutMapping("/employee") public String editEmployee(Employee employee) { employeeDao.save(employee); return "redirect:/employeeController/employee"; }
|
效果
![](6-1-RESTful 案例/339f7bd6ceff0c9cb831b0fedf1daaec.gif)
注意点
当前 SpringMVC 配置文件中存在这样几个配置
1 2 3 4 5 6 7 8
| <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
<mvc:default-servlet-handler/>
<mvc:annotation-driven/>
|
各个配置的作用
回忆:在 04-SpringMVC 视图 - 5、视图控制器 view-controller 中有介绍过“MVC 注解驱动”功能作用
annotation-driven
需要与view-controller
、default-servlet-handler
配合使用
annotation-driven
与view-controller
的关系
- 当配置了
view-controller
而不配置annotation-driven
,那么除了视图控制器中配置的请求,其他控制器方法将无法访问,即其他请求失效(404)
- 当配置了
view-controller
也配置了annotation-driven
,那么视图控制器中配置的请求和其他控制器方法都能够正常访问
annotation-driven
与default-servlet-handler
的关系
- 当配置了
default-servlet-handler
而不配置annotation-driven
,那么所有请求都将交给DefaultServlet
处理,DispatcherServlet
将失效
- 当配置了
default-servlet-handler
也配置了annotation-driven
,那么所有请求将先交给DispatcherServlet
处理,处理不了再交给DefaultServlet
处理