@目录
什么是分页 ?
两个子模块功能的问题分析 和 解决方案
有条件查和无条件查询的影响 和 解决方案
项目案例: mysql + commons-dbutils+itcast-tools+BaseServlet + 分页+JSP+JSTL+EL+MVC模式
什么是分页?
如上所示,就是分页 ,不用多说了
子模块功能的问题分析 和 解决方案
@总功能分析 常规JDBC中,点击查询或输入条件查询,在页面中可显示查询出的所有记录,有多少记录就显示多少。在这种项目的基础上增加分页功能 。 @分页功能的宗旨 是无论什么样的查询,显示出的记录都是当前页的记录 。 所以,我们必须得向系统说明我们当前是要显示第几页的数据 。 自然,需要一个PageBean类
public class PageBean<T> {
private int pageCode ;//当前页码
// private int totalPage ;//总页数,总页数应该由计算获取
private int totalRecord;//总记录数
private int pageSize;//每页记录数,这是参数是定做这个软件的甲方提出来的,在Servlet中直接定义为10了
private List<T> beanList;//当前页的记录集合,方便整页记录的转移
private String url ;//Url后的条件,条件查询设置的
}
这个PageBean类中封装了当前页、总记录数、当前页所有记录的集合等,系统通过当前页码这个参数返回pageSize条记录放在beanList集合中返回显示。
@子模块功能1 中首页的pageCode是1,尾页的pageCode是totalPage,上一页和下一页分别是pageCode-1 和pageCode+1 。
@子模块功能2
从上述两张图片中,点击1页码,当前页处于列表的第1个位置,点击2页码,当前页处于列表的第2个位置,..........,点击6页码,当前页处于列表的第6个位置,但是当点击7页码时,当前页还是处于列表的第6个位置 。 也就是说,假如每次一行只能显示10个页码,1~6页码的当前页的位置还是1~6,列表从页码1~页码10。 但是7~10页码的当前页的位置始终位于页码列表的第6个位置 ,列表从【页码2~页码11】~【页码X~页码totalPage】。其实非常好解决 ,列表头尾的判定 还是利用pageCode , begin = pageCode - 5 , end = pageCode + 4 。
@解决
- 如果 totalPage <= 10(列表长度),那么 begin = 1,end = totalPage ;
- 使用公式计算;begin = pc-5 , end = pc + 4;
- 头溢出:当 begin < 1 时 , 让 begin = 1 ;
- 尾溢出:当 end > totalPage 时 , 让 end = totalPage
有条件查和无条件查询的影响 和 解决方案
分页使得有条件查询产生一个严重问题 , 通过条件查询出40条记录,分4页显示,只有第一页是该条件下的记录,其余3页都是不带条件的记录 。所以我们必须告诉系统我们的条件是什么,每一页都要带着条件去查询和返回 。
@解决
项目案例(mvc+jdbc+c3p0+BaseServlet+mysql+JSP+EL+JSTL)
@使用
采用commons-dbutils组件,封装好的JdbcUtils工具类和TxQueryRunner工具类辅助JDBC , (学习地址 : )
BaseServlet辅助类
JSP+EL+JSTL
@数据库
1 CREATE TABLE t_customer (
2 username VARCHAR(50) DEFAULT NULL,
3 age INT(11) DEFAULT NULL,
4 balance DOUBLE(20,5) DEFAULT NULL
5 );
t_customer
@源码
1 package cn.kmust.pagination.customer.domain;
2 /**
3 * 实体类
4 * 变量名字与数据库中对应字段名一样,便于封装操作
5 * @author ZHAOYUQIANG
6 *
7 */
8 public class Customer {
9 private String username ; //用户
10 private int age ; //年龄
11 private double balance ; //资金
12 public String getUsername() {
13 return username;
14 }
15 public void setUsername(String username) {
16 this.username = username;
17 }
18 public int getAge() {
19 return age;
20 }
21 public void setAge(int age) {
22 this.age = age;
23 }
24 public double getBalance() {
25 return balance;
26 }
27 public void setBalance(double balance) {
28 this.balance = balance;
29 }
30 @Override
31 public String toString() {
32 return "Customer [username=" + username + ", age=" + age + ", balance="
33 + balance + "]";
34 }
35 public Customer(String username, int age, double balance) {
36 super();
37 this.username = username;
38 this.age = age;
39 this.balance = balance;
40 }
41 public Customer() {
42 super();
43 // TODO Auto-generated constructor stub
44 }
45
46
47
48
49 }
Customer
1 package cn.kmust.pagination.pageBean.domain;
2 import java.util.List;
3 import java.util.List;
4 /**
5 * 分页Bean
6 * 把每一页中的当前页码、总页数、总记录数、每页记录数、当前页的记录集合等参数
7 * 封装到该类的一个对象中,形成PageBean对象
8 * @author ZHAOYUQIANG
9 *
10 */
11 public class PageBean<T> {
12 private int pageCode ;//当前页码
13 // private int totalPage ;//总页数,总页数应该由计算获取
14 private int totalRecord;//总记录数
15 private int pageSize;//每页记录数,这是参数是定做这个软件的甲方提出来的,在Servlet中直接定义为10了
16 private List<T> beanList;//当前页的记录集合,方便整页记录的转移
17 private String url ;//Url后的条件,条件查询设置的
18
19 public String getUrl() {
20 return url;
21 }
22 public void setUrl(String url) {
23 this.url = url;
24 }
25 public int getPageCode() {
26 return pageCode;
27 }
28 public void setPageCode(int pageCode) {
29 this.pageCode = pageCode;
30 }
31 /*
32 * 计算总页数,这个页数是由总记录和每页记录数决定的
33 */
34 public int getTotalPage() {
35 int totalPage = totalRecord/pageSize ;
36 return totalRecord%pageSize==0 ? totalPage : totalPage+1;
37 }
38 public int getTotalRecord() {
39 return totalRecord;
40 }
41 public void setTotalRecord(int totalRecord) {
42 this.totalRecord = totalRecord;
43 }
44 public int getPageSize() {
45 return pageSize;
46 }
47 public void setPageSize(int pageSize) {
48 this.pageSize = pageSize;
49 }
50 public List<T> getBeanList() {
51 return beanList;
52 }
53 public void setBeanList(List<T> beanList) {
54 this.beanList = beanList;
55 }
56
57 }
PageBean
1 package cn.kmust.pagination.customer.servlet;
2
3 import java.io.IOException;
4 import java.io.UnsupportedEncodingException;
5
6 import javax.servlet.ServletException;
7 import javax.servlet.http.HttpServletRequest;
8 import javax.servlet.http.HttpServletResponse;
9
10 import cn.itcast.commons.CommonUtils;
11 import cn.itcast.servlet.BaseServlet;
12 import cn.kmust.pagination.customer.domain.Customer;
13 import cn.kmust.pagination.customer.service.CustomerService;
14 import cn.kmust.pagination.pageBean.domain.PageBean;
15 /**
16 * Web层
17 * 继承了我们自己写的BaseServlet类
18 * 要求写的方法得与service()相同,
19 * 并且.jsp页面必须传递过来一个method参数,如(add、deleter等)
20 *
21 * @author ZHAOYUQIANG
22 *
23 */
24 public class CustomerServlet extends BaseServlet {
25 /*
26 * 依赖CustomerService
27 */
28 private CustomerService cstmService = new CustomerService();
29 /**
30 * 客户查询所有
31 * 加入了分页功能 : 向页面返回当前页的所有记录, 返回的是一个对象,对象中封装了一个beanList集合
32 * 该集合中存放这当前页所有记录
33 * @param request
34 * @param response
35 * @return
36 * @throws ServletException
37 * @throws IOException
38 */
39 public String queryAll(HttpServletRequest request, HttpServletResponse response)
40 throws ServletException, IOException {
41 /*
42 * 1. 获取list.jsp页面传递的pc
43 * 2. 给定每页记录数ps = 10 。开发者根据客户的需求,认为规定的
44 * 3. 使用pc和ps调用sevice方法,得到当前页的PageBean对象(该对象中封装了
45 * 当前页的所有记录的集合等)
46 * 4. 把PageBean保存到request域中
47 * 5. 转发到list.jsp
48 *
49 */
50 int pageCode = getCurrentPage(request);
51 int pageSize = 10 ; //每页10记录
52 PageBean<Customer> pageBean = cstmService.queryAll(pageCode,pageSize);
53 /*
54 * 因为与条件查询共用一个list.jsp,所以也需要加url
55 */
56 pageBean.setUrl(getUrl(request));
57 request.setAttribute("pageBean", pageBean);
58 return "f:/list.jsp";
59
60 }
61
62
63 /**
64 * 条件查询
65 * 具有分页功能,按照条件查询,条件也会被带入分页中
66 * @param request
67 * @param response
68 * @return
69 * @throws ServletException
70 * @throws IOException
71 */
72 public String query(HttpServletRequest request, HttpServletResponse response)
73 throws ServletException, IOException {
74 /*
75 * 1. 封装表单数据到Customer对象中
76 * 只有一个属性username,是查询的条件critaria
77 * 2. 得到当前页码 pageCode
78 * 3. 给定pageSize 10
79 * 4. 使用pageCode和pageSize以及条件对象,调用service方法得到query,
80 * 返回当前页的PageBean对象,内封装了当前页的所有记录集合
81 * 5. 把PageBean保存到request域中
82 * 6. 转发到list.jsp显示成功信息
83 */
84 Customer criteria = CommonUtils.toBean(request.getParameterMap(), Customer.class);
85 /*
86 * 处理GET请求方式编码问题
87 * 因为query.jsp表单使用的是get提交方法
88 */
89 criteria = encoding(criteria);
90
91 int pageCode = getCurrentPage(request);
92 int pageSize = 10 ; //每页10记录
93 PageBean<Customer> pageBean = cstmService.query(criteria,pageCode,pageSize);
94 /*
95 * 得到url,保存到pageBean对象中
96 */
97 pageBean.setUrl(getUrl(request));
98 request.setAttribute("pageBean", pageBean);
99 return "f:/list.jsp";
100 }
101
102
103 /**
104 * 处理GET请求乱码
105 * 因为BaseSevlet类中只有处理POST请求的乱码,没有GET请求的乱码处理
106 * @param criteria
107 * @return
108 * @throws UnsupportedEncodingException
109 */
110 private Customer encoding(Customer criteria) throws UnsupportedEncodingException {
111 String username = criteria.getUsername();
112
113 if(username != null && !username.trim().isEmpty()){
114 username = new String(username.getBytes("ISO-8859-1"),"utf-8");
115 criteria.setUsername(username);
116 }
117 return criteria;
118 }
119
120
121
122
123 /**
124 * 获取pageCode(当前页码)
125 * 传递到Servlet中的参数都是String类型的,所以需要转换
126 * pageCode参数如果不存在,说明是第一次调用,当前页码默认为第一页
127 * @param request
128 * @return
129 */
130 private int getCurrentPage(HttpServletRequest request){
131 String value = request.getParameter("pageCode");
132 if(value == null || value.trim().isEmpty()){
133 return 1 ;
134 }
135 return Integer.parseInt(value);
136 }
137
138
139 /**
140 * 截取url
141 * 条件查询中需要使用
142 * /项目名/Servlet路径?参数字符串
143 * @param request
144 * @return
145 */
146 private String getUrl(HttpServletRequest request){
147 /*
148 * 1. 获取项目名
149 * 2. 获取Servlet路径
150 * 3. 获取参数列表
151 * 这个参数是条件
152 */
153 String contextPath = request.getContextPath();
154 String servletPath = request.getServletPath();
155 String queryString = request.getQueryString();
156 /*
157 * 4. 判断是否包含pageCode参数
158 * 如果包含需要剪掉,不要这个参数
159 */
160 if(queryString.contains("&pageCode")){
161 int index = queryString.lastIndexOf("&pageCode");
162 queryString = queryString.substring(0,index);
163 }
164 return contextPath+servletPath+"?"+queryString ;
165 }
166
167 }
CustomerServlet
1 package cn.kmust.pagination.customer.service;
2
3 import java.sql.SQLException;
4 import java.util.List;
5
6 import cn.itcast.jdbc.JdbcUtils;
7 import cn.kmust.pagination.customer.dao.CustomerDao;
8 import cn.kmust.pagination.customer.domain.Customer;
9 import cn.kmust.pagination.pageBean.domain.PageBean;
10
11
12
13 /**
14 * service 层 处理业务
15 * @功能
16 * 1. 条件查询
17 * 2. 查询 所有用户
18 * 3. 查询 所有记录行数
19 * @author ZHAOYUQIANG
20 *
21 */
22 public class CustomerService {
23 /*
24 * 依赖CustomerDao
25 */
26 CustomerDao cstmDao = new CustomerDao();
27 /**
28 * 条件查询
29 *
30 * @param criteria
31 * @param pageCode
32 * @param pageSize
33 * @return
34 */
35 public PageBean<Customer> query(Customer criteria,int pc,int ps) {
36 return cstmDao.query(criteria,pc,ps);
37 }
38 /**
39 * 查询所有客户业务
40 * 具有分页功能 : 返回PageBean对象 ,对象中封装了 当前页所有记录的集合
41 * @param pc
42 * @param ps
43 * @return
44 */
45 public PageBean<Customer> queryAll(int pc,int ps){
46 return cstmDao.queryAll(pc,ps);
47 }
48
49
50
51 }
CustomerService
1 package cn.kmust.pagination.customer.dao;
2
3 import java.sql.ResultSet;
4 import java.sql.SQLException;
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.Map;
8
9 import javax.sql.DataSource;
10
11 import org.apache.commons.dbutils.QueryRunner;
12 import org.apache.commons.dbutils.ResultSetHandler;
13 import org.apache.commons.dbutils.handlers.BeanHandler;
14 import org.apache.commons.dbutils.handlers.BeanListHandler;
15 import org.apache.commons.dbutils.handlers.MapHandler;
16 import org.apache.commons.dbutils.handlers.MapListHandler;
17 import org.apache.commons.dbutils.handlers.ScalarHandler;
18
19 import cn.itcast.jdbc.JdbcUtils;
20 import cn.itcast.jdbc.TxQueryRunner;
21 import cn.kmust.pagination.customer.domain.Customer;
22 import cn.kmust.pagination.pageBean.domain.PageBean;
23
24
25
26
27 /**
28 *dao层
29 * 对数据库的操作
30 * @author ZHAOYUQIANG
31 *
32 */
33 public class CustomerDao {
34 private QueryRunner qr = new TxQueryRunner();
35 /**
36 * 对数据库进行查询所有客户操作
37 * 具有分页功能 : 返回PageBean对象,该对象封装了当前页的所有记录的集合
38 * 当前页的所有记录都放到beanList集合中,然后随当前页码等参数封装到pageBean中返回
39 * @return
40 */
41 public PageBean<Customer> queryAll(int pc,int ps){
42 try {
43 /*
44 * 有关数据库的操作:
45 * 准备sql模版
46 * 调用QueryRunner的query方法
47 */
48 /*该方法的任务:
49 * 1. 创建PageBean对象
50 */
51 PageBean<Customer> pageBean = new PageBean<Customer>();
52 /*
53 * 2. 设置pc和ps,封装到我pageBean对象
54 */
55 pageBean.setPageCode(pc);
56 pageBean.setPageSize(ps);
57 /*
58 * 3. 查询数据库得到totalRecord(数据库所有记录),封装到我pageBean对象
59 */
60 String sql = "select count(*) from t_customer";
61 Number num = (Number)qr.query(sql,new ScalarHandler() );
62 int totalRecord = num.intValue();
63 pageBean.setTotalRecord(totalRecord);
64 /*
65 * 4. 查询数据库得到BeanList(当前页记录的集合),封装到我pageBean对象
66 * 当前页到底是第几页,当前页有多少条记录呢?
67 * 利用mysql的limit子句, (limit 4,10的意思是从第五行记录开始(包含第五行),查询10行记录)
68 * 很明显当前页的是从第(pc-1)*ps行开始,查询ps行记录。
69 * 根据limit子句的特点,巧妙的设计查询当前页的数据
70 * 用order by 通过客户姓名来排序显示
71 */
72 sql = "select * from t_customer order by username limit ?,?";
73 List<Customer> beanList = qr.query(sql,
74 new BeanListHandler<Customer>(Customer.class),(pc-1)*ps,ps);
75 pageBean.setBeanList(beanList);
76 /*
77 * 5. 返回PageBean对象
78 */
79 return pageBean ;
80 } catch (SQLException e) {
81 throw new RuntimeException(e);
82 }
83 }
84 /**
85 * 条件查询
86 * 具有分页功能
87 * @param criteria
88 * @param pc
89 * @param ps
90 * @return
91 */
92 public PageBean<Customer> query(Customer criteria,int pc,int ps) {
93 try {
94 /*
95 * 1. 创建PageBean对象
96 * 2. 设置已有属性,pc和ps(pageCode和pageSize)
97 * 3. 通过条件查询数据库得到totalRecord
98 * 4. 查询数据库,返回beanList(当前页记录的集合)
99 */
100 PageBean<Customer> pageBean = new PageBean<Customer>();
101 pageBean.setPageCode(pc);
102 pageBean.setPageSize(ps);
103 /*
104 * 3. 通过条件查询数据库得到totalRecord
105 */
106 String sql1 = null;
107 String username = criteria.getUsername();
108 if(username != null && !username.trim().isEmpty()){
109 sql1 = "select count(*) from t_customer where username like ?" ;
110 }
111 Object[] params1 = {"%"+username+"%"};
112 /*
113 * 3.3. 得到totalRecord
114 */
115 Number num = (Number)qr.query(sql1,
116 new ScalarHandler(),params1);
117 int totalRecord = num.intValue();
118 pageBean.setTotalRecord(totalRecord);
119 /*
120 * 4. 查询数据库,返回beanList(当前页记录的集合)
121 * 还是需要拼凑sql语句,并且需要limit子句
122 * params中需要给出limit后两个问号对应的值
123 *
124 */
125
126 String sql2 = "select * from t_customer where username like ? limit ?,?";
127
128 Object[] params = {"%"+username+"%",(pc-1)*ps,ps};
129 List<Customer> beanList = qr.query(sql2,
130 new BeanListHandler<Customer>(Customer.class),
131 params);
132 pageBean.setBeanList(beanList);
133 return pageBean ;
134 } catch (SQLException e) {
135 throw new RuntimeException(e);
136 }
137
138 }
139 }