在显示用户全部信息的页面,在显示全部数据的时候,长长的滚动条,像是没有边界的天空一样, 让用户查看数据很不方便. 于是, 我们要把这些数据分页显示, 就像office的word一样,每页显示一定数量的数据,这样方便用户观看, 让用户不会产生视觉疲劳, 所以我们在做项目时也把大量的用户数据进行分页显示.
首先说说分页的逻辑.
用户发出查询全部信息的请求(点击菜单信息中的查询按钮)---执行用户的请求----返回执行的结果,并在界面分页显示. 可以看出这和一般的显示数据大致相似, 我们要的是进一步把要显示的数据分页显示出来就ok了.
如果没有前人的分页要让我们自己来创造一个分页的方法来,我会这样想:
1 数据显示, 从数据库中取出自己要的数据放到java的一个集合对象中, 再想法设法的把显示的内容以分页的形式显示.(让客户端来做分页这件事情)
2 界面可以以表格的形式显示, 给表格添加一些分页需要的按钮,例如'第几页' '共几页'等内容,只需要读取一下显示就可以了. 我们把分页这个逻辑放到了数据库来做,让数据库来执行这样的事情.
3 界面只管显示,分页的逻辑让jsp 和控制层同时分担, 让数据库做简单的查询.
实际上,通过我们的经验得知, 在VS中有控件按钮,例如datagrid控件 datatable控件等等而在我们的java中是没有datagrid类似控件的,我们可以用table来做.
我们这的例子用的就是第三种方式, 让服务器和数据库承担相应的分页责任, 而客户端用来显示内容的,这样会让职责更加明确,让系统的扩展性更好.
我们详细说说这个分页的业务逻辑:
我们采用的java model1模型(关于这个模式以后会详细和mvc讲),
model1原型:
我们的分页业务逻辑:
从首先是从界面上(.jsp界面)获取第一页和共几页的参数, 让jsp和后台的执行逻辑类打交道,通过UserManager类的一个方法,在这个方法中传递我们的sql语句,在数据库中进行查询, 查询完毕后返回给我们的jsp页面,在jsp页面中与table绑定.
从数据库中查询,数据库查询的sql语句:
1 首先我们取出除了root用户外的其他用户,并且根据用户id进行排序:
select * from t_user where user_id <> 'root' order by user_id;
2 在上面查询的结果基础上,我们查询他们每一行的编号. 我们用rownum这个字段, 这个字段是oracle自带 的, 类似于我们类的一个属性的样子, rownum表示的第几行代表的就是数字几. 下面我们选取每行的数字,同时选取数据.
select rownum rn,user_id,user_name,password,contact_tel,email,create_date
from
(
select * from t_user where user_id <> 'root' order by user_id
)
我们会看到下面的结果:
其次我们再在上面的基础上进行查询:
select rownum rn,user_id,user_name,password,contact_tel,email,create_date
from
(
select * from t_user where user_id <> 'root' order by user_id
) where rownum<= 2
在上述结果集中我们再进行嵌套查询,为了我们得到的数据正好和一页的 条数 和第几页相吻合, 所以在上面查询出来的基础上嵌套查询:
select user_id,user_name,password,contact_tel,email,create_date
from(
select rownum rn,user_id,user_name,password,contact_tel,email,create_date
from
(
select * from t_user where user_id <> 'root' order by user_id
) where rownum<= 2
)where rn >0
这样我们就可以查询出数据库中总记录的第多少条记录到第多少条记录了.
从分页的业务逻辑中我们可以看从数据库中查询出来,我们要返回很多条数据,例如每页的记录信息,显示的总页
数,显示当前第多少页, 上一页,下一页等, 所以我们把他们进行封装,封装成一个pageModel工具类,这样我们在传递
和返回这些数据,可以把某些数据当做pageModel的一个属性来操作.
我们的pageModel类:
package com.bjpowernode.drp.util;
import java.util.List;
/**
* 封装分页信息
* @author summer
*
*/
public class PageModel<E> {
//设置本类为PageModel的目的是为了,以后用户查询调用分页,其他的也可以调用分页.
//结果集对象.
private List<E> list;
// 得到对象.
public List<E> getList() {
return list;
}
//设置对象.
public void setList(List<E> list) {
this.list = list;
}
//查询记录数.
private int totalRecords;
//每页多少条数据.
private int pageSize;
//第几页.
private int pageNo;
//得到总页数的方法.
public int getTotalPages()
{
return (totalRecords+pageSize-1)/pageSize ;
}
//取得首页.
public int getPageTopNo()
{
return 1;
}
//取得尾页,总的页数,尾页第总的位数页.
public int getBottomPageNo()
{
return getTotalPages();
}
//取得上一页的页号.
public int getPreviousPageNo()
{
//判断当前页是否是最后一页或者第一页
if(pageNo <= 1)
{
return 1;
}
//拿到当前页.再减去一.
return pageNo -1;
}
//取得下一页面.
public int getNextPageNo()
{
if(pageNo >= getBottomPageNo() )
{
return getBottomPageNo();
}
return pageNo + 1;
}
//得到总记录数.
public int getTotalRecords() {
return totalRecords;
}
//设置总记录数.
public void setTotalRecords(int totalRecords) {
this.totalRecords = totalRecords;
}
//得到页面的大小.
public int getPageSize() {
return pageSize;
}
//设置页面的大小.
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
//得到第多少页面.
public int getPageNo() {
return pageNo;
}
//设置第多少页面.
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
}
在这里面我们在定义对象的集合用的是泛型, 为什么是使用泛型?
//结果集对象 private List<E> list;
什么是泛型?
泛型是一种特殊的类型,它把指定类型的工作推迟到客户端代码声明并实例化类或方法的时候进行.
因为我们在定义一个对象的集合的时候,我们通常不确定对象的类型,所以我们用这样的泛型:private List<E> list;而且我们的分页需求也不止一个界面,为了能把分页类更好的封装,我们采取泛型,这样更加灵
活. 并且泛型能让我们提前发现错误,我们首先约定一个集合,这个集合中什么类型的对象都可以放,一次只要放同
一种类型的对象就ok.就像水果篮儿一样,这个水果篮可以放香蕉,可以放草莓,但不能混放.
为了让界面最少的逻辑,或者说没有逻辑,我们把更多的信息封装在了这个pageModel类中,并且在这个类中执行了
一些简单的方法,例如,得到查询的总页数:
public int getTotalPages(){
return (totalRecords+pageSize-1)/pageSize ; }
得到上一页,得到下一页等方法.
下面看我们的jsp页面, jsp页面除了需要显示信息外,也有些许的控制逻辑,也就是和后台打交道的代码.:
我们用table进行控制的:
<table width="95%" border="1" cellspacing="0" cellpadding="0"
align="center" class="table1">
<tr>
<td width="55" class="rd6">
<input type="checkbox" name="ifAll" onClick="checkAll(this)">
</td>
<td width="119" class="rd6">
用户代码
</td>
<td width="152" class="rd6">
用户名称
</td>
<td width="166" class="rd6">
联系电话
</td>
<td width="150" class="rd6">
email
</td>
<td width="153" class="rd6">
创建日期
</td>
</tr>
<%
List<User> userList = pageModel.getList();
for (Iterator<User> iter=userList.iterator(); iter.hasNext();) {
//用泛型之后就不需要转换类型了.
User user = iter.next();
%>
<tr>
<td class="rd8">
<input type="checkbox" name="selectFlag" class="checkbox1"
value="<%=user.getUserId() %>">
</td>
<td class="rd8">
<%=user.getUserId() %>
</td>
<td class="rd8">
<%=user.getUserName() %>
</td>
<td class="rd8">
<%=user.getContactTel() %>
</td>
<td class="rd8">
<%=user.getEmail() %>
</td>
<td class="rd8">
<%=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(user.getCreateDate()) %>
</td>
</tr>
<%
}
%>
</table>
我们在循环显示User集合中的内容时,使用了java迭代器 Iterator, 迭代器是一个对象, 它可以遍历并选择序列
中的对象, 而开发人员不需要了解该序列的底层结构. 迭代器通常被称为"轻量级" 对象, 因为创建它的代价小.
在这里就不详细解说了.
List<User> userList = pageModel.getList();
for (Iterator<User> iter=userList.iterator(); iter.hasNext();)
{
//用泛型之后就不需要转换类型了.
User user = iter.next(); }
在执行首页,上一页,下一页的时候我们用的是js来进行控制的:
//首页.
function topPage() {
window.self.location = "user_maint.jsp?pageNo=<%=pageModel.getPageTopNo()%>";
}
//取得上一页.
function previousPage() {
window.self.location = "user_maint.jsp?pageNo=<%=pageModel.getPreviousPageNo()%>";
}
//取得下一页的.
function nextPage() {
window.self.location = "user_maint.jsp?pageNo=<%=pageModel.getNextPageNo()%>";
}
在jsp中:
<%
int pageNo = 1;
int pageSize = 4;
String pageNoString = request.getParameter("pageNo");
if (pageNoString != null) {
pageNo = Integer.parseInt(pageNoString);
}
PageModel<User> pageModel =UserManager.getInstance().findUserList(pageNo, pageSize);
%>
我们的UserManager类:
传递sql ,与书库打交道查询的代码:
/**
* 分页查询
* @param pageNo 第几页
* @param pageSize 每页多少条数据
* @return pagemode实体.
* @throws ClassNotFoundException
*/
public PageModel<User> findUserList(int pageNo,int pageSize) throws ClassNotFoundException{
//查询的slq语句.
StringBuffer sbSql = new StringBuffer();
sbSql.append("select user_id, user_name, password, contact_tel, email, create_date ")
.append("from ")
.append("( ")
.append("select rownum rn, user_id, user_name, password, contact_tel, email, create_date ")
.append("from ")
.append("( ")
.append("select user_id, user_name, password, contact_tel, email, create_date from t_user where user_id <> 'root' order by user_id ")
.append(") where rownum <= ? ")
.append(") where rn > ? ");
//建立连接对象。
Connection conn = null;
PreparedStatement pstmt = null;
//结果记录集.
ResultSet rs = null;
//定义user对象.
PageModel<User> pageModel = null;
try {
conn = DbUtil.getConnection();
pstmt = conn.prepareStatement(sbSql.toString());
//取得值.
pstmt.setInt(1,pageNo * pageSize);
pstmt.setInt(2,(pageNo-1) * pageSize);
//传递给res对象.
rs = pstmt.executeQuery();
List<User> userList = new ArrayList();
//拿出来rs中的内容.
while(rs.next())
{
User user = new User();
//从记录集中取出数据库中查询的记录的数据,并给user实体.
user.setUserId(rs.getString("USER_ID"));
user.setUserName(rs.getString("USER_NAME"));
user.setPassword(rs.getString("PASSWORD"));
user.setContactTel(rs.getString("CONTACT_TEL"));
user.setEmail(rs.getString("EMAIL"));
user.setCreateDate(rs.getTimestamp("CREATE_DATE"));
userList.add(user);
}
//实例化pagemodel类.
pageModel =new PageModel<User>();
pageModel.setList(userList);
//传递当前第几页.
pageModel.setPageNo(pageNo);
//总记录数.
pageModel.setTotalRecords(getTotalRecords(conn));
pageModel.setPageSize(pageSize);
} catch (SQLException e) {
// 打印错误.
e.printStackTrace();
}finally{
//关闭.
DbUtil.close(rs);
DbUtil.close(pstmt);
DbUtil.close(conn);
}
return pageModel;
}
在学习分页技术的时候,以前在vs中也曾经实现过分页逻辑的实现,貌似使用的控件. vs中分页,由于没有总结,所以都忘记的差不都了........这也告诉我学习一定要时常总结,不要相信自己的大脑,我们要相信计算机,相信文字,从感性到理性过渡吧........好记性不如烂笔头(博客)!
从这次分页的学习看来,还是要从大方面的去把握,把握全局,把握这个过程,再从细节上各个的击破,不能不求甚解.尤其是第二次遇到这个东西的时候了.....
昨天的雷声似乎还在耳畔响起,就是再大的雷声,今天的阳光依然明媚,一切如初!