如何正确使用Struts ActionForm,值对象和实体?
我继承了一个使用Struts,Spring和Hibernate的大型Java应用程序。我每天处理的类和接口是:Struts动作,Struts ActionForm,值对象,服务接口和实现,DAO接口和实现以及实体。我很清楚其中大多数的方式和原因,但我不确定ActionForm,值对象和实体之间的责任是否正确分离。我还应该提到领域模型(即所有实体)不包含很多(如果有的话)真实的业务逻辑。本质上,这是一个CRUD应用程序,大多数真正的逻辑都在数据库中(糟糕!)。无论如何,我想知道几个与Java相关的独特问题:
1)实体和值对象(VO)之间似乎并没有太大区别,并且当它们沿任一方向通过服务层时,必须编写很多代码才能相互转换(Struts Action仅处理VO,DAO仅与实体打交道。因此,VO和实体似乎有些多余。为什么两者都有?
2)VO <->实体翻译代码应该放在哪里?服务层,实体,VO?
3)VO直接放置在ActionForms中,并直接绑定到JSP中的标签(例如)。这是一个好习惯吗?如果没有,什么是合适的设计?
4)不清楚如何正确处理值对象中的外键依赖关系。例如,某些VO具有一个类型字段,以数据库的形式表示一个到类型表中的外键关系。在用户界面中,这将转换为允许用户选择类型的下拉字段,或者仅显示类型的文本表示形式的标签(取决于它在哪个屏幕上)。现在,VO是否应具有类型ID的属性,类型的文本表示形式,或者两者兼而有之?谁负责在两者之间进行翻译,何时翻译?
5)VO有一个用于其数据库ID的字段。我以为VO没有身份?这是怎么回事?
我希望这些问题能够引起普遍关注。在这种类型的体系结构中,这似乎一直存在。
另外,我怀疑这种架构会严重影响该应用程序,如果我们有更好的建议,请继续。但是我主要对上述问题的回答感兴趣,因为不同的体系结构是我目前无法做的长期重构。
解决方案
1)不需要单独的VO和实体:一些公司在其项目中强制采用这种结构。在另一个项目中可能有道理,因此被强制执行(我只能猜测)
2)服务层:这是与DAO和Action层的自然分离,对吗?
3)但这并不影响值对象的绑定,只要它们在发送到DAO之前经过正确验证即可
4)服务层应负责两者之间的转换。在加载过程中并节省时间
5)如果他们没有身份,那么我们将如何防止重复?
希望这些简短的回答对我们有所帮助。我会尽力而为,稍后再给出更长的答案。
要回答最后一部分,请使用Spring MVC而不是Struts。然后,我们可以在所有层上使用相同的域对象,绑定到表单参数的类也将在Hibernate中使用,并包含真实的业务逻辑。
例如,在我确实使用Spring MVC的应用程序中,我有一个成员类。登录,注册,更改密码和编辑配置文件表单均已绑定到此类。该类还具有休眠映射和内部的大量业务逻辑(例如,对于社交网络,是"添加朋友"方法)。
考虑DAO VO转换;这是否有用取决于Hibernate的使用方式。如果整个Web请求处理都在单个Hibernate会话中,则我们实际上不需要单独的VO。
但是,如果DAO层在使用完DAO之前打开了一个会话来检索对象并关闭了该会话,则可能在收集和引用其他对象方面遇到麻烦。很有可能它们是延迟加载的,这意味着在请求这些属性时仍必须打开Session。
简而言之,在我们开始放弃这些VO之前,请仔细,仔细地查看数据库事务和会话边界。
至于以形式使用VO;如果VO很好地映射到JSP,我会说为什么不呢?令我印象深刻的是,数据模型与它所支持的过程非常匹配,并且有点怀疑数据库没有被标准化(将来可能会或者可能不会造成问题)。
回到1. 如果将DAO与延迟加载和收集一起使用,请记住,数据库会话还必须包括JSP阶段,因为在该阶段将读取DAO。
- 服务层必须具有知道要更改哪些数据库对象的功能,并且id旨在实现这一目的。服务层将不得不从数据库中检索DAO并将DAO中的VO写入字段,尽管它显然不需要用VO的ID更新DAO的ID :)
- 我们从请求中需要的是外键字段的ID。由于它来自客户端,我们可能应该在业务逻辑中检查是否存在具有此类ID的对象。
根据VO是否接受异物的ID或者需要异物,我们应该:
- 设置ID,或者
- 使用服务层通过id获取异物作为VO,并将其放入VO中,并使用服务层将其存储
业务层负责翻译,因为服务层仅处理对象检索和存储。并且文本或者id都不是对象,而是对象的标识符。服务层可以
提供搜索功能,但它不需要上下文信息。
如果我正确地阅读了问题,VO就会通过id引用数据库中的其他对象。在这种情况下,请输入ID。如果从客户端获取字符串,则应在业务层(使用服务层)进行查找,并将找到的对象的ID放入VO。或者,如果未找到ID,则返回正确的错误消息。
作为结束语;除非我们知道自己做的很好,否则请勿触摸DAO-VO。 Hibernate是功能强大且复杂的工具,看似易于使用。我们很容易犯错误,而且很难发现它们。客户和老板都似乎不喜欢在过去可以正常使用的东西中引入错误。
顺便一提;我对DAO-VO的保守态度来自解决由于EJB2到Hibernate过渡中的类似问题而引起的问题。细节在于魔鬼,即使看起来像小菜一碟,改变数据层的处理方式也是一个重大的重构。