【SpringMVC】3—RESTFul风格

⭐⭐⭐⭐⭐⭐
Github主页👉https://github.com/A-BigTree
笔记链接👉https://github.com/A-BigTree/Code_Learning
⭐⭐⭐⭐⭐⭐

如果可以,麻烦各位看官顺手点个star~😊

如果文章对你有所帮助,可以点赞👍收藏⭐支持一下博主~😆


文章目录

  • 3 RESTFul风格
    • 3.1 RESTFul概述
      • 3.1.1 REST概念
      • 3.1.2 REST规范的内涵
        • 资源
        • 状态转移
      • 3.1.3 REST规范具体要求
        • 四种请求方式
        • URL地址风格
      • 3.1.4 REST风格的好处
        • 含蓄安全
        • 风格统一
        • 无状态
        • 严谨优雅
        • 简洁优雅
        • 丰富的语义
    • 3.2 四种请求方式映射
      • 3.2.1 `HiddenHttpMethodFilter`与装饰模式
        • 简介
        • `HiddenHttpMethodFilter`要点
        • 原始请求对象的包装
      • 3.2.2 PUT请求
        • web.xml
        • 表单
        • 处理方法
      • 3.2.3 DELETE请求
        • 场景
        • 负责转换的表单
        • 删除超链接绑定单击响应函数
        • 编写单击响应函数
        • 处理方法
    • 3.3 `@PathVariable`注解
      • 3.3.1 操作
        • 传一个值
        • 传多个值
        • 处理方法

3 RESTFul风格

3.1 RESTFul概述

3.1.1 REST概念

REST:Representational State Transfer,表现层资源状态转移。

  • 定位:互联网软件架构风格;
  • 倡导者:Roy Thomas Fielding;
  • 文献:Roy Thomas Fielding的博士论文;

3.1.2 REST规范的内涵

资源

URL:Uniform Resource Locator统一资源定位器。意思是网络上的任何资源都可以通过 URL 来定位。但是在实际开发中,我们往往是使用URL来对应一个具体的功能,而不是资源本身。REST规范则倡导使用URL对应网络上的各种资源,任何一个资源都可以通过一个URL访问到,为实现操作幂等性奠定基础。而这个资源可以是网络上的一个文本、音频、视频、图片等等……

幂等性:如果一个操作执行一次和执行N次对系统的影响相同,那么我们就说这个操作满足幂等性。而幂等性正是REST规范所倡导的。

状态转移

REST倡导针对资源本身操作,所以对资源的操作如果满足幂等性,那么操作只会导致资源本身的状态发生变化而不会破坏整个系统数据。

3.1.3 REST规范具体要求

四种请求方式

REST风格主张在项目设计、开发过程中,具体的操作符合HTTP协议定义的请求方式的语义

操作请求方式
查询操作GET
保存操作POST
删除操作DELETE
更新操作PUT

另有一种说法:

  • POST 操作针对功能执行,没有锁定资源 id,是非幂等性操作;
  • PUT 操作锁定资源 id,即使操作失败仍然可以针对原 id 重新执行,对整个系统来说满足幂等性:
    • id对应的资源不存在:执行保存操作
    • id对应的资源存在:执行更新操作

URL地址风格

REST风格提倡URL地址使用统一的风格设计,从前到后各个单词使用斜杠分开不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为URL地址的一部分,以保证整体风格的一致性。还有一点是不要使用请求扩展名

传统 URL 地址REST 风格地址
/remove/emp?id=5/emp/5
  • 用一句话描述当前资源
  • 一句话中各个单词用斜杠分开,从前到后保持完全一致的书写风格
  • 不要使用问号键值对的方式传递数据
  • 需要传递数据时,把数据嵌入到URL地址中,作为地址的一部分
  • 不要使用请求扩展名

3.1.4 REST风格的好处

含蓄安全

使用问号键值对的方式给服务器传递数据太明显,容易被人利用来对系统进行破坏。使用 REST 风格携带数据不再需要明显的暴露数据的名称。

风格统一

URL 地址整体格式统一,从前到后始终都使用斜杠划分各个单词,用简单一致的格式表达语义。

无状态

在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了系统设计的复杂度。

严谨优雅

严格按照HTTP1.1协议中定义的请求方式本身的语义进行操作。

简洁优雅

过去做增删改查操作需要设计4个不同的URL,现在一个就够了。

操作传统风格REST 风格
保存/CRUD/saveEmpURL 地址:/CRUD/emp
请求方式:POST
删除/CRUD/removeEmp?empId=2URL 地址:/CRUD/emp/2
请求方式:DELETE
更新/CRUD/updateEmpURL 地址:/CRUD/emp
请求方式:PUT
查询(表单回显)/CRUD/editEmp?empId=2URL 地址:/CRUD/emp/2
请求方式:GET

丰富的语义

通过 URL 地址就可以知道资源之间的关系。它能够把一句话中的很多单词用斜杠连起来,反过来说就是可以在 URL 地址中用一句话来充分表达语义。

3.2 四种请求方式映射

3.2.1 HiddenHttpMethodFilter与装饰模式

简介

在HTML中,GET和POST请求可以天然实现,但是DELETE和PUT请求无法直接做到。SpringMVC提供了HiddenHttpMethodFilter帮助我们将POST请求转换为DELETE或PUT请求。

HiddenHttpMethodFilter要点

默认请求参数名常量:

public static final String DEFAULT_METHOD_PARAM = "_method";

HiddenHttpMethodFilter中,声明了一个常量:DEFAULT_METHOD_PARAM,常量值是"_method"

配套的成员变量:

private String methodParam = DEFAULT_METHOD_PARAM;

之所以会提供这个成员变量和配套的setXxx()方法,是允许我们在配置Filter时,通过初始化参数来修改这个变量。如果不修改,默认就是前面常量定义的值。

在这里插入图片描述

原始请求对象的包装

困难:

  • 包装对象必须和原始对象是同一个类型
  • 保证同一个类型不能通过子类继承父类实现
    • 子类对象:希望改变行为、属性的对象
    • 父类对象:随着Servlet容器的不同,各个容器对HttpServletRequest接口给出的实现不同。如果继承了 A 容器给出的实现类,那么将来就不能再迁移到 B 容器。
  • 只能让包装对象和被包装对象实现相同接口
    • 虽然使用动态代理技术大致上应该能实现,但是一旦应用代理就必须为被包装的对象的每一个方法都进行代理,操作过于繁琐。
  • 如果我们自己创建一个类实现HttpServletRequest接口
    • 困难1:在不确定具体哪一个 Servlet 容器的情况下完全没办法实现
    • 困难2:抽象方法实在太多

HttpServletRequestWrapper

HttpServletRequestWrapper类能够非常好的帮助我们对原始request对象进行包装。它为什么能帮我们解决上面的困难呢?

  • HttpServletRequestWrapper 类替我们实现了HttpServletRequest接口;
  • 为了让包装得到的新对象在任何Servlet容器平台上都能够正常工作,HttpServletRequestWrapper类此处的设计非常巧妙:它借助原始的request对象本身来实现所有的具体功能;
  • 在我们想通过包装的方式来修改原始对象的行为或属性时,只需要在HttpServletRequestWrapper 类的子类中重写对应的方法即可;

HttpMethodRequestWrapper类:

HttpMethodRequestWrapper类就是HiddenHttpMethodFilter 的一个内部类,在HttpMethodRequestWrapper类中有如下行为实现了对原始对象的包装:

  • 继承了官方包装类:HttpServletRequestWrapper
  • 在构造器中将原始request对象传给了父类构造器;
  • 将我们指定的新请求方式传给了成员变量;
  • 重写了父类(官方包装类)的getMethod()方法;
  • 外界想知道新包装对象的请求方式时,会来调用被重写的getMethod()方法,从而得到我们指定的请求方式;
/**
 * Simple {@link HttpServletRequest} wrapper that returns the supplied method for
 * {@link HttpServletRequest#getMethod()}.
 */
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
  
  private final String method;
  
  public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
        // 在构造器中将原始 request 对象传给了父类构造器
    super(request);
        
        // 将我们指定的新请求方式传给了成员变量
    this.method = method;
  }
  
  @Override
  public String getMethod() {
    return this.method;
  }
}

3.2.2 PUT请求

web.xml

<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>

表单

  • 要点1:原请求方式必须是 post
  • 要点2:新的请求方式名称通过请求参数发送
  • 要点3:请求参数名称必须是_method
  • 要点4:请求参数的值就是要改成的请求方式
<!-- 原请求方式必须是 post -->
<form th:action="@{/emp}" method="post">
    <!-- 通过表单隐藏域携带一个请求参数 -->
    <!-- 请求参数名:_method -->
    <!-- 请求参数值:put -->
    <input type="hidden" name="_method" value="put" />

    <button type="submit">更新</button>
</form>

处理方法

// 映射请求地址:URL + 请求方式
@RequestMapping(value = "/emp", method = RequestMethod.PUT)
public String updateEmp() {
    
    logger.debug("现在执行的是 updateEmp() 方法");
    
    return "target";
}

3.2.3 DELETE请求

场景

<h3>将XXX请求转换为DELETE请求</h3>
<table id="dataTable">
    <tr>
        <th>姓名</th>
        <th>年龄</th>
        <th>删除</th>
    </tr>
    <tr>
        <td>张三</td>
        <td>40</td>
        <td>
            <a th:href="@{/emp}" @click="doConvert">删除</a>
        </td>
    </tr>
    <tr>
        <td>李四</td>
        <td>30</td>
        <td>
            <a th:href="@{/emp}" @click="doConvert">删除</a>
        </td>
    </tr>
</table>

负责转换的表单

<!-- 创建一个通用表单,在删除超链接的单击响应函数中通过这个表单把GET请求转换为POST,进而再转DELETE -->
<form method="post" id="convertForm">
    <input type="hidden" name="_method" value="delete" />
</form>

删除超链接绑定单击响应函数

<td>
    <!-- /emp/{empId}/{pageNo} -->
    <!-- οnclick="convertMethod(this)" 表示点击这个超链接时,调用 convertMethod() 函数 -->
    <!-- this 代表当前超链接对象 -->
    <!-- event 是代表当前事件的事件对象 -->
    <a onclick="convertMethod(this, event)" th:href="@{/emp}">删除</a>
</td>

编写单击响应函数

<script type="text/javascript">

    function convertMethod(anchorElement, event) {

        // 获取超链接原本要访问的目标地址
        var targetURL = anchorElement.href;

        // 获取表单对象
        var formEle = document.getElementById("convertForm");

        // 把超链接原本要访问的地址设置给表单的 action 属性
        formEle.action = targetURL;

        // 提交表单
        formEle.submit();

        // 取消控件的默认行为:让超链接不会跳转
        event.preventDefault();
    }

</script>

处理方法

@RequestMapping(value = "/emp", method = RequestMethod.DELETE)
public String removeEmp() {
    
    logger.debug("现在执行的是 removeEmp() 方法");
    
    return "target";
}

3.3 @PathVariable注解

3.3.1 操作

传一个值

<a th:href="@{/emp/20}">传一个值</a><br/>
// 实际访问地址:/emp/20
// 映射地址:/emp/{empId}是把变量部分用大括号标记出来,写入变量名
@RequestMapping("/emp/{empId}")
public String getEmpById(@PathVariable("empId") Integer empId) {
    
    logger.debug("empId = " + empId);
    
    return "target";
}

传多个值

<a th:href="@{/emp/tom/18/50}">传多个值</a><br/>

处理方法

// 实际地址:/emp/tom/18/50
@RequestMapping("/emp/{empName}/{empAge}/{empSalary}")
public String queryEmp(
        @PathVariable("empName") String empName,
        @PathVariable("empAge") Integer empAge,
        @PathVariable("empSalary") Double empSalary
) {
    
    logger.debug("empName = " + empName);
    logger.debug("empAge = " + empAge);
    logger.debug("empSalary = " + empSalary);
    
    return "target";
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习 01

目录 一、机器学习 二、机器学习工作流程 2.1 获取数据 2.2 数据集 2.2.1 数据类型构成 2.2.2 数据分割 2.3 数据基本处理 2.4 特征工程 2.4.1什么是特征工程 2.4.2 为什么需要特征工程(Feature Engineering) 2.4.3 特征工程内容 2.5 机器学习 2.6 模型评估 2.7 …

Java代理之jdk动态代理+应用场景实战

本文将先介绍jdk动态代理的基本用法&#xff0c;并对其原理和注意事项予以说明。之后将以两个最常见的应用场景为例&#xff0c;进行代码实操。这两个应用场景分别是拦截器和声明性接口&#xff0c;它们在许多开发框架中广泛使用。比如在spring和mybatis中均使用了拦截器模式&a…

【计算机架构】如何计算 CPU 时间

目录 0x00 响应时间和吞吐量&#xff08;Response Time and Throughput&#xff09; 0x01 相对性能&#xff08;Relative Performance&#xff09; 0x02 执行时间测量&#xff08;Measuring Execution Time&#xff09; 0x03 CPU 时钟&#xff08;Clocking&#xff09; 0x…

【数据结构与算法】并查集

文章目录一、并查集的概念二、并查集的实现2.1 find()的实现2.2 路径压缩算法2.3 join()的实现三、并查集的应用3.1 例题&#xff1a;合并集合3.2 例题&#xff1a;连通块中点的数量四、总结一、并查集的概念 并查集是一个树形结构&#xff0c;所谓的并查&#xff0c;就是当我…

关于神经网络的权重信息和特征图的可视化

目录 1. 介绍 2. 隐藏层特征图的可视化 2.1 AlexNet 网络 2.2 forward 2.3 隐藏层特征图可视化 2.4 测试代码 3. 训练参数的可视化 3.1 从网络里面可视化参数 3.1.1 测试代码 3.1.2 参数的字典信息 3.1.3 参数可视化 3.2 从保存的权重参数文件(.pth)里面可视化参数…

汉诺塔与二进制、满二叉树的千丝万缕

汉诺塔(Tower of Hanoi)源于印度传说中&#xff0c;大梵天创造世界时造了三根金钢石柱子&#xff0c;其中一根柱子自底向上叠着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定&#xff0c;在小圆盘上不能放大圆盘&#xff0c;在三…

数据挖掘(2.3)--数据预处理

目录 三、数据集成和转换 1.数据集成 2.数据冗余性 2.1 皮尔森相关系数 2.2卡方检验 3.数据转换 四、数据的规约和变换 1.数据归约 2数据离散化 三、数据集成和转换 1.数据集成 数据集成是将不同来源的数据整合并一致地存储起来的过程。 不同来源的数据可能有不同…

【ESP32+freeRTOS学习笔记之“ESP32环境下使用freeRTOS的特性分析(2-多核环境中的任务)”】

目录1、ESP32的双核对称多处理SMP概念2、涉及任务task的特殊性2.1 创建任务的特殊函数2.2 xTaskCreatePinnedToCore&#xff08;&#xff09;函数的解释3、任务的删除4、总结1、ESP32的双核对称多处理SMP概念 最初的FreeRTOS&#xff08;以下简称Vanilla FreeRTOS&#xff09;…

线性表——顺序表

文章目录一&#xff1a;线性表二&#xff1a;顺序表1&#xff1a;概念与结构1&#xff1a;静态顺序表2&#xff1a;动态顺序表2&#xff1a;动态顺序表的代码实现1&#xff1a;结构2&#xff1a;接口实现1&#xff1a;初始化2&#xff1a;释放内存3&#xff1a;检查容量4&#…

Linux下最小化安装CentOS-7.6(保姆级)

文章目录安装包开始安装一、 新建一个虚拟机二、配置安装CentOS7.6二、开始安装CentOS三、配置CentOS并下载基本信息安装包 链接&#xff1a;https://pan.baidu.com/s/1DodB-kDy1yiNQ7B5IxwYyg 提取码&#xff1a;p19i 开始安装 一、 新建一个虚拟机 1、 打开VMWare&#x…

刷题笔记【5】| 快速刷完67道剑指offer(Java版)

本文已收录于专栏&#x1f33b;《刷题笔记》文章目录前言&#x1f3a8; 1、合并两个有序链表题目描述思路一&#xff08;递归&#xff09;思路二&#xff08;双指针&#xff09;&#x1f3a8; 2、树的子结构题目描述思路一&#xff08;递归&#xff09;&#x1f3a8; 3、二叉树…

Redis分布式锁系列

1.压力测试出的内存泄漏及解决&#xff08;可跳过&#xff09; 使用jmeter对查询产品分类列表接口进行压力测试&#xff0c;出现了堆外内存溢出异常。 我们设置的虚拟机堆内存100m&#xff0c;并不是堆外内存100m 产生堆外内存溢出&#xff1a;OutOfDirectMemoryError 原因是…

某大厂面试题:说一说Java、Spring、Dubbo三者SPI机制的原理和区别

大家好&#xff0c;我是三友~~ 今天来跟大家聊一聊Java、Spring、Dubbo三者SPI机制的原理和区别。 其实我之前写过一篇类似的文章&#xff0c;但是这篇文章主要是剖析dubbo的SPI机制的源码&#xff0c;中间只是简单地介绍了一下Java、Spring的SPI机制&#xff0c;并没有进行深…

SQL——数据查询DQL

基本语句、时间查询&#xff08;当天、本周&#xff0c;本月&#xff0c;上一个月&#xff0c;近半年的数据&#xff09;。 目录 1 查询语句基本结构 2 where 子句 3 条件关系运算符 4 条件逻辑运算符 5 like 子句 6 计算列 7 as 字段取别名 8 distinct 清除重复行 9 …

linux mysql

安装 下载包 wget https://cdn.mysql.com/archives/mysql-8.0/mysql-8.0.31-1.el8.x86_64.rpm-bundle.tar解压 tar -zxvf mysql-8.0.31-1.el8.x86_64.rpm-bundle.tar -C /usr/local/mysql安装openssl-devel插件 yum install openssl-devel安装rpm包 使用rpm -ivh安装图中r…

【Unity项目实战】从零手戳一个背包系统

首先我们下载我们的人物和背景资源,因为主要是背包系统,所以人物的移动和场景的搭建这里我们就不多讲了,我这里直接提供基础项目源码给大家去使用就行 基础项目下载地址: 链接: https://pan.baidu.com/s/1o7_RW_QQ1rrAbDzT69ApRw 提取码: 8s95 顺带说一下,这里用到了uni…

AttributeError: module transformers has no attribute LLaMATokenizer解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

AES加密

来源&#xff1a;链接: b站up主可厉害的土豆 &#xff08;据评论区说图片中有计算错误&#xff0c;但是过程是对的。只是了解过程问题不大&#xff0c;专门研究这一块的话自己可以看视频算一下&#xff09; 准备 首先&#xff0c;明文是固定长度 16字节 128位。 密钥长度可以…

TCP协议一

TCP数据报格式 TCP通信时序 下图是一次TCP通讯的时序图。TCP连接建立断开。包含大家熟知的三次握手和四次握手。 在这个例子中&#xff0c;首先客户端主动发起连接、发送请求&#xff0c;然后服务器端响应请求&#xff0c;然后客户端主动关闭连接。两条竖线表示通讯的两端&…

houjie-cpp面向对象

houjie 面向对象 面向对象&#xff08;上&#xff09; const 在一个函数后面放const&#xff0c;这个只能修饰成员函数&#xff0c;告诉编译器这个成员函数不会改数据 const还是属于函数签名的一部分。 引用计数&#xff1a;涉及到共享的东东&#xff0c;然后当某个修改的时候&…