Spring 分页接口
网页数据一页一页加载,然后展示,然后加载在展示,或是无限下来虽然感觉不到,当也确确实实的分页了,spring 全家桶做做 Web 开发,分页是少不了的功能,有的话当然是能用就用。
类的限定名称
- org.springframework.data.domain.Page
- org.springframework.data.domain.PageImpl
- org.springframework.data.domain.Pageable
- org.springframework.data.domain.Sort
- org.springframework.data.domain.Slice
- org.springframework.data.domain.SliceImpl
- org.springframework.data.web.SortDefault
- org.springframework.data.web.PageableDefault
- org.springframework.data.repository.Repository
输入接口 Pageable
Pageable 作为输入参数,包括了页码、页面大小、排序规则信息,这个是一个接口,包含在Spring Data Commons
包里面,如果开发的软件引入了Spring Data
中随便哪一个组件都会带入这个接口。
interface Pageable {
val pageNumber: Int
val pageSize: Int
val sort: Sort?
}
Sort 作为另外一个接口包括了多个排序字段、升序降序信息。
Pageable是接口类型,不能实例化,通常用PageRequest新建:
val pageable = PageRequest.of(
0, 5, Sort.by(
Sort.Order.asc("name"),
Sort.Order.desc("id")
)
)
输出接口 Page 和 Slice
Page 和 Slice 和前面的 Pageable 都是接口,非常的符合 Java 面向接口编程的味道,Page 继承了 Slice,通常这两个是在输入参数里面存在 Pageable 的时候,作为返回值返回。
Slice 结构
interface Slice<T> : Streamable<T> {
val number: Int
val size: Int
val numberOfElements: Int
val content: List<T>?
val sort: Sort?
// 其他方法和字段
}
Page结构
Page 对比 Slice 多出了总页数和总元素数量这两个字段。
interface Page<T> : Slice<T> {
val totalPages: Int
val totalElements: Long
// 其他方法和字段
}
PageImpl 是 Page 接口的常用实现,同样 Slice 接口对应的实现是 SliceImpl。
val ret = PageImpl(listOf(1,2,3,4,5))
在控制层获取分页输入参数
Pageable 是接口,如果使用的是 SpringMVC,直接作为 Controller Handler 参数并不能自动注入,直接调用会出现下面异常:
java.lang.NoSuchMethodException: org.springframework.data.domain.Pageable.<init>()
java.lang.NoSuchMethodException: org.springframework.data.domain.Sort.<init>()
需要使用配置注解 @EnableSpringDataWebSupport 开启相应的功能,使用这个注解会加载 PageableHandlerMethodArgumentResolver 和 SortHandlerMethodArgumentResolver 这两个解析器,从请求参数里面解析 Pageable 参数,并调用自带实现。如果是 SpringBoot,这一切都已经做好了,直接使用即可。
@Configuration
@EnableSpringDataWebSupport
class PaginationConfiguration {
}
自定义分页参数
全局分页参数
spring.data.web.pageable.size-parameter=size
spring.data.web.pageable.page-parameter=page
spring.data.web.pageable.default-page-size=20
spring.data.web.pageable.one-indexed-parameters=false
spring.data.web.pageable.max-page-size=2000
spring.data.web.pageable.prefix=
spring.data.web.pageable.qualifier-delimiter=_
参数 | 默认值 | 说明 |
---|---|---|
size-parameter | size | 分页大小变量名称 |
page-parameter | page | 分页页面变量名称 |
default-page-size | 20 | 默认每页数量 |
one-indexed-parameters | false | 页码从0开始还是从1开始 |
max-page-size | 2000 | 每页最大数量 |
prefix | page和size参数前缀(不包括sort) | |
qualifier-delimiter | _ | 分隔符 |
如果 one-indexed-parameters 设置为 true,默认页码将从 1 开始,否则从 0 开始。@Qualifier 注解可以给分页输入参数添加一个类似命名空间的东西,qualifier-delimiter 表示分割这个前缀的分隔符。
fun books(@Qualifier("book") p:Pageable){
}
qualifier-delimiter 默认值为 "_" 的情况下,只有 book_size / book_page / book_sort 能给正确读取。
这些参数最终会应用于 PageableHandlerMethodArgumentResolverSupport 这个类。
局部分页参数
@PageableDefault 用于设定页码和大小,@SortDefault 用于设定排序规则,@SortDefault.SortDefaults 组合多个排序规则。
fun books(
@PageableDefault(page = 0, size = 100)
@SortDefault.SortDefaults(
SortDefault(sort = ["name"], direction = Sort.Direction.ASC),
SortDefault(sort = ["id"], direction = Sort.Direction.DESC)
)
p: Pageable
) {
}
DataRepository 分页支持
Spring Data Repository 是 Spring Data 数据对象持久化的抽象层,通过这个逻辑分层可以屏蔽底层数据库差异,常用的驱动都附带 Crud 功能实现。这一部分包括接口 Repository ,和继承的Repository 的 CrudRepository 接口,还有 CrudRepository 在之上的 PagingAndSortingRepository 接口。
将 Pageable 作为方法调用参数传递,系统将会自动处理分页,根据接口方法返回类型是 List / Slice / Page 中的哪一个,如果是 Page 类型会多出一次查询,查询符合要求数据总的数量,其余的将会自动封装返回,Slice 和 Page 对比 List 会附带 Pageable 参数。同样对于 Page / Slice 返回类型,Pageable 参数是必须的,如果缺少会抛出异常。如果不需要分页,只需要排序,单独传递 Sort 对象即可。
interface BookRepository : Repository<Book, Int> {
fun findByName(name: String, p: Pageable): Page<Book>
}