需求:
如京东的所有评论功能,是先加载一页数据(比如说10条评论),当手机浏览器下滑到底时,再加载下一页数据,直到无数据加载。
技术实现:
前端:
如果判断浏览器下滑到底了呢?
$(document).off('scroll');
$(document).on({
'scroll': function(e) {
if ($(window).scrollTop() + $(window).height() == $(document).height()) {
query(No, ListPage++, PageSize);
}
}
});
后端:
Controller
获取到No,page以及pageSize,就要返回给前端分页数据了。
关键问题是如何通过传过去的page及pageSize就能获取分页数据呢?
分页中涉及到的实体包括:
总页数
总记录数
当前页
每页显示条数
1. 总页数如何计算
其中总页数=总页数/每页显示条数,还要判断是否有余数
在sql语句中就是用limit ?,? 来实现,其中第一个?代表起始行,从0开始;第二个?代表每页显示条数。
第一个?也是可以计算的,起始行号=(当前页Page-1)*pageSize+1
第二个?就是pageSize
2. 总记录数如何计算
由于是通过PreparedStatement进行执行的,通过ResultSet来获取总记录条数
具体执行过程:
类PageResultSet,代表页集信息
public class PageResultSet<T> {
public final static int PAGESIZE = 10;
private int recordNum;
private int curPage;
private int startRow;
private int rowNum;
private int pageSize;
public int getAllPage() {
int allPage = recordNum / pageSize;
if (recordNum % pageSize != 0) allPage++;
if (allPage == 0) allPage = 1;
return allPage;
}
public int getEndRow() {
int endRow = startRow + pageSize - 1;
if (endRow > recordNum) endRow = recordNum;
return endRow;
}
public int getNextPage() {
if (curPage >= getAllPage()) return getAllPage();
else return curPage + 1;
}
public int getBackPage() {
if (curPage <= 1) return 1;
else return curPage - 1;
}
}
dao中获取页集信息的代码
pageResultSet = pageDao.pageResultSet(pageSize,sql.toString(), jdbcTemplate, rag.toArray(), new RowCallbackHandler() {
@Override
public void processRow(ResultSet rs) throws SQLException {
GoodsComment info = new GoodsComment();
//user_portrait暂时没有
//NICK-name
String nickName = rs.getString("NICK_NAME");
//脱敏
info.setUserName(nickName.substring(0, 1)+"***"+nickName.substring(nickName.length()-1,nickName
.length()));
//assess-date
info.setCommentTime(rs.getString("COMMENT_TIME"));
//comment-item-star
info.setStarLevel(String.valueOf(rs.getInt("STAR_LEVEL")));
//assess-content
info.setContentDesc(rs.getString("CONTENT_DESC"));
//pay-date
info.setOrderDate(rs.getString("ORDER_DATE"));
pageList.add(info);
}
});
pageResultSet方法
prs.setPageSize(pageSize);
//起始行号
int l_srow = (prs.getCurPage() - 1) * prs.getPageSize()+ 1;
Connection con=null;
PreparedStatement pstmt=null;
try {
con=template.getDataSource().getConnection();
pstmt=con.prepareStatement(l_sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
//设置fetchSize
pstmt.setFetchSize(prs.getPageSize());
if(arg==null)
{
//prs.setRecordNum(template.queryForInt(countSql));
}
else
{
for(int i=0;i<arg.length;i++)
{
Object o=arg[i];
if(o==null)
{
System.out.println("参数为空-------------------------");
throw new DbException("分页时,无效参数异常:");
}
if(String.class==o.getClass())
{
pstmt.setString(i+1,(String)o);
}
else if(Integer.class==o.getClass())
{
pstmt.setInt(i+1,((Integer)o).intValue());
}
else if(Long.class==o.getClass())
{
pstmt.setInt(i+1,((Long)o).intValue());
}
else
{
throw new DbException("分页时,参数类型不对异常:");
}
}
}
//执行
ResultSet rs=pstmt.executeQuery();
rs.last();
//设置总记录条数
prs.setRecordNum(rs.getRow());
if (l_srow > prs.getRecordNum())
{
l_srow = (prs.getAllPage() - 1) * prs.getPageSize() + 1;
prs.setCurPage(prs.getAllPage());
}
if(l_srow==1)//第一页
{
rs.beforeFirst();
}
else
{
//移动游标到指定行号 通mysql limit 0,pageSize,所以行号减一
rs.absolute(l_srow-1);
}
int i=0;
while(rs.next()&&i<prs.getPageSize())
{
i++;
//调用dao中override的processRow方法 将一行一行的数据填数据到rs中
this.processRow(handler,rs);
}
rs.close();
} catch (DataAccessException e) {
e.printStackTrace();
throw new DbException("分页时异常:"+e.getMessage());
}
catch (SQLException e) {
e.printStackTrace();
throw new DbException("分页时异常:"+e.getMessage());
}
finally
{
try {
pstmt.close();
con.close();
} catch (SQLException e) {
}
}
return prs;
总结来说:
使用了preparedStatement来执行分页查询,通过移动其游标来方便的执行分页查询。
如通过rs.getRow()方法来获取总行数,通过rs.absolute()方法移动游标到指定行号等。与使用limitrowNo,pageSize本质上是相同的