服务层和控制器:谁负责什么?

63

在课程中,我们正在学习如何构建Spring应用程序。尽管Spring没有直接参与,但我们学习了如何创建DAO和服务层对象的接口。

请纠正我如果我错了:

DAO层相当抽象:它只包含CRUD操作,并进一步用于读取数据。(例如:获取所有对象、获取特定对象等)

服务层:包含用于创建和删除事物的服务,这是业务逻辑所在的地方。

现在,所有这些在服务层都很有意义;只有“更新”对象需要注意。您仅需放置一个“更新”函数,该函数将对象保存到您的数据库中吗?还是您也需要在那里定义逻辑呢?这就是我的困惑之处,因为我理解Spring中的对象只是POJOs(普通旧Java对象)。那么,谁验证数据呢?

假设我有一个名为“child”的对象,它具有以下字段:NameSurNameGenderPhotoBirthdate。我该如何命名服务呢?或者你是否只是让控制器负责验证,这对我来说似乎不正确。另一方面,将每个需要被调用的setter委托给服务层也不太合适。

因此,基本上就是:帮我定义通过服务层保存对象的方法。

2个回答

62

通常,Spring服务都是事务性的。将一些操作放在特定的服务方法中,是因为它们应该在同一个事务中进行分组。如果您想要从数据库中检索对象、对其进行修改并保存新版本,则检索和保存应该在同一个服务方法中进行。因此,您的服务方法根据用户需要应用程序执行的操作来确定。

我尝试限制控制器执行与验证HTTP参数相关的工作,决定使用哪个服务方法及其参数,决定在httpsession或请求中放置什么内容,决定重定向或转发到哪个视图,或执行类似的Web相关任务。

就验证而言:在控制器中验证输入参数是一件好事,可以确保没有人能够通过虚假输入破坏您的应用程序。在控制器中进行验证主要是确保输入在语法上正确(包括检测注入攻击),而服务层验证则是确保数据库中的状态符合预期的代码逻辑。

因此,控制器包含Web框架基础设施代码,服务包含应用程序逻辑代码。


6
补充一下:不仅在使用Spring时,而且在暴露远程服务或某种API时,“服务”通常都应该拥有天然的事务候选方法。 - matt b

34
如果您希望控制器能够持久化更改到一个名为Child的对象上,那么传统做法是在服务中创建一个方法,例如ChildService.update(Child newchild),该方法将处理调用正确的DAO以持久化这个Child的新版本。
控制器可以自由地向服务请求一个Child对象,并更改其属性(可能基于某些用户输入)- 一个合理的设计应该是控制器对Child POJO进行一些操作,然后请求服务来持久化更改。模型POJO不应知道任何关于控制器、服务或DAO的信息,只需简单地保存数据,正如您建议的那样 - 您肯定不希望每次调用setName()setGender()都会自动导致数据库更新。
相反,控制器和/或服务应获取一个Child对象,在其工作单元中对该对象进行任何必要的操作,然后请求服务(再由DAO)来持久化更改。
验证可以在多个层面进行 - 控制器可能希望验证来自web用户的任何输入,而服务可能希望验证它是否拥有一个有效的Child对象才将其持久化。特别是在两个层面都进行某种程度的验证,如果您想以其他方式重复使用此服务 - 例如公开REST接口、不同的前端等,这样做就很有意义。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接