JavaWeb 分页实现

一·数据库的分页实现

看一下数据库里有多少记录:

select count(*) from tbl_student limit 0,3;

JavaWeb 分页实现
mysql分页是通过limit,实现的:
从第0条开始取3条。从第三条开始取3条。

select stu_no,stu_name,stu_mark from tbl_student limit 0,3;
select stu_no,stu_name,stu_mark from tbl_student limit 3,3;

JavaWeb 分页实现

从第6条开始取3条:
JavaWeb 分页实现

二·页面

在utils包下新建类Page和PageTest,内容如下:
JavaWeb 分页实现

在utils包下新建的类Page,内容如下:

package edu.mju.stuwork.utils;

import java.util.Collection;


public class Page {
	
    private Integer pageNo;    //当前页号     *
    private Integer pageSize;  //每页记录条数  *
    private Boolean nextPage;  //是否有下一页
    private Boolean prePage;   //是否有上一页
    private Long totalRecNum;  //总共有多少条记录 (页面相关联的查询,总共有多少条记录)*
    private Integer totalPageNum;//总共多少页 
    private Collection pageContent; //该页的数据(记录明细) *
    private Integer startIndex; //记录开始位置
    private Integer endIndex;   //记录结束位置
        
	public Page() {
		super();
        pageNo=1;
        pageSize=3;
	}
	
	public Integer getPageNo() {
		return pageNo;
	}
	public void setPageNo(Integer pageNo) {
		this.pageNo = pageNo;
	}
	public Integer getPageSize() {
		return pageSize;
	}
	public void setPageSize(Integer pageSize) {
		this.pageSize = pageSize;
	}
	
	public Boolean getNextPage() {
		return pageNo<getTotalPageNum()?true:false;
	}

	public Boolean getPrePage() {
		return pageNo>1?true:false;
	}

	public Long getTotalRecNum() {
		return totalRecNum;
	}
	public void setTotalRecNum(Long totalRecNum) {
		this.totalRecNum = totalRecNum;
	}
	
	public Integer getTotalPageNum() {
		return totalRecNum%pageSize>0?(int)(totalRecNum/pageSize+1):(int)(totalRecNum/pageSize);
	}

	public Collection getPageContent() {
		return pageContent;
	}
	
	public void setPageContent(Collection pageContent) {
		this.pageContent = pageContent;
	}
    
	public int getStartIndex()
	{
		return pageSize*(pageNo-1);  // size:10 pageno:3   21
	}
    
	public int getEndIndex()
	{
		return (pageSize*pageNo>this.totalRecNum)? (int)(this.totalRecNum.longValue()):(pageSize*pageNo);
	}

	@Override
	public String toString() {
		return "Page [pageNo=" + pageNo + ", pageSize=" + pageSize + ", nextPage=" + nextPage + ", prePage=" + prePage
				+ ", totalRecNum=" + totalRecNum + ", totalPageNum=" + totalPageNum + ", pageContent=" + pageContent
				+ ", startIndex=" + startIndex + ", endIndex=" + endIndex + "]";
	}
	
	

}

在utils包下新建的类PageTest,内容如下:

package edu.mju.stuwork.utils;


public class PageTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		Page page=new Page();
		
		page.setTotalRecNum(102L);
		page.setPageSize(10);
		
		System.out.println(page.getTotalPageNum());

		page.setPageNo(11);
		
		System.out.println(page.getStartIndex()+"-"+page.getEndIndex());
		
		System.out.println(page.getNextPage());
		System.out.println(page.getPrePage());		

	}

}

百度“福州”,结果是一个列表,是一个记录集。记录不一定以横条的形式出现,他可以以各种形式出现,
JavaWeb 分页实现
这就是一条记录了:
JavaWeb 分页实现
三个字段:图片,城市名称,以及说明。
JavaWeb 分页实现
有第一页第二页第三页,是一个页面。可以说是一个记录的显示列表,也可以说是一个页面对象,记录集只是页面的一个属性而已。Page类代表用户所看到的一切。

Page类的情况:

private Integer pageNo;    //当前页号     
private Integer pageSize;  //每页记录条数  (页面规模)

有两个Boolen,分别判断有没有上一页,下一页:

private Boolean nextPage;  //是否有下一页
private Boolean prePage;   //是否有上一页

这个页面所属的查询总共有多少条记录:

private Long totalRecNum;  //总共有多少条记录 (页面相关联的查询,总共有多少条记录)

有多少页面:

private Integer totalPageNum;//总共多少页 

这个页面的数据,就是我们的查询结果:

private Collection pageContent; //该页的数据(记录明细) 

页面的开始结束范围:

private Integer startIndex; //记录开始位置
private Integer endIndex;   //记录结束位置

mysql可能不需要开始和结束范围。

开始访问页面时,new一个Page时,默认值是访问第一页,每页的记录条数默认为3条:

public Page() {
	super();
    pageNo=1;
    pageSize=3;
}

可以设置页号和获得页号:

public Integer getPageNo() {
	return pageNo;
}
public void setPageNo(Integer pageNo) {
	this.pageNo = pageNo;
}

设置页面规模和取得页面规模:

public Integer getPageSize() {
	return pageSize;
}
public void setPageSize(Integer pageSize) {
	this.pageSize = pageSize;
}

获得下一页:
如果当前的页号比总页数来的小,就一定有下一页。

public Boolean getNextPage() {
	return pageNo<getTotalPageNum()?true:false;
}

有上一页吗?:
如果当前的页号大于1,那就有。否则没有:

public Boolean getPrePage() {
	return pageNo>1?true:false;
}

总共多少条记录,由外面传入:

public void setTotalRecNum(Long totalRecNum) {
	this.totalRecNum = totalRecNum;
}

总共多少页:
把”当前的总记录条数“取模”页面规模“大于0,那么应该在整数除法的基础上加一,5条记录,每页3条,5%3>0,5/3要加一。6%3=0,6/3=2就不用。

public Integer getTotalPageNum() {
	return totalRecNum%pageSize>0?(int)(totalRecNum/pageSize+1):(int)(totalRecNum/pageSize);
}

获得开始位置:
第一页就是0,第二页就是3.

public int getStartIndex()
{
	return pageSize*(pageNo-1);  // size:10 pageno:3   21
}

获得结束的位置:
如果页面规模乘以页号,比总的记录条数还多,说明有空余。返回总记录条数就可以了。如果不是,说明页面充满,返回页面规模乘以页号。

public int getEndIndex()
{
	return (pageSize*pageNo>this.totalRecNum)? (int)(this.totalRecNum.longValue()):(pageSize*pageNo);
}

如何满足这个Page?只要四个属性有值,其他的属性都有值。

private Integer pageNo;    //当前页号     *
private Integer pageSize;  //每页记录条数  *
private Long totalRecNum;  //总共有多少条记录 (页面相关联的查询,总共有多少条记录)*
private Collection pageContent; //该页的数据(记录明细) *

测试:
就是刚才的PageTest:

package edu.mju.stuwork.utils;


public class PageTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
//		新建一个页面
		Page page=new Page();
//		设置总记录条数为102条,页面规模是10
		page.setTotalRecNum(102L);
		page.setPageSize(10);
//		输出总共有多少页
		System.out.println(page.getTotalPageNum());
//		设置页号为11
		page.setPageNo(11);
//		输出第11页的记录范围是多少
		System.out.println(page.getStartIndex()+"-"+page.getEndIndex());
//		是否有上一页,下一页
		System.out.println(page.getNextPage());
		System.out.println(page.getPrePage());		

	}

}

Run As JavaApplication

JavaWeb 分页实现
102条记录,每页10条,总共11页。设置为第11页的话,记录范围是100-102.还有上一页吗?有。还有下一页吗?没有。

根据前面所说,我们需要4个数据才能把Page准备好。pageNo和pageSize是默认就有了。totalRecNum和pageContent需要我们手动获取。

三·获取页面所需数据

1·统计有多少条记录

来到StudentDao:
根据这个条件,告诉我有多少条记录。
添加:

   long cntStusByCondition(StudentQryHelper helper);

JavaWeb 分页实现
来到StudentMapper书写映射:
totalCnt是别名
添加:

   <select id="cntStusByCondition"  parameterType="edu.mju.stuwork.service.StudentQryHelper" resultType="long">
      select count(*) totalCnt
      from tbl_student 
      <trim prefix="WHERE " prefixOverrides="AND |OR ">
	      <if test="qryStuName != null">
	        and stu_name like concat('%','${qryStuName}','%') 
	      </if>
	      <if test="qryBeginMark != null">
	        and stu_mark >= #{qryBeginMark}
	      </if>
	      <if test="qryEndMark != null">
	        and stu_mark &lt;= #{qryEndMark}
	      </if>    
      </trim>      
   </select>

回到Dao:
现在的条件不止一个,有三个。
添加:

List<Student> loadScopedStusByCondition(StudentQryHelper helper,int beginIdx, int pageSize);

回到StudentMapper:
如果这样写:
JavaWeb 分页实现
那么现在参数类型应该写什么呢?
如果写参数类型的话只有一个参数,但是我们有三个参数。如果参数类型继续写“edu.mju.stuwork.service.StudentQryHelper”,那前三个是可以的,那后面用蓝色框起来的两个应该怎么办呢?我们指定了一个参数类型,那么剩下还有两个参数没办法指定,因为一次只能指定一个参数类型。有一种做法是将三个参数分装到一个Map里,在Dao的方法中只传Map:
JavaWeb 分页实现
到时候就是aaa.begin这样。
但是可读性不够,

Mybatis提供了使用注解来完成的方法,
来到StudentDao,添加:

List<Student> loadScopedStusByCondition(@Param("helper") StudentQryHelper helper, 
		                                @Param("begin") int beginIdx, 
		                                @Param("size") int pageSize);

JavaWeb 分页实现

@Param("helper") StudentQryHelper helper表示:”StudentQryHelper helper“这个参数在Mybatis映射文件中就叫helper。

上面的Param就是Mybatis的Param了:
JavaWeb 分页实现
在StudentMapper中修改“loadScopedStusByCondition”如下:

<select id="loadScopedStusByCondition" resultType="Student">
	select *
	from tbl_student
	<trim prefix="WHERE " prefixOverrides="AND |OR ">
		<if test="helper.qryStuName != null">
			and stu_name like concat('%',#{helper.qryStuName},'%')
		</if>
		<if test="helper.qryBeginMark != null">
			and stu_mark >= #{helper.qryBeginMark}
		</if>
		<if test="helper.qryEndMark != null">
			and stu_mark &lt;= #{helper.qryEndMark}
		</if>
	</trim>
	order by stu_no desc
	limit #{begin},#{size}
</select>

JavaWeb 分页实现
来到StudentService:

添加:

/**
 * 获得一个基于某种查询的页面
 * @param helper
 * @param page
 * @return
 */
Page loadPagedStus(StudentQryHelper helper, Page page);

JavaWeb 分页实现
helper是查询条件,page是初始页面,将初始页面传进去之后会把填充好数据的页面传出来。

来到StudentServiceImpl:
添加:

public Page loadPagedStus(StudentQryHelper helper, Page page) {//进来的page的“pageNo”和“pageSize”是有值的,现在我们要给他提供:1·在这样的查询条件下,有多少条记录,2·在这样的查询条件下,查询的结果是什么

		
		page.setTotalRecNum(stuDao.cntStusByCondition(helper));
		page.setPageContent(stuDao.loadScopedStusByCondition(helper, page.getStartIndex(), page.getPageSize()));
		
		return page;
	
}

返回一个装满数据的Page。

来到StudentController:
修改:
原来:
JavaWeb 分页实现
现在:
JavaWeb 分页实现

	@GetMapping("/students")
	public String loadStus(Model model,StudentQryHelper helper,Page page) throws Exception {
		
//		if (helper.getQryStuName()!=null && helper.getQryStuName().isEmpty()) {
//			System.out.println("dfknkdfnkjdfnkd");
//		}

		if (org.apache.commons.lang3.StringUtils.isBlank(helper.getQryStuName())) {//使用lang3包的方法,做一个空串的检测
			helper.setQryStuName(null);//使空串成为null,使下面的模糊查询不加上“%”,并使StudentMapper的动态sql语句不再添加相关部分的语句。
		}
		

		page= stuService.loadPagedStus(helper, page);

		 以key/value键值对形式保存到模型,其实就是保存到request范围(请求范围)
		model.addAttribute("page", page);
		
		model.addAttribute("helper",helper);
		

		return "list_student";// 去到页面,叫list_student

	}

来到list_student,
修改:
将原来stuList请求范围改为page.pageContent:
JavaWeb 分页实现

测试:
JavaWeb 分页实现
看一下SQL:
JavaWeb 分页实现

那第二页呢?
将网址改成http://localhost:8080/stuinfo/students?pageNo=2:
JavaWeb 分页实现
如果写“?pageNo=2”,那学生控制器里的page就从默认值1,改成了2,在下面取值时自然就会算好:
JavaWeb 分页实现
来到mysql看看:
JavaWeb 分页实现
确实是应该是第二页的内容。

但是,这样要让用户输入网址,就不合理。
添加,翻页按钮,现在只显示了pageNo的一个属性pageNo,还有有没有上一页下一页,总共多少条记录,这些还没显示出来。

来到list_student:
添加:

	<!-- 页面情况信息 -->
   <div class="col-12 text-right"><!-- 占满一行,文字右对齐 -->
           共${page.totalRecNum}条, 当前显示${page.startIndex+1}-${page.endIndex}条, 第${page.pageNo}/${page.totalPageNum}页
        |<!-- 共有多少条记录,当前显示第几条到第几条。因为失从0开始,所以当前显示范围的开始加1。当前是第几页,总共多少页 -->
       <c:if test="${page.pageNo>1}"><!-- jstl+EL  测试:如果page的页号大于一,就显示这个按钮 -->
         <button class="btn btn-sm btn-outline-info" onclick="doQuery(1)">首页</button>&nbsp;
       </c:if>
       <c:if test="${page.prePage}"><!-- 如果page有上一页,就显示“上一页”按钮 -->
         <button class="btn btn-sm btn-outline-info" onclick="doQuery(${page.pageNo-1})">上一页</button>&nbsp;
       </c:if>
       <c:if test="${page.nextPage}"><!-- 如果page有下一页,就显示“下一页”按钮 -->
         <button class="btn btn-sm btn-outline-info" onclick="doQuery(${page.pageNo+1})">下一页</button>&nbsp;
       </c:if>
       <c:if test="${page.pageNo!=page.totalPageNum}"><!-- 如果page的页号不等于最后一页,就把末页的按钮放下去 -->
         <button class="btn btn-sm btn-outline-info" onclick="doQuery(${page.totalPageNum})">末页</button>&nbsp;
       </c:if>
       |
                  到&nbsp;<input type="text" class="text-center" id="pageNo" size=4 style="text-align:right;"/>&nbsp;页
       <button class="btn btn-sm btn-success" onclick="doQuery(parseInt($('#pageNo').val()));"> 跳 转 </button>	
    </div>

效果:
JavaWeb 分页实现

JavaWeb 分页实现
相当于把page的信息全部都取出来了。

所谓的分页是基于上面查询框的查询条件的分页,在查询框查找姓“张”的学生,然后点击下一页,就是查询姓“张”的同学的下一页。

当点击“下一页”时,在查询表单中偷偷添加条件pageNo=当前页号加一。然后通过js提交表单。

添加函数doQuery:当首页时是doQuery(1)

在list_student的script添加:

//查询第几页
function doQuery(pageNo){	    
	
   if(pageNo<1 || pageNo>${page.totalPageNum})/* 页号小于一,或是页号大于总页数 */
    {
       alert('页号超出范围,有效范围:[1-${page.totalPageNum}]!');/* 提示页号超出有效范围,有效范围是多少 */
       $('#pageNo').select();
       return;
    }
    else
    {
         document.forms['stuQryFrm'].pageNo.value=''+pageNo;
         document.forms['stuQryFrm'].submit();
    }
   
}

给form一个name,用于定位:
JavaWeb 分页实现
测试:
报错:
JavaWeb 分页实现
添加隐含域:

<input type="hidden" name="pageNo" value="1"/>

JavaWeb 分页实现
测试:
JavaWeb 分页实现
JavaWeb 分页实现
可以添加nbsp,加点间隔:
JavaWeb 分页实现
取得上面pageNo的值,将其转成整数,传给doQuery:
JavaWeb 分页实现
输错了默认选中,方便修改:
JavaWeb 分页实现

JavaWeb 分页实现

上一篇:java list实现分页


下一篇:笔记本使用HDMI连接显示器没反应