Controller层可以直接调用持久层吗?

时间:2013-05-21 06:32:30

标签: spring model-view-controller jsf-2 layer mybatis

我使用JSF,Spring和Mybatis进行webapp。这些框架分别在控制器,业务和dao层中使用。在我的DAO层中,我有CRUD操作的方法。现在,在我的控制器层中,我需要使用插入操作。为此,我可以使用此配置:

控制器层

我正在使用带注释的JSF

@ManagedBean
public class Controller{
    @ManagedProperty("#{business}")
    private Business business;

    public void insert(){
        business.insert();
    }
}

业务层

我正在使用带注释的Spring

public interface Business{
    public void insert();
}

@Service("business")
public class BusinessImpl implements Business{
    @Autowired
    private DaoMapper mapper;

    @Override
    @Transactional
    public void insert(){
        mapper.insert();
    }
}

DAO图层

我正在使用Mybatis(mybatis-spring库)

public interface DaoMapper{
    public void insert();
}

但是在这种情况下我的业务层只调用DAO层并且没有实现任何其他操作,我会考虑使用这种配置:

控制器层

@ManagedBean
public class Controller{
    @ManagedProperty("#{daoMapper}")
    private DaoMapper mapper;

    public void insert(){
        mapper.insert();
    }
}

DAO图层

public interface DaoMapper{

    @Transactional
    public void insert();
}

我已经测试过并且工作正常,但我想知道我是否会招致不良行为

[编辑]

实际上,DaoMapper接口是一个与XML文件(Look)相关联的MyBatis类映射器。我不知道这是否是DAO课程。我想我应该把它称为 Persisence Layer Mapper Layer

enter image description here

来源:http://www.infoq.com/articles/ddd-in-practice

如你所见。表示层,在我的情况下,控制器层(我想我又犯了另一个错误命名),直接调用DTO(或者这就是我的理解)

如果在我的控制器或表示层(无论你怎么称呼它)我需要使用插入或更新操作,我可以直接从mapper类调用,或者我必须为这个类调用mapper类创建一个新的业务类

现在。如果可以使用这种配置我有疑问:

假设在我的业务类的方法中,我需要调用插入操作。这就像:

@Service("business")
public class BusinessImpl implements Business{
    @Autowired
    private DaoMapper mapper;

    @Override
    @Transactional
    public void insert(){
        mapper.insert();
    }
}

但是来自DaoMapper界面的方法插入已经有 @Transactional 注释。方法插入将受到 @Transactional 注释的两次影响。这不是问题吗?

3 个答案:

答案 0 :(得分:2)

我建议不直接在控制器中使用DAO。在我看来。 Dao层是来自数据库的映射,就像你想要更改另一个数据库(例如从sql到nosql)一样,唯一的事情就是只创建一个新的DAO并注入,但是让控制器和服务功能完全没有改变。控制器也是如此,它的主要职责是处理请求和响应,工作应该由业务/服务层完成。如果错误的话,请指出

答案 1 :(得分:1)

如果要删除图层,可以使用Controller和Service,但跳过DAO。 您的服务可以直接调用映射器,因为您没有任何特定的查询代码。 我知道像Adam Bien这样的知名Java人士认为DAO是一种死亡模式。 http://www.adam-bien.com/roller/abien/entry/jpa_ejb3_killed_the_dao

答案 2 :(得分:0)

服务层定义域模型(业务逻辑)的操作及其原子性。

我建议无论如何都有服务层。它具有重要的功能。它实现了域模型的“动词”/动作,并且是您还可以通过 @Transactional 定义操作原子性的好地方。在我看来,使用 @Transactional 注释 MyBatis 映射器方法是一种不好的做法。实体(在您的案例中是 MyBatis 结果 POJO)是您的域模型的“名词”。

没有动作的领域模型是没有用的。

只有“名词”的域模型是没有用的,你需要能够对它执行一些操作(“动词”)。 “动词”由服务层实现。这就是为什么我认为在 99.9% 的情况下服务层是必要的。 到目前为止,您只遇到了业务逻辑操作与 CRUD 操作 1:1 的简单情况。但这是两件不同的事情。可能会有更复杂的情况。想象一下在线银行应用程序,您有注册新客户的用例。这是一个涉及多个实体的业务逻辑操作:您需要创建用户,并且需要创建与该用户关联的银行帐户。这必须发生在单个 SQL 事务中。 “动词”-“名词”分离是很自然的方法。

控制器处理 Web 方面,它们不用于实现域模型的操作。

控制器是网页控制器或 REST 控制器。它们处理与页面模型相关的方面(在 JSF 的情况下为 @ManagedBean)或定义 RESTful API(在 Spring WebMVC 的情况下为 @RestController)。它们不是为了实现领域模型的动作。 同样由于这个原因,将实体用作 RESTful API 的 DTO 也是一种不好的做法。实体是域模型“名词”,RESTful API 的 DTO 定义了 RESTful API 层的表示。这些是不同的东西。