文章目录
7 使用SpringMVC完成RESTful的实现
7.1 什么是RESTful风格?
REST:Representational State Transfer,表现层资源状态转移。它就是一个资源定位、资源操作的风格。不是标准也不是协议,只是一种风格 。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
**资源的定义:**互联网所有的事物都可以被抽象为资源。
**状态转移:**在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。
资源操作:分为POST、DELETE、PUT、GET四种方法,使用不同方法对资源进行操作(增、删、改、查)
7.2 传统风格与RESTFul风格对比
7.2.1 使用传统风格操作资源
通过不同的参数来实现不同的效果!方法单一!
http://127.0.0.1/item/queryItem?id=1 (查询,GET)
http://127.0.0.1/item/saveItem (新增,POST)
http://127.0.0.1/item/updateItem (更新,POST)
http://127.0.0.1/item/deleteItem?id=1 (删除,GET或POST)
7.2.2 使用RESTful风格操作资源
可以通过不同的请求方式来实现不同的效果!
如下:请求地址一样,但是功能可以不同!
http://127.0.0.1/item/1 (查询,GET)
http://127.0.0.1/item (新增,POST)
http://127.0.0.1/item (更新,PUT)
http://127.0.0.1/item/1 (删除,DELETE)
7.3 HiddenHttpMethodFilter
由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?
SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为 DELETE 或 PUT 请求
HiddenHttpMethodFilter 处理put和delete请求的条件:
-
当前请求的请求方式必须为post(通过表单或者ajax来发送post请求)
-
当前请求必须传输请求参数_method
满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数_method的值,因此请求参数_method的值才是最终的请求方式
在web.xml中注册HiddenHttpMethodFilter
<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>
注:
目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和HiddenHttpMethodFilter
在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter
原因:
- 在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字符集的
- request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作
- 而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:
String paramValue = request.getParameter(this.methodParam);
7.4 RESTful案例
案例目标:和传统 CRUD 一样,实现对员工信息的增删改查。
7.4.1 准备工作
-
搭建一个新的项目
-
准备实体类
public class Employee { private Integer id; private String lastName; private String email; //1 male, 0 female private Integer 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; } public Employee(Integer id, String lastName, String email, Integer gender) { super(); this.id = id; this.lastName = lastName; this.email = email; this.gender = gender; } public Employee() { } }
-
准备dao模拟数据
import java.util.Collection; import java.util.HashMap; import java.util.Map; import com.zjw.mvc.bean.Employee; import org.springframework.stereotype.Repository; @Repository public class EmployeeDao { private static Map<Integer, Employee> employees = null; static{ employees = new HashMap<Integer, Employee>(); employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1)); employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1)); employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0)); employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0)); employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1)); } private static Integer initId = 1006; public void save(Employee employee){ //如果没有ID,则自动给它赋值 if(employee.getId() == null){ employee.setId(initId++); } employees.put(employee.getId(), employee); } public Collection<Employee> getAll(){ return employees.values(); } public Employee get(Integer id){ return employees.get(id); } public void delete(Integer id){ employees.remove(id); } }
7.4.2 功能清单
7.4.3 具体功能:访问首页
-
配置view-controller
<mvc:view-controller path="/" view-name="index"/>
-
创建页面
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" > <title>Title</title> </head> <body> <h1>首页</h1> <a th:href="@{/employee}">访问员工信息</a> </body> </html>
7.4.4 具体功能:查询所有员工数据
-
控制器方法
@RequestMapping(value = "/employee", method = RequestMethod.GET) public String getEmployeeList(Model model){ Collection<Employee> employeeList = employeeDao.getAll(); model.addAttribute("employeeList", employeeList); return "employee_list"; }
-
创建employee_list.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Employee Info</title> <script type="text/javascript" th:src="@{/static/js/vue.js}"></script> </head> <body> <table border="1" cellpadding="0" cellspacing="0" style="text-align: center;" id="dataTable"> <tr> <th colspan="5">Employee Info</th> </tr> <tr> <th>id</th> <th>lastName</th> <th>email</th> <th>gender</th> <th>options(<a th:href="@{/toAdd}">add</a>)</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}"></td> <td> <a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a> <a th:href="@{'/employee/'+${employee.id}}">update</a> </td> </tr> </table> </body> </html>
-
结果展示:
7.4.5 具体功能:删除
- 在
web.xml
中的编码处理器后引入HiddenHttpMethodFilter
<!--配置处理请求方式put和delete的HiddenHttpMethodFilter-->
<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>
-
创建处理delete请求方式的表单
<!-- 作用:通过超链接控制表单的提交,将post请求转换为delete请求 --> <form id="delete_form" method="post"> <!-- HiddenHttpMethodFilter要求:必须传输_method请求参数,并且值为最终的请求方式 --> <input type="hidden" name="_method" value="delete"/> </form>
-
删除超链接绑定点击事件
引入vue.js
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script>
删除超链接<a class="deleteA" @click="deleteEmployee" th:href="@{'/employee/'+${employee.id}}">delete</a>
通过vue处理点击事件
<script type="text/javascript"> var vue = new Vue({ el:"#dataTable", methods:{ //event表示当前事件 deleteEmployee:function (event) { //通过id获取表单标签 var delete_form = document.getElementById("delete_form"); //将触发事件的超链接的href属性为表单的action属性赋值 delete_form.action = event.target.href; //提交表单 delete_form.submit(); //阻止超链接的默认跳转行为 event.preventDefault(); } } }); </script>
-
控制器方法
@RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE) public String deleteEmployee(@PathVariable("id") Integer id){ employeeDao.delete(id); return "redirect:/employee"; }
7.4.6 具体功能:添加数据
-
配置view-controller
<mvc:view-controller path="/toAdd" view-name="employee_add"></mvc:view-controller>
-
创建添加用户页面employee_add.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Add Employee</title> </head> <body> <form th:action="@{/employee}" method="post"> lastName:<input type="text" name="lastName"><br> email:<input type="text" name="email"><br> gender:<input type="radio" name="gender" value="1">male <input type="radio" name="gender" value="0">female<br> <input type="submit" value="add"><br> </form> </body> </html>
-
控制器方法
@RequestMapping(value = "/employee", method = RequestMethod.POST) public String addEmployee(Employee employee){ employeeDao.save(employee); return "redirect:/employee"; }
7.4.7 具体功能:跳转到更新数据页面
- 修改超链接
<a th:href="@{'/employee/'+${employee.id}}">update</a>
- 控制器方法
@RequestMapping(value = "/employee/{id}", method = RequestMethod.GET)
public String getEmployeeById(@PathVariable("id") Integer id, Model model){
Employee employee = employeeDao.get(id);
model.addAttribute("employee", employee);
return "employee_update";
}
-
创建employee_update.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Update Employee</title> </head> <body> <form th:action="@{/employee}" method="post"> <input type="hidden" name="_method" value="put"> <input type="hidden" name="id" th:value="${employee.id}"> lastName:<input type="text" name="lastName" th:value="${employee.lastName}"><br> email:<input type="text" name="email" th:value="${employee.email}"><br> <!-- th:field="${employee.gender}"可用于单选框或复选框的回显 若单选框的value和employee.gender的值一致,则添加checked="checked"属性 --> gender:<input type="radio" name="gender" value="1" th:field="${employee.gender}">male <input type="radio" name="gender" value="0" th:field="${employee.gender}">female<br> <input type="submit" value="update"><br> </form> </body> </html>
7.4.8 执行更新
控制器方法
@RequestMapping(value = "/employee", method = RequestMethod.PUT)
public String updateEmployee(Employee employee){
employeeDao.save(employee);
return "redirect:/employee";
}
当然了对于处理指定请求方式的控制器方法,SpringMVC中提供了@RequestMapping的派生注解
处理get请求的映射–>@GetMapping
处理post请求的映射–>@PostMapping
处理put请求的映射–>@PutMapping
处理delete请求的映射–>@DeleteMapping