SpringMVC系列四: Rest-优雅的url请求风格

Rest请求

  • 💞Rest基本介绍
  • 💞Rest风格的url-完成增删改查
    • 需求说明
    • 代码实现
    • HiddenHttpMethodFilter机制
    • 注意事项和细节
  • 💞课后作业

上一讲, 我们学习的是SpringMVC系列三: Postman(接口测试工具)

现在打开springmvc项目

在这里插入图片描述

💞Rest基本介绍

●说明

1.REST:Representational State Transfer. (资源)表现层状态转化. 是目前流行的请求方式. 它结构清晰, 很多网站使用.
2.HTTP协议里面, 四个表示操作方式的动词: GET, POST, PUT, DELETE, 它们分别对应四种基本操作: GET用来获取资源, POST用来新建资源, PUT用来更新资源, DELETE用来删除资源
3.实例. 传统的请求方法:
getBook?id=1 GET
delete?id=1 GET
update POST
add POST
4.说明: 传统的url是通过参数来说明crud的类型, rest是通过get/post/put/delete来说明crud的类型

REST的核心过滤器
1.当前的浏览器只支持post/get请求, 因此为了得到put/delete的请求方式需要使用Spring提供的HiddenHttpMethodFilter过滤器进行转换.
2.HiddenHttpMethodFilter:浏览器form表单只支持GETPOST请求, 而DELETE, PUTmethod并不支持, Spring添加了一个过滤器, 可以将这些请求转换为标准的http方法, 使得支持GET, POST, PUTDELETE请求.
3.HiddenHttpMethodFilter只能对post请求方式进行转换.
4.这个过滤器需要在web.xml中配置

💞Rest风格的url-完成增删改查

需求说明

小明去书店买书, 完成购买书籍的增删改查

代码实现

1.修改web.xml, 配置HiddenHttpMethodFilter

<!--配置HiddenHttpMethodFilter
1.作用是 把 以post方式提交的delete和put请求, 进行转换
2.配置url-pattern 是 /* 表示请求都经过 hiddenHttpMethodFilter的过滤
3.后面通过debug源码, 会看的很清楚.
-->
<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>

2.修改springDispatcherServlet-serlvet.xml 添加配置

<!--加入两个常规配置-->
<!--支持SpringMVC的高级功能, 比如JSR303校验, 映射动态请求-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--将springmvc不能处理的请求, 交给tomcat处理, 比如css, js-->
<mvc:default-servlet-handler/>

3.在web路径下创建rest.jsp, 注意引入jquery, 测试查询/添加/删除/修改

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>rest测试</title>
</head>
<body>
<h3>Rest风格的crud操作案例</h3>
<br/><hr>
<h3>rest风格的url 查询书籍[get]</h3>
<a href="?">点击查询书籍</a>
<br/><hr>
<h3>rest风格的url 添加书籍[post]</h3>
<form action="?" method="?">name:<input name="bookName" type="text"/><br/><input type="submit" value="添加书籍">
</form>
<br/><hr>
<h3>rest风格的url 删除一本书</h3>
<a href="?" id="?">删除指定id的书</a>
<br/><hr>
<h3>rest风格的url 修改书籍[put]</h3>
<form action="?"><input type="submit" value="修改书籍">
</form>
</body>
</html>

4.在com.zzw.web.rest下, 创建BookHandler.java

1.完成查询

 //BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {//查询[GET]@GetMapping(value = "/book/{id}")public String getBook(@PathVariable("id") String id) {System.out.println("查询书籍 id=" + id);return "success";}
}

5.前端修改请求地址

<h3>rest风格的url 查询书籍[get]</h3>
<a href="user/book/200">点击查询书籍</a>

2.完成添加
@PostMapping(value = "/book") @GetMapping(value = "/book/{id}")不重复

//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {//查询[GET]@GetMapping(value = "/book/{id}")public String getBook(@PathVariable("id") String id) {System.out.println("查询书籍 id=" + id);return "success";}//添加[POST]@PostMapping(value = "/book")public String addBook(String bookName) {System.out.println("添加书籍 bookName=" + bookName);return "success";}
}

前端修改请求地址

<h3>rest风格的url 添加书籍[post]</h3>
<form action="user/book" method="post">name:<input name="bookName" type="text"/><br/><input type="submit" value="添加书籍">
</form>

3.完成删除

//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {//查询[GET]@GetMapping(value = "/book/{id}")public String getBook(@PathVariable("id") String id) {System.out.println("查询书籍 id=" + id);return "success";}//添加[POST]@PostMapping(value = "/book")public String addBook(String bookName) {System.out.println("添加书籍 bookName=" + bookName);return "success";}//删除[DELETE]@RequestMapping(value = "/book/{id}", method = RequestMethod.DELETE)public String deleteBook(@PathVariable("id") String id) {System.out.println("删除书籍 id=" + id);//return "success";//[如果这样写会报错 JSP 只允许 GET、POST 或 HEAD]//解读//1. redirect:/user/success重定向//2. 会被解析成 /工程路径/user/successreturn "redirect:/user/success";//提示: 重定向不能重定向到WEB-INF下的资源, 所以需要借助successGeneral方法}//如果请求时 /user/success, 就转发到 success.jsp//successGeneral 对应的url http://localhost:8080/springmvc/user/success@RequestMapping(value = "/success")public String successGeneral() {return "success";//由该方法 转发到success.jsp页面}
}

知识点:
1.web路径/script目录下存放jquery文件, jquery复习

2.为什么前端做了一个操作后, 就可以被过滤器过滤处理, 定位到后端delete方法? 回答: HiddenHttpMethodFilter机制

3.return “success”; 会报以下错误, JSP只允许GET,POST或HEAD
在这里插入图片描述


前端修改 this是dom对象

<head><title>rest测试</title><%--script标签建议放在head内--引入jquery--%><script type="text/javascript" src="script/jquery-3.6.0.min.js"></script><script type="text/javascript">$(function () {//当页面加载完成后就执行// alert("ok...");//给删除超链接绑定一个点击事件$("#deleteBook").click(function () {// alert("点击....");//我们自己定义一个提交的行为$("#hiddenForm").attr("action", this.href);$("input:hidden").val("DELETE");$("#hiddenForm").submit();return false;//改变点击超链接的行为, 不再提交})});</script>
</head>
<body>
<h3>rest风格的url 删除一本书</h3>
<%--解读1. 默认情况下, <a href="user/book/600">删除指定id的书</a> 是get请求2. 怎么样将 get 请求转成 springmvc 可以识别的 delete 请求, 就要考虑HiddenHttpMethodFilterpublic static final String DEFAULT_METHOD_PARAM = "_method";-------------------------------------------------------------------------------------------------------------if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {String paramValue = request.getParameter(this.methodParam);if (StringUtils.hasLength(paramValue)) {String method = paramValue.toUpperCase(Locale.ENGLISH);if (ALLOWED_METHODS.contains(method)) {requestToUse = new HttpMethodRequestWrapper(request, method);}}}-------------------------------------------------------------------------------------------------------------private static final List<String> ALLOWED_METHODS =Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));3. 从上面代码可以看到 HiddenHttpMethodFilter 过滤器可以对以Post方式提交的delete, put, patch进行转换, 转换称springmvc可以识别的 RequestMethod.DELETE / RequestMethod.PUT...4. 我们需要将 get <a href="user/book/600">删除指定id的书</a> 以 post方式提交给后端handler, 这样过滤器才会生效5. 我们可以通过jquery来处理--引入jquery
--%>
<a href="user/book/600" id="deleteBook">删除指定id的书</a>
<form action="" method="post" id="hiddenForm"><input type="hidden" name="_method"/>
</form>
</body>

4.完成修改

//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {//修改[PUT]@PutMapping(value = "/book/{id}")public String updateBook(@PathVariable("id") String id) {System.out.println("修改书籍 id=" + id);return "redirect:/user/success";}
}

前端修改请求代码

<h3>rest风格的url 修改书籍[put]</h3>
<form action="user/book/666" method="post"><input type="button" name="_method" value="PUT"/><input type="submit" value="修改书籍"/>
</form>

HiddenHttpMethodFilter机制

打断点, 进行debug
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意事项和细节

1.HiddenHttpMethodFilter, 在将post转成delete / put请求时, 是按_method参数名 来读取的
2.如果web项目是运行在Tomcat8及以上, 会发现被过滤成DELETEPUT请求, 到达控制器时能顺利执行, 但是返回时(forward)会报HTTP 405的错误提示: JSP 只允许 GET、POST 或 HEAD

  1. 解决方式1: 使用Tomcat7
  2. 解决方式2: 将请求转发(forward)改为请求重定向(redirect): 重定向到一个Handler, 由Handler转发到页面
    在这里插入图片描述

3.页面测试时, 如果出现点击修改书籍, 仍然走的是删除url, 是因为浏览器原因(缓存等原因).

💞课后作业

需求说明
小王去商超买衣服, 完成购买衣服的增删改查

1.在web路径下创建restBuyClothes.jsp, 注意引入jquery, 测试查询/添加/删除/修改

<head><title>购买衣服</title><%--引入jquery--%><script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
</head>
<body>
<h3>rest风格的url 挑选衣服[get]</h3>
<a href="?">点击挑选衣服</a>
<br/><hr>
<h3>rest风格的url 添加衣服[post]</h3>
<a href="?">点击添加衣服</a>
<form action="?" method="post">clothes: <input name="clothes" type="text"><br/><input type="submit" value="添加衣服">
</form>
<br/><hr>
<h3>rest风格的url 删除一件衣服[delete]</h3>
<a href="?" id="deleteClothes">删除一件衣服</a>
<form action="" method="post" id="deleteForm"><input type="hidden" name="_method"/>
</form>
<br/><hr>
<h3>rest风格的url 修改衣服[get]</h3>
<form action="?" method="post"><input type="hidden" name="_method">
</form>
</body>

2.在com.zzw.web.rest下, 创建ClothesHandler.java

1.完成查询
@PostMapping(value = "/clothes") @GetMapping(value = "/clothes/{brand}")不重复

@RequestMapping(value = "/user")//处理Rest风格的请求 增删改查
@Controller
public class ClothesHandler {//挑选[GET]@GetMapping(value = "/clothes/{brand}")public String queryClothes(@PathVariable("brand") String brand) {System.out.println("挑选衣服 brand=" + brand);return "success";}
}

.前端修改请求

<h3>rest风格的url 挑选衣服[get]</h3>
<a href="user/clothes/阿迪达斯">点击挑选衣服</a>

2.完成添加

@RequestMapping(value = "/user")
@Controller
public class ClothesHandler {//演示Rest风格的请求//挑选[GET]@GetMapping(value = "/clothes/{brand}")public String queryClothes(@PathVariable("brand") String brand) {System.out.println("挑选衣服 brand=" + brand);return "success";}//添加[POST]@PostMapping(value = "/clothes")public String addClothes(String brand) {System.out.println("添加衣服 brand=" + brand);return "success";}
}

.前端修改请求

<h3>rest风格的url 添加衣服[post]</h3>
<form action="user/clothes" method="post">clothes: <input name="brand" type="text"><br/><input type="submit" value="添加衣服">
</form>

3.完成删除

@RequestMapping(value = "/user")
@Controller
public class ClothesHandler {//演示Rest风格的请求//挑选[GET]@GetMapping(value = "/clothes/{brand}")public String queryClothes(@PathVariable("brand") String brand) {System.out.println("挑选衣服 brand=" + brand);return "success";}//添加[POST]@PostMapping(value = "/clothes")public String addClothes(String brand) {System.out.println("添加衣服 brand=" + brand);//return "success";return "redirect:/user/success";}@RequestMapping(value = "/success2")public String successGeneral() {return "success";}
}

.前端修改请求

<head><title>购买衣服</title><%--引入jquery--%><script type="text/javascript" src="script/jquery-3.6.0.min.js"></script><script type="text/javascript">$(function () {// alert("123");$("#deleteClothes").click(function () {// alert("ok..");$("#deleteForm")[0].action = this.href;$("input:hidden")[0].value = "DELETE";$("#deleteForm").submit();return false;})})</script>
</head>
<body>
<h3>rest风格的url 删除一件衣服[delete]</h3>
<a href="user/clothes/361" id="deleteClothes">删除一件衣服</a>
<form action="" method="post" id="deleteForm"><input type="hidden" name="_method"/>
</form>
</body>

4.完成修改

@RequestMapping(value = "/user")
@Controller
public class ClothesHandler {//演示Rest风格的请求//挑选[GET]@GetMapping(value = "/clothes/{brand}")public String queryClothes(@PathVariable("brand") String brand) {System.out.println("挑选衣服 brand=" + brand);return "success";}//添加[POST]@PostMapping(value = "/clothes")public String addClothes(String brand) {System.out.println("添加衣服 brand=" + brand);//return "success";return "redirect:/user/success";}@RequestMapping(value = "/success2")public String successGeneral() {return "success";}//修改[PUT]@PutMapping(value = "/clothes/{brand}")public String updateClothes(@PathVariable("brand") String brand) {System.out.println("修改衣服 brand=" + brand);return "redirect:/user/success2";}
}

.前端修改请求

<body>
<h3>rest风格的url 修改衣服[get]</h3>
<form action="user/clothes/李宁" method="post"><input type="hidden" name="_method" value="PUT"><input type="submit" value="修改衣服"/>
</form>
</body>

在这里插入图片描述

下一讲, 我们学习 SpringMVC系列五: SpringMVC映射请求数据

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/29768.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Spark3.3.4版本,实现Standalone 模式高可用集群部署

目录 一、环境描述 二、部署Spark 节点 2.1 下载资源包 2.2 解压 2.3 配置 2.3.1 配置环境变量 2.3.2 修改workers配置文件 2.3.3 修改spark.env.sh文件 2.3.4 修改spark-defaults.conf 2.4 分发 2.5 启动服务 2.5.1 启动zookeeper 2.5.2 启动hdfs 2.5.3 启动spar…

归并排序 (递归实+非递归)

前言 归并排序是一种逻辑很简单&#xff0c;但是实现有点难度的排序&#xff0c;尤其是非递归&#xff0c;对于区间的把握更是需要一点逻辑的推导&#xff0c;但是没有关系&#xff0c;轻松拿捏 归并排序gif 归并排序单趟实现 1&#xff0c;创建tmp数组&#xff0c; 2&#xff…

javaWeb项目-在线考试系统详细功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、Java简介 Java语…

「Qt Widget中文示例指南」如何实现一个滑动条(一)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 滑动条示例展示了如…

轻轻松松上手的LangChain学习说明书

本文为笔者学习LangChain时对官方文档以及一系列资料进行一些总结&#xff5e;覆盖对Langchain的核心六大模块的理解与核心使用方法&#xff0c;全文篇幅较长&#xff0c;共计50000字&#xff0c;可先码住辅助用于学习Langchain。 一、Langchain是什么&#xff1f; 如今各类AI…

昇思25天学习打卡营第1天|快速入门

学AI还能赢奖品&#xff1f;每天30分钟&#xff0c;25天打通AI任督二脉 (qq.com) 本节通过MindSpore的API来快速实现一个简单的深度学习模型。若想要深入了解MindSpore的使用方法&#xff0c;请参阅各节最后提供的参考链接。 import mindspore from mindspore import nn from …

项目训练营第一天

项目训练营第一天 springboot后端环境搭建 1、首先需要找文章下载好tomcat、JDK、maven、mysql、IDEA。&#xff08;软件下载及环境变量配置略&#xff09; 2、在下载好的IDEA中&#xff0c;选择新建spring initial项目&#xff0c;选定java web&#xff0c;即可新建一个spri…

win11 之下载安装 allure

1. 下载 https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/2.25.0/allure-commandline-2.25.0.zip 2. 配置系统变量 path 下添加解压后的bin目录 3. 验证是否安装成功 输入 allure

Mac 安装HomeBrew(亲测成功)

1、终端安装命令&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"执行后&#xff0c;没有安装git&#xff0c;会先安装&#xff0c;安装后再执行一下命令。 2、根据中文选择源安装 3、相关命令 查看版本号&a…

python flask使用flask_migrate管理数据库迁移

&#x1f308;所属专栏&#xff1a;【Flask】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点…

一篇文章了解常用排序算法

排序 文章目录 排序直接(插入)排序InsertSort思想实现方法&#xff1a; 希尔排序ShellSort&#xff08;可过OJ)思想预排序gap的作用整体代码 选择排序SelectSort思想完整代码 堆排序HeapSort(可过OJ)思想大根堆向下调整 完整代码 冒泡排序BubbleSort快速排序&#xff08;快排&a…

Unity URP 仿原神角色渲染过程记录

想学一下NPR渲染&#xff0c;话不多说&#xff0c;先搞一只芙再说&#xff0c;边做边学 一、资源整理 终于是把东西全都集齐了 1、纹理设置 首先要把将Diffuse和Lightmap的压缩改成"无"或"高质量"。 法线贴图的纹理类型改成"法线贴图"。 除颜…

HarmonyOS 角落里的知识 —— 状态管理

一、前言 在探索 HarmonyOS 的过程中&#xff0c;我们发现了许多有趣且实用的功能和特性。有些总是在不经意间或者触类旁通的找到。或者是某些开发痛点。其中&#xff0c;状态管理是ArkUI开发非常核心的一个东西&#xff0c;我们进行了大量的使用和测试遇到了许多奇奇怪怪的问…

Android平台下VR头显如何低延迟播放4K以上超高分辨率RTSP|RTMP流

技术背景 VR头显需要更高的分辨率以提供更清晰的视觉体验、满足沉浸感的要求、适应透镜放大效应以及适应更广泛的可视角度&#xff0c;超高分辨率的优势如下&#xff1a; 提供更清晰的视觉体验&#xff1a;VR头显的分辨率直接决定了用户所看到的图像的清晰度。更高的分辨率意…

001.VMware Workstation Pro虚拟平台安装

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

《数字图像处理-OpenCV/Python》第16章:图像的特征描述

《数字图像处理-OpenCV/Python》第16章&#xff1a;图像的特征描述 本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 第16章&#xff1a;图像的特征描述 特征通常是针对图像中的目标或…

快排(霍尔排序实现+前后指针实现)(递归+非递归)

前言 快排是很重要的排序&#xff0c;也是一种比较难以理解的排序&#xff0c;这里我们会用递归的方式和非递归的方式来解决&#xff0c;递归来解决是比较简单的&#xff0c;非递归来解决是有点难度的 快排也称之为霍尔排序&#xff0c;因为发明者是霍尔&#xff0c;本来是命名…

基于Spring Boot+VUE旧物置换网站

1前台首页功能模块 旧物置换网站&#xff0c;在系统首页可以查看首页、旧物信息、网站公告、个人中心、后台管理等内容&#xff0c;如图1所示。 图1系统功能界面图 用户注册&#xff0c;在用户注册页面通过填写用户名、密码、姓名、性别、头像、手机、邮箱等内容进行用户注册&…

FlinkCDC介绍及使用

CDC简介 什么是CDC&#xff1f; cdc是Change Data Capture(变更数据获取)的简称。核心思想是&#xff0c;监测并捕获数据库的 变动(包括数据或数据表的插入&#xff0c;更新以及删除等)&#xff0c;将这些变更按发生的顺序完整记录下来&#xff0c;写入到消息中间件以供其它服…

IPv4的报头详解

1.ipv4的报头&#xff1a; 注意&#xff1a;ipv4的报头长度共有20个字节&#xff0c;数据包通过ipv4协议传输后&#xff0c;会进行封装和解封装&#xff1a; 封装&#xff1a;tcp/ip五层参考模型 应用层网络层传输层数据链路层物理层 网络层&#xff1a;tcp/udp 传输层&#…