nil*_*ils 15 java jpa multi-tier dto
在stackoverflow上阅读了一些Q/As后,我仍然对在我的Web应用程序中正确实现DTO感到困惑.我目前的实现是一个(基于Java EE的)多层架构(具有持久性,服务和表示层),但是所有层都使用"公共"包,包含(以及其他)域对象.在这种情况下,层不能真正被认为是独立的.我打算逐步删除常见的包,但我遇到了各种挑战/问题:
谢谢你的任何答案.
jno*_*ovo 16
在不同层之间使用一些包并不罕见,但通常只针对诸如日志记录等交叉问题.您的模型不应由不同的图层共享,或者对模型的更改需要在所有图层中进行更改.通常,您的模型是较低层,靠近数据层(上,下或交织,取决于方法).
顾名思义,数据传输对象是用于传输数据的简单类.因此,它们通常用于层之间的通信,特别是当您拥有通过消息而非对象进行通信的SOA体系结构时.DTO应该是不可变的,因为它们仅仅是为了传递信息而不是改变它而存在.
您的域对象是一回事,您的DTO是另一回事,您在表示层中需要的对象是另一回事.但是,在小型项目中,实施所有这些不同的集合并在它们之间进行转换可能不值得.这取决于您的要求.
您正在设计一个Web应用程序,但它可能有助于您的设计问自己,"我可以通过桌面应用程序切换我的Web应用程序吗?我的服务层真的不知道我的表示逻辑吗?".用这些术语思考将指导您走向更好的架构.
关于你的问题:
假设持久层将使用类myproject.persistence.domain.UserEntity(基于JPA的实体)来存储数据库或从数据库加载数据.要在视图中显示数据,我将提供另一个类myproject.service.domain.User.我在哪里转换它们?用户的服务是否有责任在两个类之间进行转换?这真的有助于改善耦合吗?
服务层知道它的类(DTO)和它下面的层(让我们说持久性).所以,是的,该服务负责在持久性和自身之间进行转换.
User类应该如何?它应该只包含不可变的getter吗?编辑现有用户的视图(创建新用户,使用现有用户对象的getter等)不是很麻烦吗?
DTO背后的想法是您只使用它们进行传输,因此不需要创建新用户等操作.为此你需要不同的对象.
我应该使用相同的DTO类(用户)向服务发送请求以修改现有用户/创建新用户还是应该实现其他类?
服务方法可以表示操作,DTO是仅包含数据的参数.另一种选择是使用代表操作的命令并且还包含DTO.这在SOA体系结构中很流行,其中您的服务可能仅仅是命令处理器,例如,只有一个Execute操作将ICommand接口作为参数(而不是每个命令有一个操作).
通过使用myproject.service.domain中的所有DTO,表示层不会非常依赖于服务层吗?
是的,服务层上的图层将依赖于它.这就是主意.好处是只有该层依赖于它,没有上层或下层,因此更改只会影响该层(与您从每个层使用域类时所发生的情况不同).
如何处理我自己的例外?我的当前方法重新抛出大多数"严重"异常,直到它们由表示层处理(通常记录它们并且用户被告知出现了问题).一方面我有一个问题,我再次hava共享包.另一方面,我仍然不确定这可以被视为"最佳实践".有任何想法吗?
每个层都有自己的例外.它们从一层流到另一层,封装成下一种异常.有时,它们将由一个层来处理,这将执行某些操作(例如,记录),然后可能抛出一个上层必须处理的异常.其他时候,他们可能会被处理,问题可能会得到解决.考虑一下连接数据库的问题.它会引发异常.您可以处理它并决定在一秒钟之后重试,然后可能会成功,因此异常不会向上流动.如果重试也失败,则会重新抛出异常并且它可能一直流到表示层,您可以优雅地通知用户并要求他重试图层.
松散耦合确实是推荐的方法,这意味着您最终将在业务逻辑中编写巨大的、枯燥的、痛苦的维护转换器。是的,它们属于业务逻辑:DAO 和视图之间的层。因此,业务层最终将依赖于 DAO DTO 和视图 DTO。并且将充满 Converter 类,淡化您对实际业务逻辑的看法......
如果您可以摆脱不可变视图 DTO,那就太好了。不过,用于序列化它们的库可能需要它们具有设置器。或者,如果它们有设置器,您可能会发现它们更容易构建。
我已经很好地为视图和 DAO 使用相同的 DTO 类。这很糟糕,但老实说,我并没有感觉到系统更加解耦,因为业务逻辑,最重要的部分,无论如何都必须依赖于一切。这种紧密耦合提供了极大的简洁性,并且使同步视图和 DAO 层变得更加容易。通过使用组合,我仍然可以拥有仅某一层特定的内容,而在另一层中看不到的内容。
最后,关于例外情况。最外层、视图层(如果使用 Spring 则为控制器)有责任捕获从内层传播的错误,无论是使用异常还是使用特殊的 DTO 字段。然后这个最外层需要决定是否通知客户端错误以及如何通知客户端。事实上,直到最内层,您需要区分最外层需要处理的不同类型的错误。例如,如果 DAO 层发生了一些事情,并且视图层需要知道是返回 400 还是 500,那么 DAO 层将需要向视图层提供决定使用哪一个所需的信息,并且该信息将需要要通过所有中间级别,他们应该能够添加自己的错误和错误类型。将 IOException 或 SQLException 传播到最外层是不够的,内层还需要告诉外层这是否是预期的错误。悲伤但真实。
| 归档时间: |
|
| 查看次数: |
9847 次 |
| 最近记录: |