【前言】

在BS中,分页技术的应用相当频繁。说到分页,简单的分页就很好实现了,如果在分页的基础上再加上业务逻辑,这就使得分页的技术更加的灵活了。

【简单分页】

我们先看一种简单的分页,为了做到复用,我们抽出分页公用的东西,即分页实体PageModel。

/**
* 封装分页信息
* @author Administrator
*
*/
public class PageModel<E> { //结果集
private List<E> list; //查询记录数
private int totalRecords; //每页多少条数据
private int pageSize; //第几页
private int pageNo; /**
* 总页数
* @return
*/
public int getTotalPages() {
return (totalRecords + pageSize - 1) / pageSize;
} /**
* 取得首页
* @return
*/
public int getTopPageNo() {
return 1;
} /**
* 上一页
* @return
*/
public int getPreviousPageNo() {
if (pageNo <= 1) {
return 1;
}
return pageNo - 1;
} /**
* 下一页
* @return
*/
public int getNextPageNo() {
if (pageNo >= getBottomPageNo()) {
return getBottomPageNo();
}
return pageNo + 1;
} /**
* 取得尾页
* @return
*/
public int getBottomPageNo() {
return getTotalPages();
} ...
//get,set方法省略 }

在使用的时候,以查询用户集合为例

	/**
* 分页查询
* @param pageNo 第几页
* @param pageSize 每页多少条数据
* @return pageModel
*/
public PageModel<User> findUserList(int pageNo, int pageSize) {
StringBuffer sbSql = new StringBuffer();
//查询的sql语句
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;
//定义用户分页实体
PageModel<User> pageModel = null;
try {
conn = DbUtil.getConnection();
pstmt = conn.prepareStatement(sbSql.toString());
//传入参数
pstmt.setInt(1, pageNo * pageSize);
pstmt.setInt(2, (pageNo - 1) * pageSize);
rs = pstmt.executeQuery();
List<User> userList = new ArrayList<User>();
//遍历,赋值
while (rs.next()) {
User user = new 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 = new PageModel<User>();
pageModel.setList(userList);
pageModel.setTotalRecords(getTotalRecords(conn)); //总记录数
pageModel.setPageSize(pageSize);
pageModel.setPageNo(pageNo);
}catch(SQLException e) {
e.printStackTrace();
}finally {
DbUtil.close(rs);
DbUtil.close(pstmt);
DbUtil.close(conn);
}
return pageModel;
}

这里,我们只将pageNo(页号),pageSize(每页的条数)以及User(要分页的实体)作为参数传入就可以了。其他的属性,像TotalRecords(总记录数)等都可以计算得到。在sql语句中,我们限定了每次查询的数量,在前台显示的时候,直接将pageModel传到页面,然后获取其属性。

在第一种方法中,我们的需求比较简单:查询用户名不是root的所有用户,默认排序方式是按用户id排序。但当排序方式、排序的范围、每页显示条数等都不确定的情况下,这种分页方式就比较粗糙了。

【难度提升】

1、排序范围:分为两种——查询全部,查询部分。

2、排序条件:1:按最后更新时间排序,2:按主题发表时间排序,3:按回复数量排序

3、排序类型:升序,降序。

4、选择页码,展示相应的数据。

【分析】

1、pageModel 分页实体

我们仍将抽取分页实体PageBean,与第一种方法不同的是,为了满足单击页码查询的需求,新增了两个属性beginPageIndex和endPageIndex。

/**
* 分页中一页的信息
*
* @author YANG
*
*/
public class PageBean {
// 指定的或是页面参数
private int currentPage;
private int pageSize; // 查询数据库
private List recordList; private int recordCount; // 需要计算
private int pageCount;
//开始
private int beginPageIndex;
//结束
private int endPageIndex; //省去get,set
}

2、sql语句

因为查询条件数量和内容都不确定,因而sql语句绝对不能写死。

3、关于封装

1)sql语句可以进行封装。

如何解决:——抽象出Query类,将其where子句、orderby子句等进行封装。

/**
* 辅助拼接hql
*
* @author YANG
*
*/
public class QueryHelper {
private String fromClause;
private String whereClause = "";
private String orderByClause = ""; private List<Object> params = new ArrayList<Object>(); /**
* 生成from
*
* @param clazz
* @param alias
* 别名
*/
public QueryHelper(Class clazz, String alias) {
fromClause = " FROM " + clazz.getSimpleName() + " " + alias;
} /**
* 拼接where子句
*
* @param condition
* @param param
*/
public QueryHelper addCondition(String condition, Object... param) { if ("".equals(whereClause)) {
whereClause = " WHERE " + condition;
} else {
whereClause += " AND " + condition;
}
// 参数
if (param != null) {
for (Object p : param) {
params.add(p);
}
}
return this;
} /**
* 第一个参数为true,拼接where子句
*
* @param append
* @param condition
* @param param
*/
public QueryHelper addCondition(boolean append, String condition, Object... param) { if (append) {
addCondition(condition, param);
}
return this;
} /**
* orderBy子句
*
* @param propertyName
* @param asc
* true 升序
*/
public QueryHelper addOrderByProperty(String propertyName, boolean asc) {
if ("".equals(orderByClause)) {
orderByClause = " ORDER BY " + propertyName + (asc ? "ASC" : "DESC");
} else {
orderByClause += ", " + propertyName + (asc ? "ASC" : "DESC");
}
return this;
} /**
* 第一个参数为true,拼接orderby子句
*
* @param append
* @param propertyName
* @param asc
*/
public QueryHelper addOrderByProperty(boolean append, String propertyName,
boolean asc) {
if (append) {
addOrderByProperty(propertyName, asc);
}
return this;
} /**
* 获取生成的用于查询数据列表的hql语句
*
* @return
*/
public String getListQueryHql() {
return fromClause + whereClause + orderByClause;
}
}

2)Page分页实体中的其他属性值

page中的参数可分为两类,一类是传入或给定的值,如pageSize、currentPage等;另一类是需要自动计算的属性,如beginPageIndex等。如果对需要回显页面的属性进行封装,既可避免向前台准备不必要的数据,也可防止遗漏。

如何解决:——在pageBean中利用构造函数完成

public PageBean(int currentPage, int pageSize, List recordList,
int recordCount) {
super();
this.currentPage = currentPage;
this.pageSize = pageSize;
this.recordList = recordList;
this.recordCount = recordCount; pageCount = (recordCount + pageSize - 1) / pageSize;
// 计算beginPageIndex endPageIndex
if (pageCount > 5) {
// 总页数>5,显示分页
// 当前页附近共5个 前两个+后两个+本页
beginPageIndex=currentPage-2;
endPageIndex=currentPage+2;
// 前面页码不足2显示前5个
if(beginPageIndex<1){
beginPageIndex=1;
endPageIndex=5;
}
// 后面页码不足2,显示后5个
//TODO:bulijie
if(endPageIndex>pageCount){
beginPageIndex=pageCount-10+1;
endPageIndex=pageCount;
}
} else {
// 总页数<5
beginPageIndex = 1;
endPageIndex = pageCount;
} }

……

具体业务中如何使用:

1)确定排序条件,即给QueryHelper传参。

 new QueryHelper(Reply.class, "r")
// 查询范围
.addCondition("r.topic=?", topic)
//排序条件,按发表时间postTime
.addOrderByProperty( "r.postTime ", true)
.preparePageBean(replyService, pageNum, pageSize);

2)实现类中具体实现方法

public PageBean getPageBeanByParam(int pageNum, int pageSize, QueryHelper queryHelper) {
System.out.println("DaoSupportImpl.getPageBeanByParam()"); //获取参数列表,即查询条件
List<Object> params=queryHelper.getParams(); // 查询列表
Query query = getSession().createQuery(queryHelper.getListQueryHql());
//设定参数
if(params!=null){
for (int i = 0; i < params.size(); i++) {
query.setParameter(i,params.get(i));
}
}
query.setFirstResult((pageNum-1)*pageSize);
query.setMaxResults(pageSize);
List list=query.list();
// 总数量
Query countQuery=getSession()
.createQuery(queryHelper.getCountQueryHql());
if(params!=null){
for (int i = 0; i < params.size(); i++) {
countQuery.setParameter(i,params.get(i));
}
} Long count = (Long)countQuery.uniqueResult();
//pageBean的构造函数方法
return new PageBean(pageNum, pageSize, list, count.intValue());
}

3)回显数据,最后页面的显示部分就很简单了,使用OGNL表达式或者EL表达式都可完成显示。

/**
* 查询分页信息,并放到栈顶
* @param service
* @param pageNum
* @param pageSize
*/
public void preparePageBean(DaoSupport<?> service,int pageNum,int pageSize){
PageBean pageBean = service.getPageBeanByParam(pageNum, pageSize,
this);
ActionContext.getContext().getValueStack().push(pageBean);
}

【小结】

首先,本文中的分页属于真分页。真分页的原则是显示什么查什么,而假分页是将所有的数据全部查出来,再前台控制数据的显示,这样性能会很差。在小编看来一般项目中,应用真分页的情况比较多一些。

在项目中,像分页、连接数据库、sql的增删改查等操作都可以考虑抽出一个工具类来做,其他业务上需要使用,直接拿来用就可以。以分页为例,在业务需求增多,查询难度加大的情况下,可采用拼接sql的方式来完成分页,在拼接时,要考虑是否不易出错,程序健壮性如何等问题。

【SSH】——封装参数不确定的分页查询的更多相关文章

  1. OracleHelper(对增删改查分页查询操作进行了面向对象的封装,对批量增删改操作的事务封装)

    公司的一个新项目使用ASP.NET MVC开发,经理让我写个OracleHelper,我从网上找了一个比较全的OracleHelper类,缺点是查询的时候返回DataSet,数据增删改要写很多代码(当 ...

  2. Hibernate分页查询小结

    通常使用的Hibernate通常是三种:hql查询,QBC查询和QBE查询: 1.QBE(Qurey By Example)检索方式 QBE 是最简单的,但是功能也是最弱的,QBE的功能不是特别强大, ...

  3. JAVAEE——BOS物流项目04:学习计划、datagrid、分页查询、批量删除、修改功能

    1 学习计划 1.datagrid使用方法(重要) n 将静态HTML渲染为datagrid样式 n 发送ajax请求获取json数据创建datagrid n 使用easyUI提供的API创建data ...

  4. Mybatis 分页查询

    该篇博客记录采用pagehelper分页插件实现Mybatis分页功能 一.依赖 pom.xml <!-- pagehelper --> <dependency> <gr ...

  5. oracle分页查询及原理分析(总结)

    oracle分页查询及原理分析(总结) oracle分页查询是开发总为常用的语句之一,一般情况下公司框架会提供只需套用,对于增删改查而言,查是其中最为关键也是最为难的一块,其中就有使用率最高的分页查询 ...

  6. Oracle使用MyBatis中RowBounds实现分页查询

    Oracle中分页查询因为存在伪列rownum,sql语句写起来较为复杂,现在介绍一种通过使用MyBatis中的RowBounds进行分页查询,非常方便. 使用MyBatis中的RowBounds进行 ...

  7. Mysql系列(五)—— 分页查询及问题优化

    一.用法 在Mysql中分页查询使用关键字limit.limit的语法如下: SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15 limit关键字带有 ...

  8. php 之 分页查询的使用方法及其类的封装

    一.分页的使用: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://ww ...

  9. SpringBoot16 MockMvc的使用、JsonPath的使用、请求参数问题、JsonView、分页查询参数、JsonProperty

    1 MockMvc的使用 利用MockMvc可以快速实现MVC测试 坑01:利用MockMvc进行测试时应用上下文路径是不包含在请求路径中的 1.1 创建一个SpringBoot项目 项目脚手架 1. ...

随机推荐

  1. ABAP术语-Error Message

    Error Message 原文:http://www.cnblogs.com/qiangsheng/archive/2008/01/30/1058283.html Information from ...

  2. CentOS7——网络配置

    ip addr #查看当前IP地址信息.(contos7以下的为ifconfig) /etc/sysconfig/network-scripts/ifcfg-*** #***代表不一定的,需要进入该设 ...

  3. Git详解及github的使用

    1.Devops介绍 1.Devops是什么 开发 development 运维 operations 2.Devops能干嘛 提高产品质量 1 自动化测试 2 持续集成 3 代码质量管理工具 4 程 ...

  4. MySQL数据库查看数据表占用空间大小和记录数

    MySQL数据库中每个表占用的空间.表记录的行数的话,可以打开MySQL的 information_schema 数据库.在该库中有一个 TABLES 表,这个表主要字段分别是: TABLE_SCHE ...

  5. 《python编程从入门到实践》第六章笔记

    1.字典 字典:一系列键-值对,每一个键都与每一个值相关联.与键相关联的值可以是数字.字符串.列表和字典. 最简单的字典只有一个键值对. eg: alien = {'color':'green','p ...

  6. 学习python第一天 pycharm设置

    print(“hello,world”) pycharm设置 1. 选择python 解析器,目的是确定pycharm 的运行环境. 方法: File-->Settings-->Proje ...

  7. python-集合类型

    集合具有唯一性(集合中的元素各不相同),无序性,确定性(集合中的元素是不可改变的,不能是列表,字典以及集合本身) 1.add(self, *args, **kwargs),union(self, *a ...

  8. 004---Python基本数据类型--元祖

    元祖 .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px ...

  9. sort()的部分用法

    #include <iostream> #include <cstdio> #include <algorithm>//sort要包含的头文件 #include & ...

  10. h5调试工具

    1.Safari:iPhone 调试利器,查错改样式首选: 2.iOS 模拟器:不需要真机,适合调试 Webview 和 H5 有频繁交互的功能页面: 3.Charles: Mac OS 系统首选的抓 ...