return 对 JAX-RS 中的不同 HTTP 方法做什么?

What to return for different HTTP methods in JAX-RS?

我正在练习使用 RESTEasy 实现构建 RESTFUL API。但是我还是有点迷茫,根据HTTP的方式,我应该return做什么。这是我目前正在做的方式:

  1. @GET return一个实体
  2. @POST returns 一个 HTTP 响应与创建的实际实体
  3. @PUT return 更新了实际实体的 HTTP 响应
  4. @DELETE return 删除了实际实体的 HTTP 响应

下面是我的控制器示例,用于说明。

@GET
@Path("/{bookId}")
@Produces(MediaType.APPLICATION_JSON_VALUE)
public Book getBookById(@PathParam("bookId") Integer bookId) {
    return bookService.getBookById(bookId);
}

@POST
@Consumes(MediaType.APPLICATION_JSON_VALUE)
@Produces(MediaType.APPLICATION_JSON_VALUE)
public Response inertBook(@Valid Book book) {
    return bookService.insertBook(book);
}

@DELETE
@Path("/{bookId}")
public Response deleteBook(@PathParam("bookId") Integer bookId) {
    return bookService.deleteBook(bookId);
}

@PUT
@Path("/{bookId}")
@Consumes(MediaType.APPLICATION_JSON_VALUE)
@Produces(MediaType.APPLICATION_JSON_VALUE)
public Response updateBook(@PathParam("bookId") Integer bookId, @Valid Book book) {
    return bookService.updateBook(bookId, book);
}

了解 Entity Providers, they implement MessageBodyWriter

RESTEasy 是 JAX-RS 的一个实现(今天是 Jakarta EE 的 sub-specification)。为了理解响应是如何生成的(这是你在思考你的资源方法可以做什么时需要知道的return),你应该理解MessageBodyWriter 有效。

Resource Method 可以 return 几乎任何东西,包括 StringResponse、一些自定义 bean 等,但与你的方法 return 无关s,而是 如何(作为哪种 MediaType)您的 MessageBodyWriter 实现将输出流转换为 HTTP 响应 body.

来自 JAX-RS 资源方法的

Value return 被实体提供者(即 MessageBodyWriter 实现)转换为 HTTP 响应 body,并且取决于关于你指示你的方法将什么设置为响应的 MIME 类型(@Produces,在方法之上)以及你的类路径上是否有相应的转换器(实体提供者,即 MessageBodyWriter),JAX-RS 将:

  1. 查找 @Produces 值;
  2. 然后寻找对应的转换器/MessageBodyWriter(如果在类路径中没有找到需要的实现将抛出转换异常);
  3. 使用 @Produces(MediaType.TypeHere) 将您的输出流序列化为您指示它 return 的任何内容,并将 return 它。

请记住,returning non-void Java 类型会导致 200 OK 响应,而 void 方法会导致 204 No Content 响应。

@Produces 通过向响应添加 Content-type header 来指定您的资源方法应生成的响应 body 的 MIME 类型。对于不同的 MIME 类型,您将需要一个相应的转换器库(MessageBodyWriter 的实现)到 return 任何您指定的 Media/MIME 类型。

A side-note:JAX-RS 是 RESTful 网络服务的规范,这意味着在大多数情况下,您最好使用 JSON。

  1. GET - 客户端正在尝试检索资源,换句话说,get 资源。所以是的,你应该 return 状态代码为“200 OK”的实体 在大多数情况下,它要么是单个资源,要么是集合资源;在你的例子中,要么是一本书,要么是所有的书

  2. POST - When you create a new resource, generally the client will send the representation of the new book to be created. What the client doesn't have is the identifier for the resource or how to access the resource later. What is generally done is a Location header is sent back to the client so the client can later access the resource. The status of this response should be "201 Created" Optionally, you can send back the same representation the client sent, but including the newly created identifier. You can see an example in this post.

  3. PUT - 这是一个完整的更新。因此,无论客户端发送什么,都会完全覆盖当前资源(不包括标识符)。所以最终,客户已经掌握了所有信息;无需寄回任何东西。您可以只回复“204 无内容”状态。在代码术语中,您可以简单地使用 void 方法或 return a Response 来显式设置状态。

  4. DELETE - 如果删除一切顺利,则无需发送任何内容,只需让客户知道一切正常。所以简单地发送一个“200 OK”响应是合适的。可选地,包括已删除的表示可能没问题。

这些是非常通用的准则。每个人都有自己的风格,但大多数人都试图遵循标准。以下是您可以深入了解的一些资源

放在一边

我正在查看您的服务层实现方式(您的 BookService class)并且存在一些设计缺陷。通常,在分层应用程序中,较低层不应知道其上层的任何信息。这是层的示例

  WEB
   ↓
SERVICE
   ↓
  DAO
  • WEB层就是REST层(JAX-RS代码)
  • SERVICE层是业务发生的BookService
  • DAO 层是稍后发生数据访问的数据层

在这个架构中,DAO层不应该知道SERVICE层,SERVICE层不应该知道WEB层。但是在您的示例中,您的服务知道 Response 个对象。 Response应该只在WEB层使用。更好的实现可能类似于

public Response getBook(@PathParam("id") long id) {
    Book book = bookService.findBook(id);
    if (book == null) {
        throw new NotFoundException();
    }
    return book;
}
  

现在 BookService 只负责查找图书,资源方法处理所有 Web 逻辑。