【前言】

在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. 使用缓存时出现java.io.NotSerializableException:xxx.xxx.xxx.Bean解决办法

    解决方案:   开发过程中如果想缓存某个JavaBean,请确保它所引用的对象都implents Serializable,如果某个对象不需要被cache,可以加上transient关键字,否则Ehc ...

  2. 【ppp-chap,pap,mp,mp-group】

    PPP链路端口验证(单){ PAP(明文): 主验证方: {local-user user_name:配置本地用户; password {simple||cipher}:配置验证密码; service ...

  3. PHP接收http请求头信息

    1.PHP 自带函数 getallheaders() 目前 getallheaders() 只能用于 apache 中.如果想在 nginx 中也能使用,可以使用自定义函数. foreach (get ...

  4. 批处理,%~d0 cd %~dp0 代表什么意思

    批处理,%~d0 cd %~dp0 代表什么意思   ~dp0 “d”为Drive的缩写,即为驱动器,磁盘.“p”为Path缩写,即为路径,目录cd是转到这个目录,不过我觉得cd /d %~dp0 还 ...

  5. PHP入门笔记--基础语法一

    一.基本语法 php标记 <?php ?> php代码结束标记 三种注释 // /**/ # 二.类型 四种标量类型:boolean, integer, float, string 三种复 ...

  6. uva 508 - Morse Mismatches(摩斯码)

    来自https://blog.csdn.net/su_cicada/article/details/80084529 习题4-6 莫尔斯电码(Morse Mismatches, ACM/ICPC Wo ...

  7. Matplotlib 子图的创建

    在matplotlib中,整个图像为一个Figure对象 在Figure对象中可以包含一个或者多个Axes对象  每个Axes对象相当于一个子图了 每个Axes(ax)对象都是一个拥有自己坐标系统的绘 ...

  8. 003---random随机数模块

    import random # 随机数(0-1) print(random.random()) # 随机整数, 包含尾巴 print(random.randint(-1, 2)) # 不包含尾巴 pr ...

  9. 003---Python基本数据类型--列表

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

  10. Java 基础------16进制转2进制

    我们知道,数字8用二进制表示为:1000 用16进制表示为:8 那么我给你一个16进制的数字,0x7f,他的二进制是什么呢? 一个16进制的位数,用4位表示.比如,0x 7 f 其中: 7用4位二进制 ...