Spring Data 提供了Pageable
类来支持分页查询,在服务层的实现中我们也提供了这样的接口,比如:
其中:
Pageable
接口是所有分页相关信息(如pageNumber
和pageSize
)的一个抽象,Spring Data JPA能够通过Pageable
参数来生成带分页信息的SQL语句Page
接口表示包含了分页信息的查询结果希望了解Spring Data JPA的同学可以参考Spring Data JPA入门。
有了分页查询方法的定义后,如何来使用呢?
首先需要实例化一个Pageable
对象。Pageable
定义了很多方法,但其核心的信息只有两个:
page
和size
)Spring Data提供了PageRequest
作为Pageable
的具体实现,我们直接实例化PageRequest
对象即可:
Sort sort = new Sort(Direction.DESC, "id");
Pageable pageable = new PageRequest(page, size, sort);
return blogService.findAll(pageable);
上面的代码通过参数获得分页的信息,并通过Sort
以及Direction
告诉Pageable
需要通过id
逆序排列。
第四课的分页例子中我们使用了subList
方法来返回分页数据:
实际上,可以直接调用BlogService
的findBlogs(Pageable pageable)
方法:
@Controller
@RequestMapping(value = "/blogs")
public class BlogController {
@Autowired BlogService blogService;
@GetMapping
public String getEntryByPageable(@RequestParam(value = "page", defaultValue = "0") Integer page, @RequestParam(value = "size", defaultValue = "15") Integer size, Model model) {
Sort sort = new Sort(Direction.DESC, "id");
Pageable pageable = new PageRequest(page, size, sort);
model.addAttribute("blogs", blogService.findBlogs(pageable));
return "list";
}
}
其实Spring MVC对分页提供了更强大的支持,我们可以进一步简化代码。只需要在Controller方法的参数中直接定义一个Pageble
类型的参数,Spring就会根据请求的参数来自动创建Pageable
对象。
@GetMapping
public String getEntryByPageable(@PageableDefault(value = 15, sort = { "id" }, direction = Sort.Direction.DESC) Pageable pageable, Model model) {
model.addAttribute("blogs", blogService.findBlogs(pageable));
return "list";
}
Spring支持的请求参数名如下:
page
:表示第几页,从0开始,默认为第0页
size
:表示每一页的大小,默认为20
sort
:排序相关的信息,以property,property(,ASC|DESC)
的方式组织,例如:
sort=firstname&sort=lastname,desc
表示在按firstname
正序排列基础上按lastname
倒序排列也就是只需要在浏览器端发送包含这些参数的请求,Controller就能够自动识别这些参数,并且生成Pageable
对象。
也可以为Pageable
参数设置一个默认配置,这样浏览器端的URL就可以更加简洁。Spring提供了@PageableDefault
进行个性化的设置Pageable
的默认配置。例如:
表示默认情况下按照id
倒序排列,每一页的大小为15
。
@PageableDefault
的属性包括:
page
size
value
,等同于size
sort
direction
如果将生成的Page<Blog>
对象以JSON字符串的形式(加@ResponseBody
即可)返回的话,输出结果看起来是这个样子:
{
"content":[
{"id":123,"title":"blog122","content":"this is blog content"},
{"id":122,"title":"blog121","content":"this is blog content"},
{"id":121,"title":"blog120","content":"this is blog content"},
{"id":120,"title":"blog119","content":"this is blog content"},
{"id":119,"title":"blog118","content":"this is blog content"},
{"id":118,"title":"blog117","content":"this is blog content"},
{"id":117,"title":"blog116","content":"this is blog content"},
{"id":116,"title":"blog115","content":"this is blog content"},
{"id":115,"title":"blog114","content":"this is blog content"},
{"id":114,"title":"blog113","content":"this is blog content"},
{"id":113,"title":"blog112","content":"this is blog content"},
{"id":112,"title":"blog111","content":"this is blog content"},
{"id":111,"title":"blog110","content":"this is blog content"},
{"id":110,"title":"blog109","content":"this is blog content"},
{"id":109,"title":"blog108","content":"this is blog content"}],
"last":false,
"totalPages":9,
"totalElements":123,
"size":15,
"number":0,
"first":true,
"sort":[{
"direction":"DESC",
"property":"id",
"ignoreCase":false,
"nullHandling":"NATIVE",
"ascending":false
}],
"numberOfElements":15
}
从中可以返回结果的信息:
接下来我们利用Spring MVC对分页的支持,来实现博客列表页面“下一页”的功能。
回顾前面的内容,已经在Controller中为Model增加blog
属性:
从blogs
的JSON表示可以知道,通过blogs.last
可以知道是否还有下一页,因为用th:unless
标签来控制“下一页”链接的使用:
<nav>
<ul class="pager">
<li class="previous"><a href="#"><span aria-hidden="true">←</span> 上一页</a></li>
<li th:unless="${blogs.last}" class="next"><a th:href="@{'/'+ ${user.name} + '?page=' + ${blogs.number + 1}}">下一页 <span aria-hidden="true">→</span></a></li>
</ul>
</nav>
在渲染URL时<a th:href="@{'/'+ ${user.name} + '?page=' + ${blogs.number + 1}}">
还用到了user
的信息,因此也需要在Controller中往Model中添加user
属性。
Page
和Pageable
对象Page
和Pageable
进行查询Pageble
对象Pageable
对象Page
对象渲染页面
登录发表评论 登录 注册
”下一页“ 按钮的超链接,有个bug,没有把当前session的size带过来,如果用户输入的size是5,点击一下”下一页“ 按钮, size变成了缺省的10,内容可能就不是用户想要的内容了,而且后续的"上一页","下一页"都是基于size的缺省值来走了。
<a th:href="@{'/'+ ${user.name} + '?page=' + ${blogs.number + 1}}">
应该改为
<a th:href="@{'/'+ ${user.name} + '?page=' + ${blogs.number + 1}+'&size=' + ${blogs.size}}"