在Spring MVC控制器中使用服务和数据访问对象(DAO)

6
我正在构建一个以后端/数据库数据的CRUD操作为主要内容的Web应用程序。有些情况下,我需要编写业务逻辑(随着我们在开发中深入,我相信我们会构建更多的业务逻辑)。目前,对于我创建的每个UI屏幕,我都会创建一个模型类、服务类、DAO类、控制器(实质上是servlet)和一堆jsp页面。在大多数情况下,服务类只是调用DAO中的方法来传递模型对象。基本上,我们使用模型类将数据从UI屏幕映射出来。因此,当提交表单时,控制器将填充模型对象。我已经开始使用服务类来保持Web层与DAO层之间的分离层。但有时候我觉得服务类只是增加了不必要的API调用层级,我认为我可以直接将DAO注入到控制器中,以更快地完成任务。我希望仅在需要执行其他业务逻辑时才使用服务类。如果您要设计一个应用程序,您会考虑使用控制器->DAO还是控制器->服务->DAO控制流的哪些因素?

1
我在开始现在的工作时加入了一个已经存在的项目。我已经在这里工作了一年多。老实说,我刚刚意识到应该有一个单独的层来注入DAO。工作中的项目只是将它们注入控制器中。现在我知道了这一点,并且已经了解了原子性的好处,我认为由于我们在整个应用程序中有多个交互实体,拥有一个服务层会很好。 - theblang
4个回答

11

DAO(数据访问对象)更加细化且处理一个具体实体。服务提供宏观级别的功能,可能会使用多个DAO。通常,服务用于定义事务边界,以获得原子性。换句话说,如果您使用多个DAO更新多个表格,那么在服务中定义事务边界将有助于提交或回滚对数据库所做的所有更改。

在您的设计中,由于您主要为各种实体执行CRUD操作,因此似乎服务并没有增加太多价值。但是,请把基于Web的前端视为更新数据的一种方式。使用服务将允许您稍后向其他形式的客户端(如第三方集成器等)公开相同的功能作为Web服务。

因此,总之,您的设计似乎符合传统实践。如果您认为可以根据某些共同主题将多个服务合并到一个服务中,从而减少代码开销,那么您应该继续这样做。最终目标是创建可维护的代码,当需要时,每个人都不会害怕更改。


1
“服务的使用”并不需要一个服务类来返回一个简单的列表/执行CRUD或作为RESTful-API公开。当操作多个相互交互的实体时,您需要单独的服务类。 - NimChimpsky
当为外部应用程序提供服务时,您需要使用服务。想象一下,您有一个Web服务,为Android应用程序提供数据。您可以创建一个服务层,该层将获取数据并返回DTO(数据传输对象)以供适配器层使用,该层处理REST请求并将这些DTO转换为JSON或XML以发送到Android应用程序。 - dgimenes

1
在《Pro-Spring-3》一书中,他们提到了以下这行代码,用于使用JPA2的控制器。
Once the EntityManagerFactory had been properly configured, injecting it into your service layer
classes is very simple.
他们正在使用与以下服务和存储库相同的类:
package com.apress.prospring3.ch10.service.jpa;
// Import statements omitted
@Service("jpaContactService")
@Repository
@Transactional
public class ContactServiceImpl implements ContactService {
private Log log = LogFactory.getLog(ContactServiceImpl.class);
@PersistenceContext
private EntityManager em;
// Other code omitted
}

但是如果您要使用Spring Data CRUDRepository或JPARepository,那么您的DAO将是接口,您需要创建服务层来处理您的代码。


0

我会在这里引用我的答案。

长话短说,使用服务层的优点是如果您想要处理Spring Security和角色等内容,它可以为您提供未来的扩展空间。它允许您更原子地处理事务,并且Spring本身对此有非常好的注释。


然后,您必须经历从控制器中分离出DAO关注点的痛苦。如果您的控制器与DAO紧密耦合,则在未构建服务层的情况下,这将导致更多的工作量。 - David
1
因为服务应该提供关注点分离(http://en.wikipedia.org/wiki/Separation_of_concerns),所以忽略该服务门面直接从控制器访问DAO是非常不好的做法,如果引入了服务层。尽管在最初阶段您不需要服务层会违反DRY规则,但事实上,随后进行任何重构都会更加痛苦,因为它具有SoC。 - David
我只是把这个链接留在这里 https://dev59.com/CnA65IYBdhLWcg3wrgsa ,因为它基本上总结了我的理由,即为什么对于可能会变得更加复杂的应用程序而言,拥有一个服务层是一个好主意。 - David

0

当处理多个聚合根时,请使用服务类。

将存储库(也称返回集合的dao)或dao直接注入控制器,无需额外的层/类来执行基本的获取操作。

仅在必要时使用服务类,否则您将有两倍于所需的代码。

您可以使存储库通用,并使用@Transactional(propagation = Propagation.REQUIRED)进行注释,这将强制存在事务,但如果已经存在,则不会创建新事务。因此,如果稍后在一个服务类方法中使用多个存储库,则只会有一个事务。


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