笔记来源:【尚硅谷】SpringMVC教程丨一套快速上手spring mvc

RESTful 案例

1、准备工作

Step1、创建工程

File-New-Project,默认Next

05-RESTful 案例 - 图1

填写项目工程基本信息,点击FINISH

05-RESTful 案例 - 图2

Step2、完善 POM

修改打包方式为war,并引入相关依赖

  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. <groupId>com.vectorx</groupId>
  7. <artifactId>SpringMVC_RESTful</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <packaging>war</packaging>
  10. <properties>
  11. <maven.compiler.source>8</maven.compiler.source>
  12. <maven.compiler.target>8</maven.compiler.target>
  13. </properties>
  14. <dependencies>
  15. <dependency>
  16. <groupId>org.springframework</groupId>
  17. <artifactId>spring-webmvc</artifactId>
  18. <version>5.3.16</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>ch.qos.logback</groupId>
  22. <artifactId>logback-classic</artifactId>
  23. <version>1.2.11</version>
  24. <scope>test</scope>
  25. </dependency>
  26. <dependency>
  27. <groupId>javax.servlet</groupId>
  28. <artifactId>javax.servlet-api</artifactId>
  29. <version>4.0.1</version>
  30. <scope>provided</scope>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.thymeleaf</groupId>
  34. <artifactId>thymeleaf-spring5</artifactId>
  35. <version>3.0.15.RELEASE</version>
  36. </dependency>
  37. </dependencies>
  38. </project>

Step3、web.xml

File-Project Structure-Modules,在Deployment Descriptors中点击+号添加Deployment Descriptor Location,默认路径中不带src\main\webapp\,需要手动添加

05-RESTful 案例 - 图3

web.xml中添加两个过滤器和一个前端控制器:

  • 编码过滤器:CharacterEncodingFilter(注意顺序)
  • 处理PUTDELETE的请求过滤器:HiddenHttpMethodFilter
  • 前端控制器:DispatcherServlet
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  5. version="4.0">
  6. <!--配置编码过滤器-->
  7. <filter>
  8. <filter-name>CharacterEncodingFilter</filter-name>
  9. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  10. <init-param>
  11. <param-name>encoding</param-name>
  12. <param-value>UTF-8</param-value>
  13. </init-param>
  14. <init-param>
  15. <param-name>forceResponseEncoding</param-name>
  16. <param-value>true</param-value>
  17. </init-param>
  18. </filter>
  19. <filter-mapping>
  20. <filter-name>CharacterEncodingFilter</filter-name>
  21. <url-pattern>/*</url-pattern>
  22. </filter-mapping>
  23. <!--配置处理 PUT 和 DELETE 的请求过滤器-->
  24. <filter>
  25. <filter-name>HiddenHttpMethodFilter</filter-name>
  26. <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  27. </filter>
  28. <filter-mapping>
  29. <filter-name>HiddenHttpMethodFilter</filter-name>
  30. <url-pattern>/*</url-pattern>
  31. </filter-mapping>
  32. <!--配置 SpringMVC 前端控制器-->
  33. <servlet>
  34. <servlet-name>DispatcherServlet</servlet-name>
  35. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  36. <init-param>
  37. <param-name>contextConfigLocation</param-name>
  38. <param-value>classpath:springMVC.xml</param-value>
  39. </init-param>
  40. <load-on-startup>1</load-on-startup>
  41. </servlet>
  42. <servlet-mapping>
  43. <servlet-name>DispatcherServlet</servlet-name>
  44. <url-pattern>/</url-pattern>
  45. </servlet-mapping>
  46. </web-app>

Step4、SpringMVC 配置文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:mvc="http://www.springframework.org/schema/mvc"
  6. 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">
  7. <!--自动扫描包-->
  8. <context:component-scan base-package="com.vectorx.restful"></context:component-scan>
  9. <!--配置Thymeleaf视图解析器-->
  10. <bean id="ThymeleafViewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
  11. <property name="order" value="1"></property>
  12. <property name="characterEncoding" value="UTF-8"></property>
  13. <property name="templateEngine">
  14. <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
  15. <property name="templateResolver">
  16. <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
  17. <property name="prefix" value="/WEB-INF/templates/"></property>
  18. <property name="suffix" value=".html"></property>
  19. <property name="templateMode" value="HTML5"></property>
  20. <property name="characterEncoding" value="UTF-8"></property>
  21. </bean>
  22. </property>
  23. </bean>
  24. </property>
  25. </bean>
  26. <!--配置视图控制器-->
  27. <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
  28. <!--配置MVC注解驱动-->
  29. <mvc:annotation-driven/>
  30. </beans>

Step5、创建 Controller、Dao、Bean

EmployeeController

  1. @Controller
  2. @RequestMapping("/employeeController")
  3. public class EmployeeController {
  4. @Autowired
  5. private EmployeeDao employeeDao;
  6. }

EmployeeDao

  1. public interface EmployeeDao {
  2. /**
  3. * 增改员工信息
  4. *
  5. * @param employee
  6. */
  7. void save(Employee employee);
  8. /**
  9. * 删除员工信息
  10. *
  11. * @param id
  12. */
  13. void deleteById(Integer id);
  14. /**
  15. * 获取所有员工信息
  16. *
  17. * @return
  18. */
  19. List<Employee> getAll();
  20. /**
  21. * 根据员工id获取员工信息
  22. *
  23. * @param id
  24. * @return
  25. */
  26. Employee getById(Integer id);
  27. }

EmployeeDaoImpl

  1. @Repository
  2. public class EmployeeDaoImpl implements EmployeeDao {
  3. private static Map<Integer, Employee> employeeMap;
  4. private static Integer initId = 1000;
  5. static {
  6. employeeMap = new HashMap<>();
  7. employeeMap.put(++initId, new Employee(initId, "张三", "zhangsan@qq.com", 1));
  8. employeeMap.put(++initId, new Employee(initId, "李四", "lisi@qq.com", 0));
  9. employeeMap.put(++initId, new Employee(initId, "王五", "wangwu@qq.com", 0));
  10. employeeMap.put(++initId, new Employee(initId, "赵六", "zhaoliu@qq.com", 1));
  11. }
  12. @Override
  13. public void save(Employee employee) {
  14. if (employee.getId() == null) {
  15. employee.setId(++initId);
  16. }
  17. employeeMap.put(employee.getId(), employee);
  18. }
  19. @Override
  20. public void deleteById(Integer id) {
  21. employeeMap.remove(id);
  22. }
  23. @Override
  24. public List<Employee> getAll() {
  25. return new ArrayList<>(employeeMap.values());
  26. }
  27. @Override
  28. public Employee getById(Integer id) {
  29. return employeeMap.get(id);
  30. }
  31. }

Employee

  1. public class Employee {
  2. private Integer id;
  3. private String lastName;
  4. private String email;
  5. private Integer gender;
  6. public Employee() {
  7. }
  8. public Employee(Integer id, String lastName, String email, Integer gender) {
  9. this.id = id;
  10. this.lastName = lastName;
  11. this.email = email;
  12. this.gender = gender;
  13. }
  14. public Integer getId() {
  15. return id;
  16. }
  17. public void setId(Integer id) {
  18. this.id = id;
  19. }
  20. public String getLastName() {
  21. return lastName;
  22. }
  23. public void setLastName(String lastName) {
  24. this.lastName = lastName;
  25. }
  26. public String getEmail() {
  27. return email;
  28. }
  29. public void setEmail(String email) {
  30. this.email = email;
  31. }
  32. public Integer getGender() {
  33. return gender;
  34. }
  35. public void setGender(Integer gender) {
  36. this.gender = gender;
  37. }
  38. @Override
  39. public String toString() {
  40. return "Employee{" +
  41. "id=" + id +
  42. ", lastName='" + lastName + '\'' +
  43. ", email='" + email + '\'' +
  44. ", gender='" + gender + '\'' +
  45. '}';
  46. }
  47. }

2、功能清单

功能 URL路径 请求方式
访问首页 / GET
查询所有员工 /employee GET
删除员工 /employee/1 DELETE
跳转到添加员工页面 /toAdd GET
添加员工 /employee POST
跳转到修改员工页面 /employee/2 GET
修改员工 /employee PUT

3、访问首页

index.html

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>首页</title>
  6. </head>
  7. <body>
  8. <h1>首页</h1>
  9. <a th:href="@{/employeeController/employee}">查看员工信息</a>
  10. </body>
  11. </html>

测试

05-RESTful 案例 - 图4

4、列表功能

EmployeeController.java

  1. @GetMapping("/employee")
  2. public String getAllEmployee(Model model) {
  3. List<Employee> employeeList = employeeDao.getAll();
  4. model.addAttribute("employeeList", employeeList);
  5. return "employeelist";
  6. }

employeelist.html

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>员工信息</title>
  6. <style type="text/css">
  7. table {
  8. width: 50%;
  9. border: 1px black solid;
  10. border-collapse: collapse;
  11. vertical-align: middle;
  12. text-align: center;
  13. }
  14. tbody tr:nth-child(odd) {
  15. background-color: rgb(211, 216, 188);
  16. }
  17. th, td {
  18. border: 1px black solid;
  19. }
  20. </style>
  21. </head>
  22. <body>
  23. <table>
  24. <tr>
  25. <th colspan="5">员工信息</th>
  26. </tr>
  27. <tr>
  28. <th>ID</th>
  29. <th>姓名</th>
  30. <th>邮箱</th>
  31. <th>性别</th>
  32. <th>操作</th>
  33. </tr>
  34. <tr th:each="employee : ${employeeList}">
  35. <td th:text="${employee.id}"></td>
  36. <td th:text="${employee.lastName}"></td>
  37. <td th:text="${employee.email}"></td>
  38. <td th:text="${employee.gender == 1 ? '男' : '女'}"></td>
  39. <td>
  40. <a href="">修改</a>
  41. <a href="">删除</a>
  42. </td>
  43. </tr>
  44. </table>
  45. </body>
  46. </html>

效果

05-RESTful 案例 - 图5

5、删除功能

webapp下新建static/cssstatic/js,用来放置css文件和js文件

  • 引入static/js/vue.js
  • static/css/employeelist.css作为外部样式文件
  • static/js/employeelist.js作为外部js文件

employeelist.html

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>员工信息</title>
  6. <link th:href="@{/static/css/employeelist.css}" rel="stylesheet" type="text/css"/>
  7. </head>
  8. <body>
  9. <table id="employeeTable">
  10. <tr>
  11. <th colspan="5">员工信息</th>
  12. </tr>
  13. <tr>
  14. <th>ID</th>
  15. <th>姓名</th>
  16. <th>邮箱</th>
  17. <th>性别</th>
  18. <th>操作</th>
  19. </tr>
  20. <tr th:each="employee : ${employeeList}">
  21. <td th:text="${employee.id}"></td>
  22. <td th:text="${employee.lastName}"></td>
  23. <td th:text="${employee.email}"></td>
  24. <td th:text="${employee.gender == 1 ? '男' : '女'}"></td>
  25. <td>
  26. <a href="">修改</a>
  27. <!--<a th:href="@{/employeeController/employee/}+${employee.id}">删除</a>-->
  28. <a @click="deleteEmployee" th:href="@{'/employeeController/employee/'+${employee.id}}">删除</a>
  29. </td>
  30. </tr>
  31. </table>
  32. <form method="post" id="deleteForm">
  33. <input type="hidden" name="_method" value="delete"/>
  34. </form>
  35. <script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
  36. <script type="text/javascript" th:src="@{/static/js/employeelist.js}"></script>
  37. </body>
  38. </html>

employeelist.css

  1. table {
  2. width: 50%;
  3. border: 1px black solid;
  4. border-collapse: collapse;
  5. /* 垂直水平居中 */
  6. vertical-align: middle;
  7. text-align: center;
  8. }
  9. /* 间隔变色 */
  10. tbody tr:nth-child(odd) {
  11. background-color: rgb(211, 216, 188);
  12. }
  13. th, td {
  14. border: 1px black solid;
  15. }

employeelist.js

  1. var vue = new Vue({
  2. el: "#employeeTable",
  3. methods: {
  4. deleteEmployee: function (event) {
  5. if (confirm('确认删除吗?')) {
  6. var deleteForm = document.getElementById("deleteForm");
  7. deleteForm.action = event.target.href;
  8. deleteForm.submit();
  9. }
  10. event.preventDefault();
  11. }
  12. }
  13. });

SpringMVC 配置文件

  1. <!--开放静态资源访问-->
  2. <mvc:default-servlet-handler/>

效果

05-RESTful 案例 - 图6

6、添加功能

employeelist.html

  1. <!-- 略 -->
  2. <tr>
  3. <th>ID</th>
  4. <th>姓名</th>
  5. <th>邮箱</th>
  6. <th>性别</th>
  7. <th>操作 <a th:href="@{/employeeController/toAdd}">添加</a><br/></th>
  8. </tr>
  9. <!-- 略 -->

employeeadd.html

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>添加员工</title>
  6. </head>
  7. <body>
  8. <h1>添加员工</h1>
  9. <form th:action="@{/employeeController/employee}" method="post">
  10. 姓名:<input type="text" name="lastName"/><br/>
  11. 邮箱:<input type="text" name="email"/><br/>
  12. 性别:<input type="radio" name="gender" value="1">
  13. <input type="radio" name="gender" value="0"><br/>
  14. <input type="submit" value="添加">
  15. </form>
  16. </body>
  17. </html>

EmployeeController.java

  1. @GetMapping("/toAdd")
  2. public String toAdd() {
  3. return "employeeadd";
  4. }
  5. @PostMapping("/employee")
  6. public String addEmployee(Employee employee) {
  7. employeeDao.save(employee);
  8. return "redirect:/employeeController/employee";
  9. }

效果

05-RESTful 案例 - 图7

7、修改功能

employeelist.html

  1. <!-- 略 -->
  2. <a th:href="@{/employeeController/employee/}+${employee.id}">修改</a>
  3. <!-- 略 -->

employeeedit.html

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>修改员工</title>
  6. </head>
  7. <body>
  8. <h1>修改员工</h1>
  9. <form th:action="@{/employeeController/employee}" method="post">
  10. <input type="hidden" name="_method" th:value="put">
  11. <input type="hidden" name="id" th:value="${employee.id}">
  12. 姓名:<input type="text" name="lastName" th:value="${employee.lastName}"/><br/>
  13. 邮箱:<input type="text" name="email" th:value="${employee.email}"/><br/>
  14. 性别:<input type="radio" name="gender" value="1" th:field="${employee.gender}">
  15. <input type="radio" name="gender" value="0" th:field="${employee.gender}"><br/>
  16. <input type="submit" value="修改">
  17. </form>
  18. </body>
  19. </html>

EmployeeController.java

  1. @GetMapping("/employee/{id}")
  2. public String getEmployeeById(@PathVariable("id") Integer id, Model model) {
  3. Employee employee = employeeDao.getById(id);
  4. model.addAttribute("employee", employee);
  5. return "employeeedit";
  6. }
  7. @PutMapping("/employee")
  8. public String editEmployee(Employee employee) {
  9. employeeDao.save(employee);
  10. return "redirect:/employeeController/employee";
  11. }

效果

05-RESTful 案例 - 图8

注意点

当前 SpringMVC 配置文件中存在这样几个配置

  1. <!--配置视图控制器-->
  2. <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
  3. <!--开放静态资源访问-->
  4. <mvc:default-servlet-handler/>
  5. <!--配置MVC注解驱动-->
  6. <mvc:annotation-driven/>

各个配置的作用

  • view-controller:简化页面跳转实现
  • default-servlet-handler:开放静态资源访问
  • annotation-driven:这里主要有 2 个作用

    • 1)解决因配置视图控制器导致其他请求失效(404)的问题
    • 2)解决因配置静态资源访问导致其他请求失效(404)的问题

回忆:在 04-SpringMVC 视图 - 5、视图控制器 view-controller 中有介绍过“MVC 注解驱动”功能作用

annotation-driven需要与view-controllerdefault-servlet-handler配合使用

annotation-drivenview-controller的关系

  • 当配置了view-controller而不配置annotation-driven,那么除了视图控制器中配置的请求,其他控制器方法将无法访问,即其他请求失效(404)
  • 当配置了view-controller也配置了annotation-driven,那么视图控制器中配置的请求和其他控制器方法都能够正常访问

annotation-drivendefault-servlet-handler的关系

  • 当配置了default-servlet-handler而不配置annotation-driven,那么所有请求都将交给DefaultServlet处理,DispatcherServlet将失效
  • 当配置了default-servlet-handler也配置了annotation-driven,那么所有请求将先交给DispatcherServlet处理,处理不了再交给DefaultServlet处理