【SpringMVC】(二)RESTFul
RESTFul
RestFul简介
REST:Representational State Transfer,表现层资源状态转移
资源:资源是一种看待服务器的方式
资源的表述:资源的表述是资源在某个特定时刻的状态的描述。可以在客户端-服务器端之间转移、交换。
状态转移:在客户端和服务器端之间转移(transfer)代表资源状态的描述,通过转移和操作资源的表述,来间接实现操作资源的目的。
说人话就是统一资源相同但操作不同的请求的请求路径,如getUserById和DeleteUserByName都设置资源路径为User
即:相同的请求路径、不同的请求方式表示不同的操作
RESTFul的实现
在Http协议中四个表示操作方式的动词:GET、Post、Put、Delete
传统方式 | RESTFul方式 | |
---|---|---|
查询 | findAllUser | /user get |
id查询 | getUserById?id=1 | /user/1 get |
添加 | saveUser | /user post |
修改 | updateUser | /user put |
删除 | deleteUser | /user delete |
Get和Post请求模拟
@RequestMapping(value = "/user", method = RequestMethod.GET) public String getAllUser() { System.out.println("查询所有用户信息"); return "success"; } @RequestMapping(value = "/user/{id}", method = RequestMethod.GET) public String getUserById(@PathVariable("id") Integer id) { System.out.println("根据id" + String.valueOf(id) +"查询所有用户信息"); return "success"; } @RequestMapping(value = "/user", method = RequestMethod.POST) public String addUser(@RequestParam("username") String username, @RequestParam("password") String password) { System.out.println("添加用户信息:" + username + "," + password); return "success"; }
<a th:href="@{/user}">查询所有用户信息</a><br> <a th:href="@{/user/1}">查询id为1的用户信息</a><br> <form th:action="@{/user}" method="post"> UserName:<input type="text"name="username" value="宇多田光"><br> Password:<input type="password"name="password" value="admin123"><br> <input type="submit"><br> </form>
Put和Delete请求模拟:使用HiddenHttpMethodFilter过滤器转换请求方式
form表单中的method方法设置为Post或者Delete是不起作用的,可以通过过滤器替换request请求的方法实现Put和Delete
<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>
根据源码,实现请求方式转换需要有两个条件:
①请求方式为post
②必须传输一个name为_method值为put或者delete的请求参数
<form th:action="@{/user}" method="post"> <input type="hidden" name="_method" value="put"> UserName:<input type="text"name="username" value="宇多田光"><br> Password:<input type="password"name="password" value="admin123"><br> <input type="submit"><br>
console:
修改用户信息:宇多田光,admin123
※HiddenHttpMethodFilter请求方式转换过滤器和CharacterEncodingFilter编码过滤器的顺序
CharacterEncodingFilter过滤器设置编码的前提条件是在此之前不能获取任何的请求参数,而HiddenHttpMethodFilter获取了name为_method的请求参数,因此CharacterEncodingFilter的< Filter-mapping > 要放在HiddenMethodFilter之前
RESTFull风格案例
通过请求方式实现Employee的增删改查
RESTFul方式 | |
---|---|
查询 | /employee get |
id查询 | /employee/1 get |
添加 | /employee post |
修改 | /employee put |
删除 | /employee/1 delete |
employee_list.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table id="dataTable" border="1" cellspacing="0" cellpadding="0" style="text-align: center"> <tr> <th colspan="5">Employee Information</th> </tr> <tr> <td>Id</td> <td>LastName</td> <td>Email</td> <td>Gender</td> <td>Option</td> </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 @click="deleteEmployee" th:href="@{/employee/} + ${employee.id}">delete</a> <a th:href="@{/employee/} + ${employee.id}">update</a> </td> </tr> </table> <form method="post" id="deleteForm"> <input name="_method" type="hidden" value="delete"> </form> <a th:href="@{/add}">添加</a> <script type="text/javascript" th:src="@{/static/js/vue.js}"></script> <script type="text/javascript"> var vue = new Vue({ el: "#dataTable", methods:{ deleteEmployee:function (event) { console.log("HELLO") var deleteFrom = document.getElementById("deleteForm"); //将触发点事件的href属性赋值给deleteform表单的action deleteFrom.action = event.target.href; //表单提交 deleteFrom.submit(); //取消超链接的默认行为 event.preventDefault(); } } }); </script> </body> </html>
显示操作:
/employee(请求) (GET) --> getAllEmploye(控制器方法) --> employee_list(前端页面)
@RequestMapping(value = "/employee", method = RequestMethod.GET) public String getAllEmployee(Model model) { Collection<Employee> employeelist = employeeDao.getAll(); model.addAttribute("employeelist", employeelist); return "employee_list"; }
①首先通过在SpringMVC.xml配置文件设置视图控制器实现/employee请求和getAllEmploye控制器方法的映射
②通过DAO获取employeelist并将其添加到request域中
③通过ThymeLeaf视图转发到前端页面employee_list.html
④在前端页面通过ThymeLeaf获取request域中的employeelist并渲染显示
删除操作:
/employee/{id} (DELETE) --> DeleteEmployeeById --> "redirect:/employee"
@RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE) public String DeleteEmployeeById(@PathVariable("id") Integer id) { employeeDao.delete(id); return "redirect:/employee"; }
①这里前端页面的删除是一个超链接,其内容经过Thymeleaf渲染后为 /employyee/1的形式而超链接默认只能通过get发送请求,因此直接点击会被当成“根据ID进行查询”的操作
<a @click="deleteEmployee" th:href="@{/employee/} + ${employee.id}">delete</a>
解决办法是使用Vue,通过给超链接添加一个点击事件,当用户点击时将点击事件的请求地址(/employyee/1)赋值给一个带有隐藏域的form表单的action,提交表单并且禁用点击事件的默认行为,最终服务器的过滤器组件HiddenHttpMethodFilter会将表单的post请求更改为delete请求。
转换请求方式用的deleteForm表单
<form method="post" id="deleteForm"> <input name="_method" type="hidden" value="delete"> </form>
Vue实现转移事件
<script type="text/javascript" th:src="@{/static/js/vue.js}"></script> <script type="text/javascript"> var vue = new Vue({ el: "#dataTable", methods:{ deleteEmployee:function (event) { console.log("HELLO") var deleteFrom = document.getElementById("deleteForm"); //将触发点事件的href属性赋值给deleteform表单的action deleteFrom.action = event.target.href; //表单提交 deleteFrom.submit(); //取消超链接的默认行为 event.preventDefault(); } } }); </script>
如此一来就得到了一个请求路径为"/employee/1",请求方式为"Delete"的request
③通过DAO实现根据id删除
④重定向到/employee请求,这里使用转发"employee_list"到前端页面的话,request是没有页面需要的内容的,因此需要重定向到请求/employee,经控制器方法向请求域添加employeelist才能使前端获取到数据
根据Id查询+修改操作
/employee/{id} (GET) --> toUpdateEmployee --> "employee_update"
/employee (POST-->PUT) --> UpdateEmployee --> "redirect:/employee"
①通过前端超链接点击的GET方式的请求,经ThymeLeaf渲染的请求路径为 /employee/id,然后经控制器方法toUpdateEmployee通过DAO根据id获取到Employee对象,然后向request域中添加此对象转发至前端页面employee_update
<a th:href="@{/employee/} + ${employee.id}">update</a>
@RequestMapping(value = "/employee/{id}", method = RequestMethod.GET) public String toUpdateEmployee(Model model, @PathVariable("id") Integer id) { Employee employee = employeeDao.get(id); model.addAttribute("employee", employee); return "employee_update"; }
②前端页面employee_update根据request域中的内容通过ThymeLeaf进行渲染回显
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div style="border: cornflowerblue 1px solid"> <form th:action="@{/employee}" method="post"> <input type="hidden" name="_method" value="put"> 编号:<input type="text" name="id" th:value="${employee.id}"><br> 姓名:<input type="text" name="lastName" th:value="${employee.lastName}"><br> 邮箱:<input type="text" name="email" th:value="${employee.email}"><br> 性别:<input type="text" name="gender" th:value="${employee.gender}"><br> <input type="submit" value="修改"> </form> </div> </body> </html>
③employee_update表单提交请求地址为 /employee请求方式为POST的request请求,因表单含有"_mothod"隐藏域,因此会服务器过滤器修改请求方式为PUT
④该请求会被被控制器方法UpdateEmployee匹配,经DAO修改后重定向到/employee请求
@RequestMapping(value = "/employee", method = RequestMethod.PUT) public String UpdateEmployee(Employee employee) { employeeDao.save(employee); return "redirect:/employee"; }
添加操作(略)
employee_list.html
<a th:href="@{/add}">添加</a>
springMVC.xml
<mvc:view-controller path="/add" 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>Title</title> </head> <body> <div style="border: cornflowerblue 1px solid"> <form th:action="@{/employee}" method="post"> 编号:<input type="text" name="id"><br> 姓名:<input type="text" name="lastName" value="宇多田光"><br> 邮箱:<input type="text" name="email" value="hikaru@163.com"><br> 性别:<input type="text" name="gender" value="1"><br> <input type="submit" value="添加"> </form> </div> </body> </html>
AddEmployee()
@RequestMapping(value = "/employee", method = RequestMethod.POST) public String AddEmployee(Employee employee) { employeeDao.save(employee); return "redirect:/employee"; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库