Spring Data 官方文档》4.7 Spring Data扩展

4.7 Spring Data扩展

这部分说明Spring Data一系列的扩展功能,可以使Spring Dta使用多样的上下文.目前大部分集成是针对Spring MVC.

4.7.1 Querydsl扩展

Querydsl是一个框架,通过它的流式API构建静态类型的SQL类查询。多个Spring Data模块通过QueryDslPredicateExecutor与Querydsl集成。
例29 QueryDslPredicateExecutor接口

1 public interface QueryDslPredicateExecutor<T> {
2   T findOne(Predicate predicate); ①
3     Iterable<T> findAll(Predicate predicate); ②
4     long count(Predicate predicate); ③
5     boolean exists(Predicate predicate); ④
6     // … more functionality omitted.
7 }

① 查询并返回一个匹配Predicate的单例实体

②查询并返回所有匹配Predicate的实体

③ 返回匹配Predicate的实体数量

④ 返回是否存在一个匹配Predicate的实体

为了简单的使用Querydsl功能,在你的仓库接口继承QueryDslPredicateExecutor.

例30 在仓库集成QueryDsl

1 interface UserRepository extends CrudRepository<User, Long>,
2 QueryDslPredicateExecutor<User> {
3 }

像上面这样就可以使用Querydsl的Predicate书写类型安全的查询

1 Predicate predicate = user.firstname.equalsIgnoreCase("dave").and(user.lastname.startsWithIgnoreCase("mathews"));
2 userRepository.findAll(predicate);

4.7.2 Web支持

注意
本节包含Spring Data Web支持的文档是在1.6范围内的Spring Data Commons实现的.因为支持新引入的内容改变了很多东西,我们保留了旧行为的文档在”遗留Web支持”部分.

如果模块支持仓库编程模型,那么Spring Data模块附带了各种Web模块支持.Web关联的东西需要Spring MVC的JAR包位于classpath路径下,它们中有些甚至提供了Spring HATEOAS集成.一般情况,集成方式支持使用@EnableSpringDataWebSupport注解在你的JavaConfig配置类.
例31 启用Spring Data web支持

1 @Configuration
2 @EnableWebMvc
3 @EnableSpringDataWebSupport
4 class WebConfiguration {}

@EnableSpringDataWebSupport注解注册了一些组件,我们将在稍后讨论.注解还将在类路径上检测Spring HATEOAS,如果才在将为其注册集成组件.
作为可选项,如果你使用XML配置,注册SpringDataWebSupport或者HateoasWareSpringDataWebSupport作为Spring bean:
例32 用XML启用Spring Data web支持

1 <bean class="org.springframework.data.web.config.SpringDataWebConfiguration" />
2 <!-- If you're using Spring HATEOAS as well register this one *instead* of the former -->
3 <bean class"org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration"/>

基本Web支持
上面展示的的配置设置将注册几个基本组件:

  • 一个DomainClassConverter启用Spring MVC来根据请求参数或路径变量管理仓例实体类的实例
  • HandlerMethodArgumentResolver实现让Spring MVC从请求参数解析Pageable和Sort实例

实体类转换
DomainClassConverter允许你在Spring MVC控制器方法签名中直接使用实体类型,因此你不必手动的通过仓库查询实例:
例33 一个Spring MVC控制器在方法签名中使用实体类型

1 @Controller
2 @RequestMapping("/users")
3 public class UserController {
4   @RequestMapping("/{id}")
5   public String showUserForm(@PathVariable("id") User user, Model model) {
6     model.addAttribute("user", user);
7     return "userForm";
8   }
9 }

如你所见,方法直接接收一个User实例并没有更进一步的查询是否必要.实例可以通过Spring MVC将路径变量转换为实体类的id类型并最终通过在实体类型注册的仓库实例上调用findOne(…)访问实例转换得到.

注意
当前的仓库必须实现CrudRepository做好准备被发现来进行转换.

为了分页和排序分解方法参数
上面的配置片段还注册了一个PageableHandlerMethodArgumentResolver和一个SortHandlerMethodArgumentResolver实例.注册使得Pageable和Sort成为有效的控制器方法参数.
例34 使用Pageable作为控制器方法参数

01 @Controller
02 @RequestMapping("/users")
03 public class UserController {
04   @Autowired UserRepository repository;
05   @RequestMapping
06   public String showUsers(Model model, Pageable pageable) {
07     model.addAttribute("users", repository.findAll(pageable));
08     return "users";
09   }
10 }</blockquote>

这个方法签名将使Spring MVC尝试使用下面的默认配置从请求参数中转换一个Pageable实例:

表1 请求参数转换Pageable实例

为了定制行为,可以继承SpringDataWebConfiguration或者启用等效的HATEOAS并覆盖pageableResolver()或sortResolver()方法并导入你的自定义配置文件替代@Enable-注解.
有一种情况你需要多个Pageable或Sort实例从请求转换(例如处理多个表单),你可以使用Spring的@Qualifier注解来互相区别.请求参数必须以${qualifier}为前缀.这样一个方法的签名像这样:

1 public String showUsers(Model model,
2                         @Qualifier("foo")Pagebale first,
3                         @Qualifier("bar") Pageable second) {
4   ...
5 }

你必须填充foo_page和bar_page等.
默认的Pageable在方法中处理等价于一个new PageRequest(0, 20),但是可以使用@PageableDefaults注解在Pageable参数上定制.
Hypermedia支持分页
Spring HATEOAS包装了一个代表模型的类PageResources ,它可以使用Page实例包装必要的Page元数据内容作为连接让客户端导航页面.一个页面到一个PageResources的转换被Spring HATEOAS的ResourceAssembler接口实现PagedResourcesAssembler来完成.
例35 使用一个PagedResourcesAssembler作为控制器方法参数

01 @Controller
02 class PersonController {
03   @Autowired PersonRepository repository;
04   @RequestMapping(value = "/persons", method = RequestMethod.GET)
05   HttpEntity<PagedResources<Person>> persons(Pageable pageable,
06                                              PagedResourcesAssembler assembler) {
07     Page<Person> persons = repository.findAll(pageable);
08     return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK);
09   }
10 }

像上面这样配置将允许PageResourcesAssembler作为控制器方法的一个参数.在这调用toResources(…)方法有以下作用:

  • Page的内容将PageResources实例的内容
  • PageResources将获得PageMetadata实例,该实例由Page和基础的PageRequest中的信息填充
  • PageResources获得prev和next连接,添加这些依赖在页面.这些链接将指向uri方法的调用映射.页码参数根据PageableHandlerMethodArgumentResolver添加到参数以在后面被转换

假设我们有30个Person实例在数据库.你现在可以触发一个GET请求 http://localhost:8080/persons, 你将可以看到类似下面的内容:

01 { "links" : [ { "rel" : "next",
02 "href" : "http://localhost:8080/persons?page=1&size=20 }
03 ],
04 "content" : [
05 … // 20 Person instances rendered here
06 ],
07 "pageMetadata" : {
08 "size" : 20,
09 "totalElements" : 30,
10 "totalPages" : 2,
11 "number" : 0
12 }
13 }

你可以看到编译生成了正确的URI,并且还会提取默认配置转换参数到即将到来的请求中的Pageable.这意味着,如果你改变配置,链接也将自动跟随改变.默认情况下,编译指向控制器执行的方法,但是这可以被一个自定义链接作为基本构建来构成分页的Link重载PagedResourcesAssembler.toResource(…)方法定制.
Querydsl web 支持
那些整合了QueryDSL的存储可能从Request查询字符串中的属性驱动查询.
这意味着前面例子的查询字符串可以给出User的对象

1 ?firstname=Dave&lastname=Matthews

可以被转换为

1 QUser.user.firstname.eq("Dave").and(QUser.user.lastname.eq("Matthews"))

使用QuerydslPredicateArgumentResolver.

注意
当在类路径上找到Querydsl时,该功能将在@EnableSpringDataWebSupport注解中自动启用

添加一个@QuerydslPredicate到一个方法签名将提供一个就绪的Predicate,可以通过QueryDslPredicateExecutor执行.

提示
类型信息通常从返回方法上解析.由于这些信息不一定匹配实体类型,使用QuerydslPredicate的root属性可能是个好主意.

01 @Controller
02 class UserController {
03   @Autowired UserRepository repository;
04   @RequestMapping(value = "/", method = RequestMethod.GET)
05   String index(Model model, @QuerydslPredicate(root = User.class) Predicate predicate,  ①
06               Pageable pageable, @RequestParam MultiValueMap<String, String>
07     parameters) {
08         model.addAttribute("users", repository.findAll(predicate, pageable));
09         return "index";
10   }
11 }

①为User转换匹配查询字符串参数的Predicate

默认的绑定规则如下:

  • Object在简单属性上如同eq
  • Object在集合作为属性如同contains
  • Collection在简单属性上如同in

这些绑定可以通过@QuerydslPredicate的bindings属性定制或者使用Java8default methods给仓库接口添加QuerydslBinderCustomizer

01 interface UserReposotory extends CurdRepository<User, String>,
02   QueryDslPredicateExecutor<User>,  ①
03   QuerydslBinderCustomizer<QUser> {  ②
04     @Override
05     default public void customize(QuerydslBindings bindings, QUser user) {
06       bindings.bind(user.username).first((path, value) -> path.contains(value));  ③
07       bindings.bind(String.class).first((StringPath path, String value) -> path.containsIgnoreCase(value));  ④
08       bindings.excluding(user.password);  ⑤
09     }
10   }

① QueryDslPredicateExecutor为Predicate提供特殊的查询方法提供入口
② 在仓库接口定义QuerydslBinderCustomizer将自动注解@QuerydslPredicate(bindings=…)
③ 为username属性定义绑定,绑定到一个简单集合
④ 为String属性定义默认绑定到一个不区分大小写的集合
⑤ 从Predicate移除密码属性

仓库填充

如果你使用Spring JDBC模块,你可能熟悉在DataSource使用SQL脚本来填充.一个类似的抽象在仓库级别可以使用,尽管它不是使用SQL作为数据定义语言,因为它必须由存储决定.填充根据仓库支持XML(通过Spring的OXM抽象)和JSON(通过Jackson)定义数据.
假设你有一个文件data.json内容如下:
例36 JSON定义的数据

1 [ { "_class" : "com.acme.Person",
2      "firstname" : "Dave",
3       "lastname" : "Matthews" },
4       { "_class" : "com.acme.Person",
5      "firstname" : "Carter",
6       "lastname" : "Beauford" } ]

你可以容易的根据Spring Data Commons提供仓库的命名空间填充元素填充你的仓库.为了填充前面的数据到你的PersonRepository,像下面这样配置:
例37 声明一个Jackson仓库填充

01 <?xml version="1.0" encoding="UTF-8"?>
02   <beans xmlns="http://www.springframework.org/schema/beans"
03     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04     xmlns:repository="http://www.springframework.org/schema/data/repository"
05     xsi:schemaLocation="http://www.springframework.org/schema/beans
06       http://www.springframework.org/schema/beans/spring-beans.xsd
07       http://www.springframework.org/schema/data/repository
08       http://www.springframework.org/schema/data/repository/spring-repository.xsd">
09     <repository:jackson2-populator locations="classpath:data.json" />
10   </beans>

这样的声明可以让data.json文件可以被一个Jackson的ObjectMpper读取和反序列化.
JSON将要解析的对象类型由检查JSON文档的_class属性决定.基本组件将最终选择合适的仓库去处理反序列化的对象.
要使用XML定义数据填充仓库,你可以使用unmarshaller-populator元素.你配置它使用Spring OXM提供给你的XML装配选项.在Spring reference documentation查看更多细节.
例38 声明一个装配仓库填充器(使用JAXB)

01 <?xml version="1.0" encoding="UTF-8"?>
02     <beans xmlns="http://www.springframework.org/schema/beans"
03       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
04       xmlns:repository="http://www.springframework.org/schema/data/repository"
05       xmlns:oxm="http://www.springframework.org/schema/oxm"
06       xsi:schemaLocation="http://www.springframework.org/schema/beans
07         http://www.springframework.org/schema/beans/spring-beans.xsd
08         http://www.springframework.org/schema/data/repository
09         http://www.springframework.org/schema/data/repository/spring-repository.xsd
10         http://www.springframework.org/schema/oxm
11         http://www.springframework.org/schema/oxm/spring-oxm.xsd">
12       <repository:unmarshaller-populator locations="classpath:data.json"
13         unmarshaller-ref="unmarshaller" />
14       <oxm:jaxb2-marshaller contextPath="com.acme" />
15     </beans>

遗留web支持

Spring MVC的实体类绑定
如果正在开发Spring MVC web应用,你通常必须从URL中解析实体类的id.默认的,你的任务是转化请求参数或URL参数到实体类并将它移交给下面或直接在实体上操作业务逻辑.这看起来像下面这样:

01 @Controller
02 @RequestMapping("/users")
03 public class UserController {
04   private final UserRepository userRepository;
05  
06   @Autowired
07   public UserController(UserRepository userRepository) {
08     Assert.notNull(repository, "Repository must not be null!");
09     this.userRepository = userRepository;
10   }
11  
12   @RequestMapping("/{id}")
13   public String showUserForm(@PathVariable("id") Long id, Model model) {
14     // Do null check for id
15     User user = userRepository.findOne(id);
16     // Do null check for user
17     model.addAttribute("user", user);
18     return "user";
19   }
20 }

首先你为每个控制器定义一个依赖的仓库来查找它们分别管理的实体.查询实体也是样板,因为它总是一个findOne(…)调用.幸运的Spring提供了方法来注册自定义组件,允许一个String值转换到一个属性类型.
属性编辑
Spring3.0之前JavaPropertyEditors被使用.为了集成这些,Spring Data提出一个DomainClassPropertyEditorRegistrar来查询所有注册到ApplicatonContext的Spring Data仓库和一个定制的PropertyEditor来管理实体类.

01 <bean class="….web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
02   <property name="webBindingInitializer">
03     <bean class="….web.bind.support.ConfigurableWebBindingInitializer">
04       <property name="propertyEditorRegistrars">
05         <bean class=
06           "org.springframework.data.repository.support.DomainClassPropertyEditorRegistrar"/>
07       </property>
08     </bean>
09   </property>
10 </bean>

如果你已经像上面这样配置Spring MVC,你可以向下面这样配置你的控制器,从而减少不清晰和样板式的代码

查看源代码

打印帮助

1 @Controller
2 @RequestMapping("/users")
3 public class UserController {
4   @RequestMapping("/{id}")
5   public String showUserForm(@PathVariable("id") User user, Model model) {
6     model.addAttribute("user", user);
7     return "userForm";
8   }
9 }

转载自 并发编程网 - ifeve.com

时间: 2024-09-11 10:24:11

Spring Data 官方文档》4.7 Spring Data扩展的相关文章

《Spring 5官方文档》35. Spring注解编程模型

介绍 这篇文档是以Spring Framework 4.2作为框架基础编写的,但是,这篇文档是一份还在进行的工作.所以随着时间推移,你会看到这份文档还在更新. 目录 概要 术语 例子 FAQ 附录 概要 这些年,Spring Framework已经频繁的升级它可以支持的注解.元注解和组合注解.这篇文档旨在帮助开发者(Spring框架使用者.Spring核心框架开发者和Spring全家桶的成员项目开发者)开发和运用Spring注解. 这些是文档目标 这篇文档的主要目的包含以下内容: 怎么使用Spr

《Spring 5 官方文档》1. Spring入门指南(一)

译者注:为了方便理解,本译文里面部分名词翻译如下,如有异议,请在评论区指出. Dependency Injection - 依赖注入 Inversion of Control – 控制反转 Instrumentation – 植入 AOP - 面向切面​​的编程 Milestones – 里程碑 Snapshots – 快照 Artifact - 工件(这个词在文中大部分地方都没有翻译,用过Maven或Gradle的都明白,如果有更好的中文翻译,请写在评论区) 1.Spring入门指南 本参考指

《Spring 5官方文档》翻译邀请

公司新的应用已经开始使用Spring 5,所以本月组织大家翻译<Spring 5 官方文档> SINGLE网页版  PDF版本. 如何领取 通过评论领取想要翻译的文章,每次领取一章或一节(根据内容长短),翻译完后再领取其他章节.领取完成之后,建议在一个星期内翻译完成,如果不能完成翻译,也欢迎你邀请其他同学和你一起完成翻译.请谨慎领取,并发网是非盈利组织,没办法去跟进每一篇译文的进展,所以很多文章领取了没有翻译,会导致文章长时间没人翻译. 如何提交? 翻译完成之后请登录到并发编程网后台,点击左上

Spring Data 官方文档》Reference Documentation至5.2. Examples Repository

文档结构 参考文档的这一部分讲解Spring Data Cassandra所提供的核心功能. Cassandra 支持 介绍 Cassandra 模块特性设置. Cassandra 资源库 介绍 Cassandra 所支持的资源. 5. Cassandra 支持 Cassandra 包含了非常广泛的特性, 其总结如下 Spring配置支持Cassandra驱动的实例类和副本集使用基于Java的@Configuration类或XML命名空间. CassandraTemplate帮助程序类,可提高执

《Spring Data 官方文档》5.6 保存, 更新, 以及删除数据行

5.6. 保存, 更新, 以及删除数据行 'CassandraTemplate'提供了一种简单的方法来保存,更新和删除域对象,并将这些对象映射到存储在Cassandra中的文档. 5.6.1. 如何在映射层中处理复合主键字段 Cassandra要求您至少具有一个CQL表的分区键字段.或者,您可以有一个或多个Clustering键字段. 当您的CQL表具有复合主键字段时,您必须创建一个@PrimaryKeyClass以定义复合主键的结构. 在这个上下文中,复合主键意味着一个或多个分区列,或1个分区

《Spring Data官方文档》5.3. Connecting to Cassandra with Spring至5.5. Introduction to CassandraTemplate

5.3. 连接到Spring Cassandra 5.3.1. 外部化连接属性 你需要连接到Cassandra来创建配置文件信息.接触点是键空间的所必需的最小字段,但是为了清楚起见,最好能添加端口. 我们称这些为cassandra.properties cassandra.contactpoints=10.1.55.80,10.1.55.81 cassandra.port=9042 cassandra.keyspace=showcase 下面两个例子中我们将使用spring把这些属性加载到Spr

《Spring 5 官方文档》16.ORM和数据访问(二)

16.3.4编程式事务划分 开发者可以在应用程序的更高级别上对事务进行标定,而不用考虑低级别的数据访问执行了多少操作.这样不会对业务服务的实现进行限制:只需要定义一个Spring的PlatformTransactionManager即可.当然,PlatformTransactionManager可以从多处获取,但最好是通过setTransactionManager(..)方法以Bean来注入,正如ProductDAO应该由setProductDao(..)方法配置一样.下面的代码显示Spring

《Spring 5 官方文档》16.ORM和数据访问(三)

16.4.2 基于JPA的EntityManagerFactory和EntityManager来实现DAO 虽然EntityManagerFactory实例是线程安全的,但EntityManager实例不是.注入的JPA EntityManager的行为类似于从JPA Spec中定义的应用程序服务器的JNDI环境中提取的EntityManager.它将所有调用委托给当前事务的EntityManager(如果有);否则,它每个操作返回的都是新创建的EntityManager,通过使用不同的Enti

《Spring 5 官方文档》26. JMS(一)

26.1 介绍 Spring 提供了一个 JMS 的集成框架,简化了 JMS API 的使用,就像 Spring 对 JDBC API 的集成一样. JMS 大致可分为两块功能,即消息的生产与消费.JmsTemplate类用于消息生产和消息的同步接收. 对于类似 Java EE 的消息驱动 Bean 形式的异步接收,Spring 提供了大量用于创建消息驱动 POJOs(MDPs)的消息监听器.Spring 还提供了一种创建消息侦听器的声明式方法. org.springframework.jms.