MVC 架构 DTO/Model mapping/conversion
MVC architecture DTO/Model mapping/conversion
使用Spring MVC 我们通常会看到Controller、Service 和Repository 层。 Repository 层使用 Entity 模型,它与数据库是一对一的映射。我想到了以下 -
- Service层是否应该使用相同的Entity模型?
- Service层是否应该使用单独的Domain模型?如果是,那么 to/fro 映射应该在服务层完成吗?
- Controller层我们应该使用相同的Domain模型吗?
- Controller层是否应该使用单独的DTO模型?如果是,那么 to/fro 映射应该在 Controller 层完成?
- 我们有什么简单的方法可以不用写太多冗长的代码来做映射吗?我过去用过几次推土机。
这个问题可能有人问过,但我找不到。所以请原谅我重复的问题。
1) 是的,
2) 没有,
3,4) 使用实体进行输出,但使用 CommandObjects 和 DTO(但不是实体)进行输入。这取决于您的体系结构,但我不希望客户端操纵您实体的每个字段,那么您需要将用于 request-mapping(命令对象)的对象与您的域实体分开。
- 是的。
- 没有。该服务应在存储库对象返回的实体模型上工作。
- 没有。控制器应使用 DTO。 DTO 应包含表单字段和验证注释(如果您使用的是 JSR303)。
- 是的。 DTO 在控制器层中使用。 DTO 应该公开一个接受实体模型的构造函数。实体模型到 DTO 的转换是在这个构造函数中完成的。实体模型的情况相同。实体模型还应该公开一个重载的构造函数,它接受 DTO 对象作为参数。 DTO 到实体模型的转换应该在这里发生。
- DTO (Entity model as arg) 和 Entity model (DTO as arg) 的重载构造函数很冗长。
整个服务层使用的实体模型应该是一样的。
根据您的架构和应用程序的复杂性,您可能希望在服务和控制器层中使用不同的域模型。
我的建议是:
- 服务始终在使用数据库检索和存储的实体上工作
- 服务始终采用 DTO 或简单类型作为参数,return 仅采用 DTO。为什么?因为 DTO 与数据库分离,您既不会 运行 进入 LazyInitializationException 也不必使用 open-session-in-view anti-pattern.
- 将 DTO 视为服务和控制器之间共享的唯一模型
- 对于实体和 DTO 对象之间的映射,我建议使用 ModelProjector。它非常简单、精简并留下最小的足迹
ModelProjector 通过匹配 属性 名称简单地将一个模型映射到另一个模型。如果它们不匹配,你可以用注解告诉它。也可以将复杂的实体层次结构映射到 "flattened" 数据结构上,使用非常直接的注解。实体 类 保持不变。
使用Spring MVC 我们通常会看到Controller、Service 和Repository 层。 Repository 层使用 Entity 模型,它与数据库是一对一的映射。我想到了以下 -
- Service层是否应该使用相同的Entity模型?
- Service层是否应该使用单独的Domain模型?如果是,那么 to/fro 映射应该在服务层完成吗?
- Controller层我们应该使用相同的Domain模型吗?
- Controller层是否应该使用单独的DTO模型?如果是,那么 to/fro 映射应该在 Controller 层完成?
- 我们有什么简单的方法可以不用写太多冗长的代码来做映射吗?我过去用过几次推土机。
这个问题可能有人问过,但我找不到。所以请原谅我重复的问题。
1) 是的,
2) 没有,
3,4) 使用实体进行输出,但使用 CommandObjects 和 DTO(但不是实体)进行输入。这取决于您的体系结构,但我不希望客户端操纵您实体的每个字段,那么您需要将用于 request-mapping(命令对象)的对象与您的域实体分开。
- 是的。
- 没有。该服务应在存储库对象返回的实体模型上工作。
- 没有。控制器应使用 DTO。 DTO 应包含表单字段和验证注释(如果您使用的是 JSR303)。
- 是的。 DTO 在控制器层中使用。 DTO 应该公开一个接受实体模型的构造函数。实体模型到 DTO 的转换是在这个构造函数中完成的。实体模型的情况相同。实体模型还应该公开一个重载的构造函数,它接受 DTO 对象作为参数。 DTO 到实体模型的转换应该在这里发生。
- DTO (Entity model as arg) 和 Entity model (DTO as arg) 的重载构造函数很冗长。
整个服务层使用的实体模型应该是一样的。 根据您的架构和应用程序的复杂性,您可能希望在服务和控制器层中使用不同的域模型。 我的建议是:
- 服务始终在使用数据库检索和存储的实体上工作
- 服务始终采用 DTO 或简单类型作为参数,return 仅采用 DTO。为什么?因为 DTO 与数据库分离,您既不会 运行 进入 LazyInitializationException 也不必使用 open-session-in-view anti-pattern.
- 将 DTO 视为服务和控制器之间共享的唯一模型
- 对于实体和 DTO 对象之间的映射,我建议使用 ModelProjector。它非常简单、精简并留下最小的足迹
ModelProjector 通过匹配 属性 名称简单地将一个模型映射到另一个模型。如果它们不匹配,你可以用注解告诉它。也可以将复杂的实体层次结构映射到 "flattened" 数据结构上,使用非常直接的注解。实体 类 保持不变。