【问题标题】:In JAX RS, differences between returning Response and Bean or Collection of Beans (DTO)在 JAX RS 中,返回响应与 Bean 或 Bean 集合 (DTO) 之间的区别
【发布时间】:2013-04-30 15:27:48
【问题描述】:

我正在构建一个 REST api。我的问题是,在使用 Jersey 时,我的服务构建和返回 Response 对象或返回 bean 或集合之间有什么区别。我只关心成功的调用,我会针对错误和异常情况抛出适当的异常。

这是一个例子:

@Produces(MediaType.APPLICATION_JSON)
public Response search(FooBean foo){
    List<FooBean> results = bar.search(foo);
    return Response.ok(results).build();
}

对比

@Produces(MediaType.APPLICATION_JSON)
public List<FooBean> search(FooBean foo){
    List<FooBean> results = bar.search(foo);
    return results;
}

我已经看到使用的两个示例,我更喜欢第二种情况,只是为了更容易识别服务方法。我已经检查了对这两种方法的响应,它们似乎是相同的。

想法?

【问题讨论】:

  • 考虑到你没有像你说的那样返回一些 Exception 类,它们是相同的。 Response 提供返回任何类型对象的选项,还设置了HttpStatus。在这种情况下,它将产生200 OK。但是您不能使用Response 随意切换到其他状态。当然,这是我的意见,但我喜欢Response 方式。
  • 您的意思是您可以使用 Response 对象切换到不同的响应状态吗?如果我返回 List,响应状态也是 200 OK。
  • 是的,您可以根据需要切换。默认情况下,如果实体不为空,Response.ok().entity(entity).build(); 将返回 200 OK,否则将返回 204 NO CONTENT。即使实体为空,您也可以强制返回 200 OK 状态和 Response.ok().entity(entity).status(Status.OK).build();
  • 我明白了。所以除了偏好之外,返回 bean 和返回 Response builder 之间有什么区别吗?
  • 不,如果你在资源类之前捕获异常或在资源类之后拦截,没有区别......

标签: rest jax-rs jakarta-ee


【解决方案1】:

JAX-RS 规范中解释了这些差异:

3.3.3 返回类型

资源方法可以返回 void、Response、GenericEntity 或其他 Java 类型,这些返回类型映射到响应实体主体如下:

无效
结果是一个带有 204 状态代码的空实体正文。

响应
生成从响应的实体属性映射的实体主体,其状态代码由响应的状态属性指定。空返回值导致 204 状态代码。如果未设置 Response 的状态属性:非空实体属性使用 200 状态码,如果实体属性为空,则使用 204 状态码。

GenericEntity强>
生成从 GenericEntity 的 Entity 属性映射的实体主体。如果返回值不为空,则使用 200 状态码,空返回值将导致 204 状态码。

其他
生成从返回实例的类映射的实体主体。如果返回值不为空,则使用 200 状态码,空返回值导致 204 状态码。

需要为响应提供额外元数据的方法应返回一个 Response 实例,ResponseBuilder 类提供了一种使用构建器模式创建 Response 实例的便捷方法.

“常规”bean 的映射方式与Response 几乎相同,但Response 允许您设置其他元数据(响应标头、专用状态、专用内容类型等)。至于使用哪一个,这完全由您决定 - Response 为您提供更大的灵活性,但常规 bean 更“自我记录”。

【讨论】:

【解决方案2】:

如果您想始终返回响应 200 - OK ,捕获和处理在您的方法返回结果之前或之后可能发生的所有异常,使用拦截或 WebApplicationException 没有区别。因此,这两种方法都会产生相同的响应。

唯一的区别是在特定的场景下,比如返回空对象,或者创建对象,比如这个例子:

@POST
@Consumes("application/json")
public Response post(String content) {
    URI createdUri = ...
    Object createdContent = create(content);
    return Response.created(createdUri).entity(createdContent).build();
}

在这种情况下,返回将是 201 - CREATED(带有访问创建对象的 URI)

所以,下面的方法:

@POST
@Consumes("application/json")
public Object post(String content) {
    URI createdUri = ...
    Object createdContent = create(content);
    return createdContent;
}

...将返回响应200 - OK

如果您不关心您的客户将收到哪种响应状态,您可以毫无问题地使用任何声明。

来源:Jersey

【讨论】:

  • 很好的解决方案,因为我们主要使用对象进行操作,而不仅仅是字符串。所以,我有一个问题 - 如何从响应中检索对象并获取它的 xml 或 json 表示形式?
【解决方案3】:

我个人的看法,如果response包含DTO(Bean/Collection of beans),那么rest服务总是必须返回DTO,而不是Response对象。

动机:早晚都会要求您提供rest客户端api,让客户更容易使用rest服务。通常,您必须为其提取 rest 接口,并使用您的 rest 服务 实现它们。这些rest接口被你的rest客户端的客户端使用。

从客户端的角度来看,处理 DTO 和普通 Response 之间存在巨大差异。如果使用 Response,则强制您的客户端:

  1. 明确检查响应代码以处理成功的响应
  2. 通过明确检查代码来处理错误
  3. 自行将您的响应正文转换为 DTO。

这意味着处理 Response 与在方法中返回错误代码非常相似,这被认为是一种非常糟糕的做法。为了在一个地方处理错误,使用了异常(我不是在说 FP 处理错误的方式,这是最好的)。

那么你可以做什么:

  1. 如果请求处理成功,将你的rest服务数据转换成DTO/Bean并返回。
  2. 如果验证失败或出现问题,请在您的休息服务中引发异常。也许默认的异常映射器对您不利,因此,您必须实现自己的异常映射器。

所以如果要提前考虑,你应该返回 DTO。

一个用例,当应返回纯响应时 - 例如,当您导出文件时。似乎 JAX RS 不允许返回 InputStream 对象。不确定,必须检查。

@Perception 指出了另一个用例,但它更像是一个例外,而不是一个规则:

需要在响应中提供额外元数据的方法 应返回 Response 的实例,即 ResponseBuilder 类 提供了一种方便的方法来使用 建造者模式。

注意:这是 JAX RS 的一般问题,不依赖于确切的实现,如 Resteasy 或 Jersey

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-17
    • 1970-01-01
    • 2016-08-20
    • 1970-01-01
    • 2011-10-11
    • 2011-05-16
    • 2011-06-10
    相关资源
    最近更新 更多