最近在写一个博客系统,前端用的是vue,后端springboot框架,数据库用的是MySQL,后端dao层使用的是jdbcTemplate。
博客系统的展示页面需要进行分页,使用element-ui的分页组件:
<el-pagination
:page-size="20"
:pager-count="11"
layout="prev, pager, next"
:total="1000">
</el-pagination>
此时分页就有两种方法:前端分页和后端分页。
前端分页就是在加载当前页面时把所有数据从后端那拿到手,然后在前端实现分页。
后端分页是在后端先把数据处理好,再发给前端,前端只需要访问对应的页面拿相应页的数据即可。显然后端分页对于数据量大的web网页更为可行,于是我去查后端分页的写法,发现MyBatis和JPA都有现成的后端分页组件,唯独jdbcTemplate没有,于是我决定自己写一个(以实体Article为例):
首先创建PageList类,代表每一页:
public class PageList {
private int currentPage;//当前页
private int pageSize;//当前页的数据量
private int articleNumber;//总数据量
private List<Article> articleList=new ArrayList<Article>();//这一页的全部article数据
private int pageNumber;//总页数
public PageList(int currentPage,int pageSize){
this.currentPage=currentPage;
this.pageSize=pageSize;
pageNumber=(articleNumber%pageSize==0?(articleNumber/pageSize):(articleNumber/pageSize+1));
}
}
get和set我就省略了。前端请求后端的分页数据主要是这里的articleNumber和articleList,注意这里的pageNumber总页数计算逻辑。
然后写dao层:
public PageList getArticlesByPage(int currentPage,int pageSize){
PageList pageList=new PageList(currentPage,pageSize);
pageList.setArticleNumber(jdbcTemplate.queryForObject("SELECT count(id) FROM article",Integer.class));
/*pageList.setPageNumber();*/
if(pageList.getCurrentPage()==pageList.getPageNumber()){
pageList.setArticleList(jdbcTemplate.query("SELECT * FROM article limit ?,?",new BeanPropertyRowMapper<>(Article.class),(currentPage-1)*pageSize,pageList.getArticleNumber()-(currentPage-1)*pageSize-1));
}else{
pageList.setArticleList(jdbcTemplate.query("SELECT * FROM article limit ?,?",new BeanPropertyRowMapper<>(Article.class),(currentPage-1)*pageSize,pageSize));
}
return pageList;
}
这里用到了MySQL的特有语法,查询第n行到m行数据:
select * from table_name limit n-1 m-n;
用(currentPage-1)*pageSize表示之前有多少数据,即n-1。判断是否是最后一页,如果是的话就是计算第n行到最后一行的数据;不是的话就是计算第n行开始,一共pageSize行的数据。
最后就是写controller:
@CrossOrigin
@GetMapping("/api/article/{size}/{page}")
public PageList articlePageList(@PathVariable("size") int size,@PathVariable("page") int page){
return articleService.getArticlesByPage(page,size);
}
前端根据GetMapping的路径构建参数表示对应路径拿数据即可,比方说一页有4篇文章(vue变量pageSize为4),是第一页,前端就可以写成:
this.$axios.get('/api/article/'+this.pageSize+'/1')