乐趣区

两行代码玩转Spring-Data排序和分页

【本文版权归微信公众号 ” 代码艺术 ”(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】

一:唠嗑

在实际项目中对 Spring Data 的各种使用相当多,简单的增删改查 Spring Data 提供了现成的方法,一些复杂的,我们可以在接口方法写 And,Not 等关键字来搞定,想写原生 SQL,CQL(Neo4j),Query DSL(Elasticsearch)的,直接使用 @Query(“……”)注解搞定,真的是方便到不行!

本篇博客不打算讲 Spring Data 如何使用,不同的模块(JPA,Neo4j….)使用也略不相同,但 Spring Data 的排序 Sort 和分页 Pageable 接口都是差不多的,所以带大家搞明白搞明白 Spring Data 的排序和分页是如何使用的。

二:介绍

Spring Data 的任务是为数据访问提供一个熟悉的、一致的、基于 Spring 的编程模型,同时仍然保留底层数据存储的特殊特性。

Spring Data 项目的目的是为了简化构建基于 Spring 框架应用的数据访问计数,包括非关系数据库、Map-Reduce 框架、云数据服务等等;另外也包含对关系数据库的访问支持。

SpringData 让数据访问变得更加方便。

三:模块

Spring Data

  • Spring Data for Apache Cassandra
  • Spring Data Commons
  • Spring Data Couchbase
  • Spring Data Elasticsearch
  • Spring Data Envers
  • Spring Data for Pivotal GemFire
  • Spring Data Graph
  • Spring Data JDBC
  • Spring Data JDBC Extensions
  • Spring Data JPA
  • Spring Data LDAP
  • Spring Data MongoDB
  • Spring Data Neo4J
  • Spring Data Redis
  • Spring Data REST
  • Spring Data for Apache Solr
  • Spring for Apache Hadoop

四:排序

通过一行代码就可以快速使用:

Sort sort = new Sort(Sort.Direction.DESC, "id");

在 Sort 类中定义了一个枚举类型 Direction,该枚举类型声明了两个常量ASCDESC 定义方向。该构造方法的第一个参数指明方向降序(DESC)或升序(ASC),第二个参数指明以 id 列的值为准进行排序。

你也可以创建一个多属性的 Sort 实例。

Sort(Sort.Direction direction, List<String> properties)

你也可以只传入属性而不声明方向:

Sort(String... properties)

不过官方已经弃用该方法,推荐使用

public static Sort by(String... properties)

当你不声明方向时,默认方向为升序。

public static final Direction DEFAULT_DIRECTION = Direction.ASC;

Sort 的一些方法

修饰符和类型 方法和描述
Sort and(Sort sort)
返回由当前排序的排序顺序与给定的排序顺序组成的新排序。
Sort ascending()
返回具有当前设置但升序方向的新排序。
static Sort by(List<Sort.Order> orders)
为给定的 Sort.Order 创建一个新的排序。
static Sort by(Sort.Direction direction, String... properties)
创建一个新的排序。
static Sort by(Sort.Order... orders)
Creates a new Sort for the given Sort.Orders.
static Sort by(String... properties)
Creates a new Sort for the given properties.
Sort descending()
返回具有当前设置但顺序相反的新排序。
boolean equals(Object obj)
Sort.Order getOrderFor(String property)
根据 property 获取 Order
boolean isSorted()
boolean isUnsorted()
Iterator<Sort.Order> iterator()
static Sort unsorted()
返回一个根本没有排序设置的排序实例。

Sort.Order

Sort.OrderSort 的 一个静态内部类,官方说明是:PropertyPath 实现了排序的配对。方向和属性。它用于提供排序的输入。

简单来讲,你可以定义一个 Order,在需要时传入 order 构建 Sord 实例。

Order(Sort.Direction direction, String property)

更独特的使用是加入自己的空处理提示的枚举:

Order(Sort.Direction direction, String property, Sort.NullHandling nullHandlingHint)

Sort.NullHandling是可用于排序表达式的空处理提示的枚举。对使用的数据存储的一种提示,用于在非空条目之后对具有空值的条目进行排序。

在需要 Sort 时,可通过 Order 创建:

Sort(Sort.Order... orders)

Sort.Order 的一些方法

修饰符和类型 方法和描述
static Sort.Order asc(String property)
创建升序的 Order 实例
static Sort.Order by(String property)
创建默认方向的 Order 实例
static Sort.Order desc(String property)
创建降序的 Order 实例
Sort.Direction getDirection()
Sort.NullHandling getNullHandling()
String getProperty()
Sort.Order ignoreCase()
开启不分大小写排序
boolean isAscending()
返回此属性的排序是否要升序。
boolean isDescending()
返回此属性的排序是否应该降序。
boolean isIgnoreCase()
返回该排序是否区分大小写。
Sort.Order nullsFirst()
返回 Sort.Order 使用 Sort.NullHandling.NULLS_FIRST 作为空处理提示。First:第一个
Sort.Order nullsLast()
返回 Sort.Order 使用Sort.NullHandling.NULLS_LAST 作为空处理提示。Last:最后一个
Sort.Order nullsNative()
返回 Sort.Order 使用Sort.NullHandling.NATIVE 作为空处理提示。NATIVE:原生的
Sort.Order with(Sort.Direction direction)
创建 Order 实例.
Sort.Order with(Sort.NullHandling nullHandling)
创建 Order 实例.
Sort withProperties(String... properties)
创建 Order 实例.
Sort.Order withProperty(String property)
创建 Order 实例.

如果你还想全面了解它的使用,推荐阅读官方英文文档:https://docs.spring.io/spring…

五:分页

Pageable 只是 Spring Data 提供的分页信息的抽象接口。

实现类:

AbstractPageRequest:抽象类。供 PageRequestQPageRequest继承。

PageRequest:基本的可页面化 Java Bean 实现。

QPageRequest:基本的 Java Bean 实现,可以支持 QueryDSL。

分页功能也只需要一行代码:

Pageable pageable = new PageRequest(int page, int size, Sort sort);

page – 从零开始的索引页

size– 要返回的页面的大小

sort – 排序

你也可以创建没有排序的分页

PageRequest(int page, int size)

更方便的是可以一行代码创建有排序方向和属性的分页

PageRequest(int page, int size, Sort.Direction direction, String... properties)

如果你使用的是 2.0 以后的版本,官方已经弃用以上构造方法的形式,推荐使用静态方法:

修饰符和类型 方法和描述
static PageRequest of(int page, int size)
static PageRequest of(int page, int size, Sort.Direction direction, String... properties)
static PageRequest of(int page, int size, Sort sort)

比如我们想遍历整个数据表,就可以使用分页遍历,这样不至于一次把数据全部加载到内存。

修饰符和类型 方法和描述
Pageable first() 请求第一页。
Sort getSort() 返回排序参数。
Pageable next() 请求下一个页面。
PageRequest previous() 请求前一页。

注意:在使用 next() 方法时,不要把 pageable.next() 直接作为参数传入方法,如 repository.findAll(page.next()) 这样的写法会导致死循环。查看 next()方法的源码发现这个方法只是帮我们 new 了一个新的 Pageable 对象,原来的 pageable 还是没啥变化。一直 next()下去也只是在原地踏步。

    public Pageable next() {return new PageRequest(getPageNumber() + 1, getPageSize(), getSort());
    }

正确的写法:

repository.findAll(pageable = pageable.next());

六:使用

【本文版权归微信公众号 ” 代码艺术 ”(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】

Spring Data Jpa 除了会通过命名规范帮助我们扩展 Sql 语句外,还会帮助我们处理类型为 Pageable 的参数,将 pageable 参数转换成为 sql 语句中的条件,同时,还会帮助我们处理类型为 Page 的返回值,当发现返回值类型为Page,Spring Data Jpa 将会把数据的整体信息、当前数据的信息,分页的信息都放入到返回值中。这样,我们就能够方便的进行个性化的分页查询。

public interface UserRepository extends JpaRepository<User,Long> {

    @Override
    Page<Medical> findAll(Pageable pageable);
}

如果你想用 @Query 写原生查询语句并实现分页:

Spring Data JPA 目前不支持原生查询的动态排序,因为它必须操作声明的实际查询,这对于原生 SQL 是无法可靠地做到的。但是,您可以通过自己指定 count 查询来使用原生查询进行分页,如下面的示例所示:

public interface UserRepository extends JpaRepository<User, Long> {

  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

七:读取

分页查询:

Page<Book> sampleEntities = userRepository.findAll(pageable);

接口 Page 继承了接口Slice,话不多说,直接上干货!

总页数

int getTotalPages()

元素的总数

long getTotalElements()

返回当前页的索引(是第几页)

int    getNumber()

返回作为 List 的页面内容

List<T>    getContent()

返回当前在这个页上的元素的数量

int    getNumberOfElements()

返回用于请求当前页的Pageable

default Pageable    getPageable()

返回页的大小。

int    getSize()

返回页的排序参数。

Sort getSort()

页面是否有内容。

boolean    hasContent()

是否有下一页。

boolean    hasNext()

是否有上一页

boolean    hasPrevious()

当前页是否是第一个

boolean    isFirst()

当前页是否是最后一个

boolean    isLast()

下一页的 Pageable

Pageable nextPageable()

上一页的 Pageable

Pageable previousPageable()

关于 Spring Data 的排序与分页就到这里,记得点赞哦~~~

版权声明

【本文版权归微信公众号 ” 代码艺术 ”(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究。若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!】

退出移动版