• 周四. 12月 1st, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

【源码分析】- 在SpringBoot中你会使用REST风格处理请求吗?

[db:作者]

1月 6, 2022

目录

前言

1、什么是 REST 风格

1.1  资源(Resources)

1.2  表现层(Representation)

1.3  状态转化(State Transfer)

1.4  综述

2、实操SpringBoot 实现REST风格的表单提交

2.1   非REST 风格的代码

2.2   REST风格的代码

3、源码分析

3.1 Springboot 的处理思路

3.2 HiddenHttpMethodFilter 处理 PUT 和DELETE


前言

工作中面试中,总能提到REST风格 ?

但你真的会使用到它吗?知道怎么去修改底层配置吗?

是不是在繁杂业务代码中早就迷失了 ? …

1、什么是 REST 风格

很多解释概念的博客,个人感觉阮一峰讲的最透彻,

原文链接 https://blog.csdn.net/zhangliangzi/article/details/51428171 

此链接不是原创,为防止他删文章,我把精华摘抄点过来,

首先 RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

REST这个词,是 Roy Thomas Fielding 在他2000年的博士论文中提出的。

REST,即 Representational State Transfer 的缩写,如果一个架构符合REST原则,就称它为RESTful架构。

要理解RESTful架构,最好的方法就是去理解Representational State Transfer这个词组到底是什么意思,它的每一个词代表了什么涵义。如果你把这个名称搞懂了,也就不难体会REST是一种什么样的设计。

 

1.1  资源(Resources)

REST的名称”表现层状态转化”中,省略了主语。”表现层”其实指的是”资源”(Resources)的”表现层”。

所谓”资源”,就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。

所谓”上网”,就是与互联网上一系列的”资源”互动,调用它的URI。

 

1.2  表现层(Representation)

“资源”是一种信息实体,它可以有多种外在表现形式。我们把”资源”具体呈现出来的形式,叫做它的”表现层”(Representation)。

比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。

URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的”.html”后缀名是不必要的,因为这个后缀名表示格式,属于”表现层”范畴,而URI应该只代表”资源”的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对”表现层”的描述。

 

1.3  状态转化(State Transfer)

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生”状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是”表现层状态转化”。

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

 

1.4  综述

综合上面的解释,我们总结一下什么是RESTful架构:

(1)每一个URI代表一种资源;

(2)客户端和服务器之间,传递这种资源的某种表现层;

(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”。

摘抄结束:希望了解更多,去上面的原文链接(希望他还在)

思考 :我个人理解一言以蔽之:它是一种前端获取资源的 原则,这个原则更多的在客户端通过有目的的动词表示本次请求的含义。

 

2、实操SpringBoot 实现REST风格的表单提交

 

2.1   非REST 风格的代码

举例说明:对用户表的的操作,增删改查平衡车那个都是这么写:

 @RequestMapping(value = "/getUser",method = RequestMethod.POST)
public String getUser(){
return "GET-张三";
}
@RequestMapping(value = "/saveUser",method = RequestMethod.POST)
public String saveUser(){
return "POST-张三";
}
@RequestMapping(value = "/putUser",method = RequestMethod.POST)
public String putUser(){
return "PUT-张三";
}
@RequestMapping(value = "/deleteUser",method = RequestMethod.POST)
public String deleteUser(){
return "DELETE-张三";
}

 

每种业务都有自己的路径,增删改查前端会看到四种不同的路径,代码整体看起来比较冗余

 

2.2   REST风格的代码

@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getUser(){
return "GET-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser(){
return "POST-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.PUT)
public String putUser(){
return "PUT-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.DELETE)
public String deleteUser(){
return "DELETE-张三";
}

 

很明显的区别,请求路径统一,通过请求方式区分获取、删除、修改、保存 等动作,清爽多了

既然这么简洁,我们实操一下吧

第1步:application.propertities 文件配置 spring.mvc.hiddenmethod.filter.enable=true,开启表单的REST风格支持(这个源码分析部分会讲到)

第2部:编写一个前端页面实测一下 REST 风格的提交:

注意下页面的 hidden隐藏域参数细节(后面源码部分会提到)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>测试 REST 风格</h1>
<form action="/user" method="get">
<input value="GET提交" type="submit">
</form>
<form action="/user" method="post">
<input value="POST提交" type="submit">
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="PUT" />
<input value="PUT提交" type="submit">
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="DELETE" />
<input value="DELETE提交" type="submit">
</form>
</body>
</html>
点击并拖拽以移动

 

点击四个按钮,发现跳转正确!

他是怎么跳转的,看源码分析  ↓

 

3、源码分析

 

3.1 Springboot 的处理思路

     SpringBoot的处理思路是:既然浏览器天然只能发送 GET 和 POST 请求,那可以利用前后的参数配合,根据约定好的参数,把POST或者GET 定向地转成 PUT 或 DELETE 请求

 

3.2 HiddenHttpMethodFilter 处理 PUT 和DELETE

实现对REST 请求风格的支持主要得益于HiddenMethodFilter 类,它同样是在WebMvcAutoConfiguration 这个自动配置类中在项目启动时自动注入的。

 // 类WebMvcAutoConfiguration下
// spring.mvc.hiddenmethod.filter.enabled 为 true 才会加载过滤器,这里就解释了前面的配置项

@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled")
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}

着重看一下 HiddenHttpMethodFilter ,顾名思义 隐藏HTTP方法过滤器,它的类注释翻译完粘贴过来:

由于浏览器目前仅支持 GET 和 POST,因此一种常用技术(例如 Prototype 库使用的技术)是使用带有附加隐藏表单字段 ( _method ) 的普通 POST 来传递“真正的”HTTP 方法。 此过滤器读取该参数并相应地更改HttpServletRequestWrapper.getMethod()返回值。 只允许”PUT” 、 “DELETE”和”PATCH” HTTP 方法。
请求参数的名称默认为_method ,但可以通过methodParam属性进行调整

看下 HiddenHttpMethodFilter 的核心方法 doFilterInternal() , 他是如何吧我们的隐藏表单解析的

 // 核心方法
 @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpServletRequest requestToUse = request;
// 首先必须满足为POST提交,然后再根据表单隐藏域名叫”_method“ 的参数进行判断
if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
// 获取 名称为 ”_method“ 的参数
String paramValue = request.getParameter(this.methodParam);
// 获取到的参数不为空
if (StringUtils.hasLength(paramValue)) {
// 把类型名称帮我们转为大写
String method = paramValue.toUpperCase(Locale.ENGLISH);
// 只允许 PUT DELETE PATCH
if (ALLOWED_METHODS.contains(method)) {
// 重新包装下这个类型为POST的request 成为客户端想让它成为的样子
requestToUse = new HttpMethodRequestWrapper(request, method);
}
}
}
filterChain.doFilter(requestToUse, response);
}

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注