读书笔记《building-a-restful-web-service-with-spring》REST中的CRUD操作
在第3章,第一个端点中,我们创建了我们的第一个 RESTful 端点来访问我们示例物业管理系统中的房间。检索数据的请求通常映射到 RESTful Web 服务中的 HTTP GET
方法。
现在,我们将扩展前面的示例并实现剩余的端点以支持所有 CRUD(创建、读取、更新和删除)操作。
在本章中,我们将介绍以下主题:
将 CRUD 操作映射到 HTTP 方法
创建资源
更新资源
删除资源
测试 RESTful 操作
模拟
PUT
和DELETE
方法
OPTIONS
:此方法表示对所请求的 URI。这通常不直接 与 REST 一起使用。但是,此方法可以用作底层 通信的一部分。例如,在从网页消费 Web 服务时可以使用此方法(作为跨域资源共享机制的一部分)。GET
:该方法检索由 请求的 URI。在 RESTful Web 服务的上下文中,此方法用于检索资源。如第3章所示,第一个端点 ,这是用于 读取操作(CRUD 中的 R)的方法。HEAD
:这些请求在语义上与GET
请求相同,只是响应的主体是 未传输。此方法对于获取有关资源的元信息很有用。类似于OPTIONS
方法,这种方法通常不直接用于 REST Web 服务中。PUT
:此方法请求服务器将包含的实体存储在请求URI下。为了支持更新 REST 资源,可以利用此方法。根据 HTTP 规范,如果实体不存在,服务器可以创建资源。由 Web 服务设计者决定 是否应实现此行为,或者是否应仅由POST
请求。DELETE
:最后一个未映射的操作是删除资源。 HTTP 规范定义了一个DELETE
方法,该方法在语义上与 RESTful 资源的删除一致。TRACE
:此方法用于 在 Web 服务器上执行操作。这些操作通常旨在帮助 HTTP 应用程序的开发和测试。TRACE
请求通常不会映射到任何 特定的 RESTful 操作。CONNECT
:此 HTTP 方法定义为通过 一个代理服务器。由于它处理传输层问题,因此该方法没有到 RESTful 操作的自然语义映射。
RESTful 架构不要求使用 HTTP 作为通信协议。此外,即使选择 HTTP 作为底层传输,也没有规定将 RESTful 操作映射到 HTTP 方法。开发人员可以通过 POST
请求切实支持所有操作。
话虽如此,以下 CRUD 到 HTTP 方法的映射通常用于 REST Web 服务:
手术 |
HTTP 方法 |
---|---|
创造 |
|
读 |
|
更新 |
|
删除 |
|
我们示例物业管理系统的inventory 组件处理房间。在第3章,第一个端点中,我们建立一个端点来访问房间。让我们看看如何定义一个端点来创建新资源:
我们在 RoomsResource
类中添加了一个新方法来处理新房间的创建。如第3章所述,第一个端点 , @RequestMapping
用于将请求映射到 Java 方法。在这里,我们将 POST
请求映射到 addRoom()
。
我们将新房间作为 @RequestBody
注释传递。此注解指示 Spring 将传入 Web 请求的主体映射到方法参数。此处使用 Jackson 将 JSON 请求正文转换为 Java 对象。
使用这种新方法,使用以下 JSON 正文向 http://localhost:8080/rooms
发送请求将导致创建一个新房间:
我们的新方法将返回新创建的房间:
我们可以决定只返回新资源的 ID 以响应资源创建。但是,由于我们可能会清理或以其他方式处理发送过来的数据,因此最好 返回完整资源。
第 8 章,测试 RESTful Web 服务,将详细介绍了如何有效地测试 RESTful Web 服务,但是为了快速测试我们新创建的端点的 目的,让我们看看如何测试使用 Postman 创建新房间。
Note
Postman (https://www.getpostman.com) 是一个 Google Chrome 插件扩展,它提供用于构建和测试 Web API 的工具。
以下屏幕截图说明了如何使用 Postman 测试此端点:
在 Postman 中,我们 指定我们将 POST
请求发送到 URL (http://localhost:8080/rooms
) 带有内容类型标头 (application/json
) 和请求正文。如下所示发送此请求将导致创建并返回一个新房间:
我们已经使用 Postman 成功地为我们的库存服务添加了一个房间。创建不完整的请求同样容易,以确保我们的端点在将数据持久化到数据库之前执行任何必要的健全性检查。
第 8 章,测试 RESTful Web 服务,将讨论测试 RESTful Web 服务的其他方法。
发布表单是在 Web 上创建新实体的传统方式,它可以很容易地用于 创建新的 RESTful 资源。我们可以将方法更改为以下内容:
与前面方法的主要区别在于,我们告诉 Spring 映射表单请求(即,使用内容类型,application/x-www-form-urlencoded
)而不是 JSON要求。此外,我们不期望将对象作为参数,而是单独接收每个字段。
在主要 Web 服务消费者是 Web 应用程序的情况下,使用表单请求可能更适用。然而,在大多数情况下,前一种方法更符合 RESTful 原则,应该受到青睐。此外,当处理复杂的资源时,表单请求将被证明使用起来很麻烦。从开发人员的角度来看,将对象映射委托给第三方库(例如 Jackson)更容易。
现在我们已经创建了一个新资源,让我们看看如何更新它。
选择 URI 格式是 设计 RESTful API 的重要部分。如前所述,使用路径 /rooms/{roomId}
访问房间,并在 /rooms
下创建房间。您可能还记得,根据 HTTP 规范,PUT
请求可能会导致创建实体(如果它们不存在)。根据更新请求创建新资源的决定取决于服务设计者。但是,它确实会影响用于此类请求的路径选择。
从语义上讲,PUT
请求更新存储在提供的请求 URI 下的实体。这意味着更新请求应该使用与 GET
请求相同的 URI:/rooms/{roomId}
。然而,这种方法阻碍了在更新时支持资源创建的能力,因为没有可用的房间标识符。
我们可以使用的替代路径是 /rooms
,房间标识符在请求正文中传递。使用这种方法,当资源不包含PUT 请求可以被视为 POST
请求="indexterm"> 标识符。
鉴于第一种方法在语义上更准确,我们将选择不支持更新时创建资源,我们将使用以下路径来处理 PUT
请求: /rooms/{roomId}。
正如本章开头所讨论的,我们将更新请求映射到 HTTP PUT
动词。用 @RequestMapping(value = "/{roomId}", method = RequestMethod.PUT)
注释这个方法指示 Spring 直接 PUT
在这里请求。
房间标识符是路径的一部分并映射到第一个方法参数。与资源创建请求类似,我们使用 @RequestBody
将主体映射到第二个参数。
使用 Postman,我们可以快速创建一个测试用例来更新我们之前创建的房间。为此,我们发送一个带有以下正文的 PUT
请求:
结果响应将是更新后的房间:
如果我们尝试更新一个不存在的房间,服务器将生成以下响应:
由于我们不支持在更新时创建资源,因此服务器会返回一个错误,指示找不到资源。
Note
请参阅 第 4 章,数据表示,了解关于错误处理和响应格式的讨论。
毫不奇怪,我们使用 DELETE
动词来删除 REST 资源。此外,您已经知道删除请求的路径是 /rooms/{roomId}
。
处理房间删除的Java方法如下所示:
通过将请求映射方法声明为 RequestMethod.DELETE
,Spring 将使该方法处理 DELETE
请求。
由于资源被删除,在响应中返回它没有多大意义。服务设计者可以选择返回一个布尔标志来指示资源已成功删除。在我们的例子中,我们利用响应的状态元素将该信息传递给消费者(参见 Chapter 4,数据表示,了解有关响应格式的更多详细信息)。删除房间的响应如下:
通过这个操作,我们现在有一个完整的 CRUD API 用于我们的库存服务。在结束本章之前,让我们讨论一下 REST 开发人员如何处理并非所有 HTTP 动词都可以使用的情况。
在某些情况下(例如,当服务或其消费者位于过度的 企业防火墙之后,或者如果主要消费者是网页),只有GET
和 POST
HTTP 方法可能可用。在这种情况下,可以通过在请求中传递自定义标头来模拟丢失的动词。
例如,可以使用 POST
请求通过设置自定义标头来处理资源更新(例如,X-HTTP-Method-Override
) 到 PUT
表示我们正在通过 POST
PUT 请求> 请求。以下方法将处理这种情况:
通过在映射注解上设置headers
属性,Spring请求路由会拦截POST
使用我们的自定义标头请求并调用此方法。普通的 POST
请求仍将映射到我们为创建新房间而组合在一起的 Java 方法。