控制器,服务,存储库和简单的委托方法

时间:2013-03-14 13:24:12

标签: spring java-ee service repository

我有一个Java EE应用程序,它使用spring / hibernate / jsp和典型图层的标准堆栈:

  • @Repository(或DAO)
  • @服务
  • @Controller

每个存储库都有许多find ...方法(例如,对于BookRepository:简单的findById,findByTitle,findByAuthor,更复杂的findMostUsed,findMostCommented等。)

服务层包含调用存储库的业务逻辑。

控制器调用服务方法并填充要在JSP中使用的ModelAndView。

当然,有些方法在服务中有一些复杂的业务逻辑。但令人讨厌的是,有很多这样的愚蠢方法:

public List<Book> findMostUsed() {
    return repository.findMostUsed();
}
public List<Book> findMostCommented (boolean includeRating) {
    return repository.findMostCommented(includeRating);
}
...

所以它们只是一个简单的委托(这些查找方法中没有业务逻辑 - 存储库中的数据库查询会进行所有选择和分组)。

如果我需要更改存储库中的方法,则还需要更改服务。经过2年的开发,没有必要为这些方法添加任何逻辑 - 只更改查询及其参数。

我看到人们创建控制器的设计更糟糕 - &gt;门面 - &gt;服务 - &gt;存储库 - &gt; DAO的每一层都充满了这样的方法。

什么是更好的设计?

也许删除所有这些方法并将服务转换为更通用(例如BookPricingService,BookRatingService等,而不是单个BookService(违反单一责任原则btw)?然后Controller将调用Service和Repository层,这是不好。

或许可以使find方法更通用,例如findByCriteria(标准)来减少它们的数量。但问题是查询是如此不同,这将以一种switch-case块结束,该块根据条件类型选择正确的查询/参数。顺便说一句,Spring-Data还建议每个查询使用@Query注释一个方法。

也许这只是我们为了获得抽象层而付出的代价?

1 个答案:

答案 0 :(得分:1)

对于这样的简单getter,我只是将@Repository直接注入我的@Controller或需要@Service,并使用@Transactional(propagation = Propagation.REQUIRED)注释存储库。该annoatation incidcation方法必须在事务中使用,并且如果尚未存在则创建一个(但如果已经在事务中则不会创建第二个)。

当操作多个根聚合/实体时,即当存在两种类型的存储库时,应使用服务类。由于服务捆绑了一个工作单元所需的方法,因此它们是同一事务的一部分。

我也厌倦了不同的模式和依赖。​​

我还使用critera查询和generics来避免许多非常类似的方法,例如:

@Transactional(readOnly = true)
    public <T> List<T> getFieldLike(String fieldName, String value) {
        final Session session = sessionFactory.getCurrentSession();
        final Criteria crit = session.createCriteria(genericType).add(Restrictions.ilike(fieldName, value, MatchMode.ANYWHERE));
        return crit.list();
    }

    @Transactional(readOnly = true)
    public <T> List<T> getFieldsEq( final Map<String, Object> restrictions) {
        final Session session = sessionFactory.getCurrentSession();
        final Criteria crit = session.createCriteria(genericType);
        for (final Map.Entry<String, Object> entry : restrictions.entrySet()) {
            crit.add(Restrictions.eq(entry.getKey(), entry.getValue()));
        }
        return crit.list();
    }