几周前我开始学习 EJB,我对如何在客户端和服务器端重用实体类有疑问。假设我们有 CRUD 应用程序。
- 服务器被编写为 EJB 并管理数据(创建、读取、更新、删除)。它使用 JPA 连接数据库。
- 客户端是使用 JSF2 编写的,它是一个简单的图形用户界面,使用远程 EJB 来管理数据。
- 两者(客户端和服务器)在不同的服务器上工作。
- 要使用 EJB,客户端需要有 EJB 接口(interface)和实体(需要实体来反序列化 EJB 返回的对象)。
- 服务器端实体有 JPA 注释。
- 客户端实体需要与服务器相同,但不需要 JPA 注释。
- (客户端和服务器)实体应该在同一个 jar 库中,因为它更容易维护。
这些是我解决问题的建议:
- 创建仅包含实体接口(interface)的库,以便客户端和服务器可以按照他们需要的方式实现它。
- 创建包含没有 JPA 注释的实体实现的库(服务器将需要使用 xml 而不是注释)。
什么是最好的解决方案?我的解决方案正确吗?如果有任何建议,我将不胜感激。
最佳答案
如果您信任客户端,或者如果您不关心是否有任何 JPA 注释泄露给客户端,您可以将 JPA 实体用作数据传输对象 (DTO)。警告:任何未被服务器获取的惰性托管关系将对客户端不可用,可能在序列化期间导致异常,或者可能查询和序列化太多东西。 (这是您的选项 1)
或者,您可以为每个实体创建 DTO。每个实体可能有许多 DTO(例如,包含论坛帖子所有字段的完整 DTO,仅包含标题、日期、作者的摘要 DTO)。您可以使用类似 Commons BeanUtils 的实用程序以反射方式从实体复制到 DTO,而无需编写大量样板代码 (dto.setTitle(entity.getTitle()); dto.setDate(entity.getDate()); ...
)。在这种情况下,DTO 存在于一个单独的 JAR 中,由客户端和服务器共享,但实体存在于它们自己的部署单元中并且对服务器是私有(private)的。这是 EJB 1/2 过去最受反对的做法。 (这与您的选项 2 有一些相似之处,但您将重用 DTO 而不是实体本身)
然后您可以将服务器公开为 WEB 服务或 REST 端点(JAX-WS 和 JAX-RS 使这变得非常容易)。通过适当的配置,甚至可以在客户端中重用 JPA bean。这具有与其他技术互操作的额外好处,但可能会很慢。
您的选项 2 也是可行的,但您将增加维护 XML 部署描述符的开销(XDoclet 在这种情况下可能会有所帮助,如果它支持 JPA - 已经很多年没有使用它了)。
使用任何类型的远程处理时,请注意通信通常是昂贵的。因此,远程调用应尽可能粗粒度,并尽可能少地交换数据(因此总结了上面提到的 DTO)。
关于oop - 在 EJB<->JSF2 应用程序中重用服务器端和客户端的实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18741434/