【问题标题】:Practical use of Value Objects in Spring MVC applicationSpring MVC 应用中值对象的实际使用
【发布时间】:2016-11-15 17:09:02
【问题描述】:
在我用 Hibernate 和 Spring MVC 编写的应用程序中,我有一些简单的类来表示客户、他的主要办公室地址和其他办公室的位置列表。有一个表单允许添加和编辑客户的数据,然后 Spring MVC 将其映射到 DTO、验证、发送到服务,服务将其转换为(略有不同的)实体并保存。
我考虑过使用值对象来表示和隐式验证某些对象——即电话号码、地址,但我真的不知道如何在这些框架中使用它们——即使我认为我理解值对象的概念和不变性.
如果我将在表示层中使用的 DTO 中使用它们,那么我不能依赖 Spring 将字段从表单映射到对象的机制 - 因为没有设置器。而且我必须在 Controller 或 Service 中手动进行映射。
我应该在实体中使用值对象(嵌入它们)吗?或者也许这太简单了,根本无法使用值对象?
【问题讨论】:
标签:
java
spring-mvc
domain-driven-design
value-objects
【解决方案1】:
您的问题主要不是关于值对象,而是您的主要问题(如果我理解正确的话)是如何从 Web 表单发送数据、验证数据并将数据保存在实体中。
创建一个表单对象,例如MyForm,其中包含用户可以在屏幕中输入的所有字段。表单对象用于将数据传输到服务器,例如:
class MyForm {
@NotBlank
private String name;
@NotBlank
private String phoneNumber;
@NotBlank
private String address;
// getters and setters
}
在服务器端控制器验证、转换和存储数据:
@Controller
class GuestbookController {
@RequestMapping(value = "/guestbook", method = RequestMethod.GET)
String myget(Model model, MyForm form) {
// put data on model
}
@RequestMapping(value = "/mysubmit", method = RequestMethod.POST)
String mysubmit(@Valid MyForm form, Errors errors, Model model) {
if (errors.hasErrors()) {
return myget(model, form);
}
myrepository.save(new MyEntity(form.getName(), form.getPhoneNumber(), form.getAddress()));
return "redirect:/myview";
}
}
您可能需要比单个字符串更详细的地址。那么,是的,使用包含所有地址详细信息的值对象就可以了。
【解决方案2】:
这是我谦虚的回应。
- DTO 是没有逻辑的简单数据容器,
- 而值对象则相反,封装了逻辑。
只是一个有趣的事情,DTO 过去在 Java 中被称为值对象。
查看它的一种方法(正如我所读)是让值对象封装实体的所有逻辑,实体只处理身份。
DTO 允许将域模型与 UI(或任何其他端口/适配器)分离。
值对象应该在域层之外使用吗?我不知道,但我个人不这样做。在我的设置中,它们由应用层和域内部使用,但在应用层之外只有 DTO。
我有 Spring 可以处理的 DTO 和数据映射器来进行转换(dto 在 UI/应用程序层边界处建模)。 DTO 通常可以有 setter(根据某些人的说法是事件公共财产)。
现在,如果您想使用框架映射的不可变对象,解决方案取决于您使用的技术。当我使用 JSON(和 Jackson)进行 Web 服务时,我直接使用构造函数上的 @JsonCreator 注释映射不可变命令对象,但我将我的 pojos 耦合到 jackson。为了避免这种情况,您还可以将您的客户序列化程序添加到框架中,让它自动转换控制器方法参数周围的数据结构。
否则,您始终可以使用数据映射器或工厂方法进行映射。 (我相信你写了一篇关于那个的帖子......)