hades666
介绍
世界上几乎所有的应用程序都必须访问数据以完成其工作。 使用域驱动的设计方法,您将需要定义和构建组成域的实体的存储库。 如今,Java开发人员经常使用JPA来实现这些存储库。 JPA使此任务更容易,但仍需要大量样板代码。 Hades是一个开放源代码库,它建立在JPA和Spring之上,可以通过减少实际所需的工作量来显着改善数据访问层的实现。 本文将带您进行导览,并概述了Hades在数据访问层开发方面实际上可以为您做些什么,并介绍了最新版本2.0的新功能。
Hades的核心部分包括一个通用的存储库实现,该实现不仅为您提供基本的CRUD(创建,读取,更新和删除)方法,而且还在顶部添加了一些功能,从而消除了围绕该通用实现的需求(例如分页)你自己 这包括查询存储库中的实体页面,动态添加排序定义等功能。
查询
由于您通常必须执行的大多数数据访问操作都是查询操作,所以Hades的核心功能之一就是以最小的努力轻松地定义和执行查询。 这样做的过程实际上包括三个步骤:
- 添加实体特定的存储库界面
- 添加查询方法
- 微调查询
在第一步中,您声明一个扩展GenericDao<Entity, Id>
的接口,这将导致在Hades接口中定义的CRUD操作也可在您的接口上使用:
public interface UserRepository extends GenericDao<User, Long> { … }
下一步是将查询方法添加到满足您的业务需求的界面:
List findByUsername(String username);
这应该引起一个问题,即如何从该方法派生查询。 如果您不添加任何其他元数据,则Hades将尝试查找格式为{entity}.{method-name}
的JPA命名查询,并在可用时使用它。 如果找不到任何内容,它将尝试解析方法名称并从中创建查询。 因此,前面的示例将导致查询select u from User u where u.username = ?
。 当然,查询解析器支持更多的关键字,因此可以随时在参考文档中进行查询。
如果您希望手动定义查询,则可以利用Hades的@Query
注释定义要直接在方法中执行的查询:
@Query("select from User u where u.lastname = ?");
List someReallyStrangeName(String lastname);
这使您可以自由选择自己喜欢的命名方法,同时保留对查询定义的完全控制,而不会打扰到样板查询执行代码。 执行查询还有很多其他方面, 例如对查询使用分页,执行修改查询等 。
自举阴霾
因此,既然您已经了解了如何使用查询方法创建存储库接口,那么如何开始并准备使用它们可能就很有趣了。 您可以通过创建GenericDaoFactory
实例并要求其为您创建存储库来为存储库接口创建实例:
EntityManager em = … // Get access to EntityManager
GenericDaoFactory factory = GenericDaoFactory.create(em);
UserRepository userRepository = factory.getDao(UserRepository.class);
由于通常通过依赖项注入将存储库交给客户,因此Hades在Spring应用程序中的用法具有复杂的集成。 因此,要在Spring应用程序中引导Hades,您只需使用Hades命名空间并声明一个基本软件包,该基本软件包将被扫描以查找存储库。
<hades:dao-config base-package="com.acme.*.repository" />
这将获取扩展GenericDao
所有存储库接口,并为每个接口创建Spring Bean。 当然,名称空间允许对要检测的内容进行更精细的控制 。 Hades Eclipse插件提供了与Spring IDE和SpringSource Tool Suite(STS)的无缝集成,因此您将能够引用其他bean的Hades存储库,并在工作区中将它们标记为Spring bean。 有关详细信息,请查阅参考文档。
稽核
跟踪实体的创建者,修改者和相应日期是非常普遍的要求。 Hades提供了一个EntityListener
,它将透明地为您完成这项工作。 要激活Hades审核,您需要在orm.xml
定义AuditingEntityListener
<persistence-unit-metadata>
<persistence-unit-defaults>
<entity-listeners>
<entity-listener class="org.synyx.hades.domain.auditing.support.AuditingEntityListener" />
</entity-listeners>
</persistence-unit-defaults>
</persistence-unit-metadata>
然后在您的Spring配置中激活审核,如下所示:
<hades:auditing auditor-aware-ref="auditorAware" />
引用的Spring bean auditorAware
必须实现AuditorAware
接口,您通常会实现该接口来查询当前用户的安全模块。 如果只想跟踪创建和修改日期,则只需忽略该属性。 有关审核功能的更多信息, 请参阅文档。
JPA 2.0和事务存储库
从2.0版开始,Hades基于JPA 2.0以及相应版本的Hibernate,EclipseLink和OpenJPA。 从该版本开始,CRUD操作是开箱即用的事务,因此在非常简单的情况下,不再需要事务包装层。 此外,具体的存储库接口也可以轻松进行事务处理。
public interface UserRepository extends GenericDao<User, Long> {
@Transactional(readOnly = true);
List<User> findByUsername();
@Override
@Transactional(readOnly = true, timeout = 60);
List<User> readAll();
}
如您所见,您可以使用@Transactional
注释查询方法,以使它们参与事务。 如果您不愿意,则不必使用批注,基于XML的事务配置也可以正常工作。 默认情况下, GenericDao
中实现的CRUD操作是事务性的(对于只读操作, readOnly
设置为true)。 通过简单地重新声明方法并在其上应用自定义@Transactional
即可完成为这些方法重新配置事务设置的操作。 有关更多详细信息,请参阅有关交易的参考文档 。
技术指标
最新版本的一个很酷的功能是GenericDao
的扩展,使其能够执行规范。 规范是由Eric Evans和Martin Fowler提出的领域驱动设计概念,可以归结为将实体的业务规则捕获为谓词。 Hades提供了一个抽象,可以轻松地基于JPA 2.0标准API构建此类谓词。 假设您有作家写的书。 Hades让您定义如下规格:
class BookSpecifications {
public Specification<Book> hasAuthorWithFirstnameLike(final String firstname) {
return new Specification<Book>() {
public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
return cb.like(root.join("author").get("firstname"), firstname);
}
}
}
public Specification<Book> hasGenre(final Genre genre) {
return new Specification<Book>() {
public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> cq, CriteriaBuilder cb) {
return cb.equal(root.get( "genre"), genre);
}
}
}
}
诚然,这并不是要编写的最漂亮的代码(希望通过Java 8的单一抽象方法(SAM)功能,它会变得更好)。 从积极的方面来看,我们有可能在存储库中直接执行规范:
bookRepository.readAll(hasAuthorWithFirstnameLike("Oliv*"));
好的,这几乎是我们可以通过声明的查询实现的,对吗? 将规范组合到新规范中时,规范的威力真正闪耀。 Hades提供了一个Specifications
助手类,该类允许即时合成:
bookRepository.readAll(where(hasAuthorWithFirstnameLike( "Oliv*").or(hasGenre(Genres.IT)));
这样,扩展您的存储库就成为添加新规范的问题。 拥有足够的规格,您将获得一个非常灵活的类似DSL的API,可以查询您的存储库,而不会为每种特殊情况使用查询方法污染存储库。 在文档中可以找到更详细的介绍 。
扩展名
2.0版本的另一部分是扩展模块,该模块无缝地将Hades与应用程序的上层技术(例如Spring MVC)集成。 它提供了一个PropertyEditor
和Spring 3.0 Converter
,它可以通过实体的ID透明地将实体绑定到Spring MVC控制器方法,以及一个MVC扩展,可以从HTTP请求中动态提取分页信息。 因此,显示用户页面的控制器可能如下所示:
@Controller
class UserController {
@Autowired
UserRepository userRepository;
@RequestMapping("/users")
public void showUsers(Pageable pageable, Model model) {
model.addAttribute("users", userRepository.readAll(pageable));
}
@RequestMapping("/users/{id}")
public String showUser(@PathVariable("id") User user, Model model) {
model.addAttribute("user", user);
return"user";
}
}
如您所见,对于showUsers(…)
方法,不需要自己解析HttpServletRequest
以获得分页信息。 注意,在showUser(…)
,绑定到id路径变量的方法参数已经是实体。 由于Spring MVC基础结构的配置超出了本文的范围,请随时查看扩展模块上的参考文档章节,其中提供了一些配置示例以简化设置 。
下一步是什么?
展望未来,Hades将超越2.1.x系列,成为Spring Data项目的一部分,其核心将作为其他数据存储库实现的基础。 Spring Data是一个SpringSource项目,旨在为各种新兴的专用数据存储(包括NoSQL数据库)提供惯用的Spring支持。
摘要
Hades极大地简化了使用JPA实施数据访问层的过程。 您可以免费获得复杂的CRUD操作,查询执行和规范。 它可以单独使用,但也可以与Spring很好地集成。 除此之外,还有一个Spring IDE / STS Eclipse插件以及一个Spring Roo插件,可以使用Roo轻松创建存储库。 有关更多信息, 请参见项目网站 。
hades666