JAX-RS是否需要数据传输对象(DTO)?

3
如果JAX-RS应用程序的方法返回一个域对象,那么表示(比如JSON)将包含此对象的所有属性 - 对吗?但是,如果该对象包含不应暴露给Web的“私有”数据怎么办?
另外,从外部到内部的另一个方向是什么:如何防止私有字段被覆盖?
唯一的解决方案似乎是创建数据传输对象(DTO)。
使用“automapper”不会是解决方案,除非无法指定要映射的字段。
那么,JAX-RS是否强制开发人员创建DTO?还是有其他解决方案?
3个回答

3

为了使您的实体能够透明地编组和解组到XML中,并从XML中解组出来,请使用JAXB注释进行注释(一个类可以同时用JPA和JAXB注释进行注释,这样既可以给出XML表示,也可以在数据库中持久化)。

@Entity
@XmlRootElement
public class MyEntity implements Serializable {

    @Id @GeneratedValue
    private Long id;

    ....

}

在上面的例子中,我只使用了一个JAXB注释@XmlRootElement。现在,假设您不想在序列化的XML中包含id属性。只需添加JAXB注释@XmlTransient即可:
@Entity
@XmlRootElement
public class MyEntity implements Serializable {

    @XmlTransient
    @Id @GeneratedValue
    private Long id;

    ....

}

因此,不,没有严格需要 DTO(以及将它们映射到和从实体中映射的样板代码)。

@XmlTransient 在 JAX-RS 支持的每种输出格式中都有效,还是仅限于 XML 和 JSON? - deamon
@XmlTransient 是来自于 JAXB,JAXB 用于 XML。JSON 输出器恰好支持其子集。因此,它取决于所使用的序列化程序以及所涉及的格式。顺便说一句,我不知道其他“标准”序列化程序,因此这可能是一个无意义的问题。 - StaxMan
这对实体之间的双向关系也适用吗?我记得遇到过循环引用问题。也许我错过了一些明显的东西,开始创建 DTO。你能分享一下你的想法吗? - opensourcegeek

2
我认为更好的说法是JAX-RS要求你使用“表现形式(representations)”。
我的Foo领域对象不知道它是以RESTful方式被使用的。它只知道Bar(另一个聚合根)和通过那个Bar可以导航到的任何实体。事实上,我还有一个命令行界面可以使用这个应用程序,它不使用REST甚至不使用HTTP。
我的RESTful接口将Foo/Bar包装成通过URI彼此链接的表现形式(DTOs)。我猜你可以称它们为DTOs,但如果你(如其他答案所述)只是用所需的内容注释你的领域模型来编组和解组它们,那么我认为你正在将自己编码到一个禁止HATEOAS的角落里。
当你有一个集合时,这也很明显。如果Foo->* Bar,你会以未编组的形式返回所有的Bar项吗?为什么不只返回一个URI和一些其他最小的数据,例如:
GET foo/fff
<foo>
  <link rel="self" uri="uri="foo/fff" />
  <bar uri="bar/abc123">
    <status="Active" />
  </bar>
  <bar uri="bar/qqq">
    <status="Inactive" />
  </bar>
</foo>

如果客户想了解有关某个酒吧的更多信息,可以使用以下方法:
获取 bar/abc123
<bar>
  <link rel="self" uri="bar/abc123" />
  <foo uri="foo/fff" />
  <status>Active</status>
  <title>Some Bar</title>
  ...
</bar>

当然,这只是个开始,因为使用HATEOAS,你将提供其他“有意义”的链接,客户端可以对其进行操作,这就是需要记住URI是不透明的并且不必指向文档的重要性所在。例如,对于bar/abc123,您可以将其POST到bar/deactivate URI,并将状态设置为非活动状态。或者一个常见的deactivate URI - 或者其他任何东西!意义在于超文本和您定义的关系。你不应该只是传递DTOs。 - Doug Moscrop
1
缺点是使用这些*表示类意味着需要维护一整套其他对象。我见过有人使用Resource类本身来“成为”表示。也许这是更好的选择,但对我来说似乎很混乱。到目前为止,我唯一的犹豫是我需要将更多的逻辑推入领域服务和实体,并将其排除在资源之外,但我避免这样做,因为我真的不希望领域知道它以RESTful方式被使用。 - Doug Moscrop

1

@XmlTransient(或相应的注释)指示映射器/编组器不将带注释的属性包含在序列化输出中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接