文章目录
十六、书城项目第五阶段——分页
001-图书分页
A. 分页模块的分析
希望对上面的后台图书管理进行分页显示,就像是首页index.jsp一样
分页要达到的效果:每页显示四条数据 和 分页条
即如下效果:
首页的样子如下:
客户端进行传递就是下面这样:百度分页数量设置:
B. 分页模型 Page 的抽取(当前页数,总页数,总记录数,当前页数据,每页记录数)
在bean package中 创建Page类:
package com.atguigu.bean;
import java.util.List;
/**
* Page 是分页的模型类(对象)
* @param <T> 如果用户模块需要分页,那就是每页就是用户数据;如果是图书模块需要分页,那么每页就是图书数据。所以使用泛型。
*/
public class Page<T> {
//固定设定一页4条数据,设置为常量
public static final Integer PAGE_SIZE = 4;
// 当前页码
private Integer pageNo;
// 总页码
private Integer pageTotal;
// 当前页显示数量(一页显示的数据条数)
private Integer pageSize = PAGE_SIZE;
// 总记录数
private Integer pageTotalCount;
// 当前页数据(当前页的所有数据对象)
private List<T> items;
public Page() {
}
public Page(Integer pageNo, Integer pageTotal, Integer pageSize, Integer pageTotalCount, List<T> items) {
this.pageNo = pageNo;
this.pageTotal = pageTotal;
this.pageSize = pageSize;
this.pageTotalCount = pageTotalCount;
this.items = items;
}
public Integer getPageNo() {
return pageNo;
}
public void setPageNo(Integer pageNo) {
this.pageNo = pageNo;
}
public Integer getPageTotal() {
return pageTotal;
}
public void setPageTotal(Integer pageTotal) {
this.pageTotal = pageTotal;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getPageTotalCount() {
return pageTotalCount;
}
public void setPageTotalCount(Integer pageTotalCount) {
this.pageTotalCount = pageTotalCount;
}
public List<T> getItems() {
return items;
}
public void setItems(List<T> items) {
this.items = items;
}
@Override
public String toString() {
return "Page{" +
"pageNo=" + pageNo +
", pageTotal=" + pageTotal +
", pageSize=" + pageSize +
", pageTotalCount=" + pageTotalCount +
", items=" + items +
'}';
}
}
C. 分页的初步实现
BookServlet中添加page()方法:
点击“图书管理”,就要实现上面的分页效果:
所以要将 表示“图书管理”的 a标签 的 action=list 改为action=page
即修改manager_menu.jsp:
修改book_manager.jsp:
将requestScope.books改为 —> requestScope.page.items
以前遍历 books ,现在遍历 page.items
BookService中添加page()方法:
BookServiceImpl中实现page()方法:
@Override
//处理分页(给每一个Page对象设置它的五个属性)
public Page<Book> page(int pageNo, int pageSize) {
//五个属性:pageNo, pageTotal, pageSize, pageTotalCount, items
Page<Book> page = new Page<Book>();
// 设置当前页码
page.setPageNo(pageNo);
// 设置每页显示的数量
page.setPageSize(pageSize);
// 求总记录数
Integer pageTotalCount = bookDao.queryForPageTotalCount();
// 设置总记录数
page.setPageTotalCount(pageTotalCount);
// 求总页码
Integer pageTotal = pageTotalCount / pageSize;
if (pageTotalCount % pageSize > 0) {
pageTotal+=1;
}
// 设置总页码
page.setPageTotal(pageTotal);
// 求当前页数据的开始索引
int begin = (page.getPageNo() - 1) * pageSize;
// 求当前页数据
List<Book> items = bookDao.queryForPageItems(begin,pageSize);
// 设置当前页数据
page.setItems(items);
return page;
}
BookDao中添加两个方法:
queryForPageTotalCount()
queryForPageItems(int begin, int pageSize)
BookDaoImpl中实现上面的两个方法:
测试BookDaoImpl中的
queryForPageTotalCount()和queryForPageItems(int begin, int pageSize)方法:
在BookDaoImplTest中写如下代码:
测试BookServiceImpl中的page()方法:
在BookServiceImplTest中写如下代码:
测试BookServlet中的page()方法:
在以上页面点击图书管理后,出现分页效果,如下图:
上面这个页面还缺少分页条(与主页面index.jsp中的相同),在book_manager.jsp中做如下添加:
将当前页码,总页数,总记录条数实现一下:
D. 首页、上一页、下一页、末页实现
首页:pageNo = 1
上一页:pageNo - 1
下一页:pageNo + 1
末页:pageNo = pageTotal
在book_manager.jsp中做如下修改:
注意:程序运行之后,点击上一页,下一页,首页,末页,控制台会出现NumberFormatException异常,但并不影响程序运行。
出现NumberFormatException异常原因:
点击图书管理之后,最开始并没有page对象
所以BookServlet中的page()方法的
req.getParameter("pageNo")
req.getParameter("pageSize")
都获取不到参数,所以导致WebUtils.parseInt()方法的第一个参数为空
只能取默认值
点击上一页,下一页,首页,末页还是会出现这个异常是因为:
req.getParameter("pageSize")一直获取不到,只能取默认值
如果不想控制台出现这个异常,可以将WebUtils的parseInt()方法改写如下(也可以不改):
if (strInt == null){
return defaultValue;
}else {
return Integer.parseInt(strInt);
}
也可以把原来的方法中的 e.printStackTrace();注释掉
E. 分页模块中跳转到指定页数功能实现
实现如上图功能
给确定按钮绑上单击事件:
上面写的还有些问题:
首先 location.href 中 不能使用localhost,访问的是你自己的电脑
要改为动态的:
在head.jsp中 加入一行代码:
修改 location.href :
第二个问题:输入的页数可能小于1,也可能大于最大页数
先对前台的代码进行修改
修改book_manager.jsp:
还要提供服务器的校验:
因为懂行的人会在地址栏直接修改,越过前台校验。
在BookServiceImpl的page方法中添加校验:
因为很多功能都会用到这个校验,所以将这个校验放在Page类的setPageNo方法里:
注意:在BookServiceImpl中,要将page.setPageNo()方法放在page.setPageTotal()方法之后,否则会出现pageTotal为空的情况。
如果在输入框中输入小数,会一直跳转到第一页:
因为WebUtils的parseInt()方法中的
Integer.parseInt(参数1,参数2)方法是将字符串转换为int类型
将字符串参数1转换为十进制int类型,而参数2表示字符串参数1原本是几进制
输入小数字符串,会显示NumberFormatException,那么就会取默认值1。
F. 分页模块中,页码 1,2,【3】,4,5 的显示,要显示 5 个页码,并且页码可以点击跳转。
为了与上面的情况相符,t_book中只保留20条数据。
为了出现总页码数大于5的情况,每页只显示2条数据——>修改page类的PAGE_SIZE = 2;
修改book_manager.jsp:
G. 修改分页后,增加,删除,修改图书信息的回显页面
使用分页之后,添加图书,修改图书,删除图书都出现了一些问题,进行修改。
点击添加图书,提交之后,显示空白,因为此时 action=list 不是分页
所以将BookServlet中 action=list 改为 action=page
点击添加图书,点击提交之后,回到图书列表页面,但是不在最后一页(看不到添加的结果)
实现 点击提交之后,直接到最后一页:
修改book_manager.jsp:
修改book_edit.jsp:
修改BookServlet的add方法:
考虑到每页显示两条记录,如果共10页,再添加一条记录就到了11页的情况:
让pageNo + 1
假设总页数为10页,第10页只有一条数据,那么增加一条数据之后
总页数还是10,但是BookServlet的pageNo为11,
此时pageNo > pageTotal ---> pageNo = pageTotal
所以虽然地址栏中pageNo=11 但是显示的是第10页
(地址栏pageNo=11这个问题我不知道怎么解决,
但是重新运行之后看这些页面就没有这个问题了,老师没有这个问题)
再添加一条数据之后 pageNo == pageTotal 显示第11页
删除图书:
修改图书:
002-实现首页index.jsp的分页
实现首页index.jsp的分页
通过地址 http://ip:port/工程路径/ 或者 http://ip:port/工程路径/index.jsp
访问主页面index.jsp
要对index.jsp实现分页,index.jsp无法处理分页,所以要创建ClientBookServlet
这样就是要访问ClientBookServlet
但是无法显示地访问ClientBookServlet,一定要通过访问index.jsp的地址实现分页
怎么做?
在web下的pages目录创建一个client目录,
在client目录下创建一个和index.jsp一样的jsp。
在src的web package下创建 ClientBookServlet:
在ClientBookServlet中需要实现 page()分页方法,可以直接将BookServlet的page()方法复制过去。
再进行相应的修改。
上面这个index.jsp只负责请求转发:
这样就实现了
从 主页面index.jsp 到 ClientBookServlet 再到 web下的pages下的client/index.jsp
对web下的pages下的client/index.jsp进行修改:
遍历商品(图书)
运行之后,发现只有两个商品,将Page类的 PAGE_SIZE 改为4即可
实现分页条:
可以将book_manager.jsp的分页条复制粘贴 替换
web下的pages下的client/index.jsp的分页条
再对其中的请求地址进行修改:
如何快速修改请求地址?
使用搜索替换 ctrl + r
003-分页条的抽取
会发现 前台 和 后台 的分页条 的实现代码都是相同的,只是请求地址不同;
将分页条的代码抽取出来。
首先:在Page类中添加一个属性 url,作为分页条的请求地址
getXXX() setXXX()方法别忘了,toString()和构造方法都要重写一下。
然后:
使用 ${ requestScope.page.url } —>ctrl+r 替换—> 前后台的请求地址和?action=page
前台(web下的pages/client/index.jsp):
后台(book_manager.jsp):
然后:在前后台的Servlet的page方法中设置url
前台(ClientBookServlet):
后台(BookServlet):
这样做的好处:
1、修改分页条的请求地址更加方便(不同的模块直接修改page.setUrl()即可)
2、这样写之后,前后台 实现分页条的代码都是一样的,将代码提取出来。
提取分页条代码:
在pages/common下创建page_nav.jsp
将分页条的代码复制过去,
然后client/index.jsp和book_manager.jsp相关分页条代码直接静态包含就可以了。
page_nav.jsp:
004-首页价格搜索
实现以上功能,并且分页显示。
表单的请求地址指向ClientBookServlet:
并加上隐藏域,调用pageByPrice()方法
修改pages/client/index.jsp:
在ClientBookServlet中实现pageByPrice()方法:
BookService中添加如下方法:
BookServiceImpl中实现pageByPrice()方法:
BookDao中添加如下方法:
BookDaoImpl中实现上面两个方法:
在BookDaoImplTest中测试:
queryForPageTotalCountByPrice()
和
queryForPageItemsByPrice()
在BookServiceImplTest中测试pageByPrice():
修改细节:
实现 点击上方查询之后 数字保留 不消失:
添加pages/client/index.jsp 中的两个value值:
但是点击下一页,数字还是会消失,并且分页条发生了变化。
解决方法:
在ClientBookServlet的pageByPrice()方法中的
setUrl()中添加&min=...&max=...
如下: