【前言】

在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. 重置mysql5.7.25临时密码

    安装完mysql之后,登陆以后,不管运行任何命令,总是提示这个:mac mysql error You must reset your password using ALTER USER statem ...

  2. Java解决跨域问题

    同源 URL由协议, 域名, 端口组成. 如果两个URL的协议, 域名, 端口相同, 那么这两个URL为同源. 同源策略 script, iframe, link 可以跨域加载一些静态资源, 比如脚本 ...

  3. qt项目:员工信息管理系统

    开发一个员工信息管理系统 一.项目具体要求: 1.用qt开发界面,数据库用QSqlite 数据库文件名:demostudent.db 2.通过界面能够查看到数据库中员工信息表中内容,包括员工姓名.年龄 ...

  4. 【TOJ 3305】Hero In Maze II

    描述 500年前,Jesse是我国最卓越的剑客.他英俊潇洒,而且机智过人^_^.突然有一天,Jesse心爱的公主被魔王困在了一个巨大的迷宫中.Jesse听说这个消息已经是两天以后了,他急忙赶到迷宫,开 ...

  5. Flask-SQLAlchemy安装及设置

    Flask-SQLAlchemy安装及设置 SQLALchemy 实际上是对数据库的抽象,让开发者不用直接和 SQL 语句打交道,而是通过 Python 对象来操作数据库,在舍弃一些性能开销的同时,换 ...

  6. 基于SpringBoot+SpringSecurity+mybatis+layui实现的一款权限系统

    这是一款适合初学者学习权限以及springBoot开发,mybatis综合操作的后台权限管理系统 其中设计到的数据查询有一对一,一对多,多对多,联合分步查询,充分利用mybatis的强大实现各种操作, ...

  7. CentOS7版本基础使用

    第1章 CentOS7的使用 1.1 为什么要使用CentOS7版本 CentOS7是在CentOS6基础上发布的新版本,与之前的版本相比,主要的更新包括: 1.内核更新到3.10.0 2.支持Lin ...

  8. .NET中获取当前的IP地址

    /// <summary> /// 获取本地IP地址信息 /// </summary> public static string GetAddressIP() { ///获取本 ...

  9. Hadoop Eclipse 插件制作以及安装

    在本地使用Eclipse调试MapReduce程序,需要Hadoop插件,笔摘记录下制作安装过程. 准备工作(hadoop-2.6.0为例): 搭建好Hadoop环境 下载Hadoop安装包,解压到某 ...

  10. Leecode刷题之旅-C语言/python-58.最后一个单词的长度

    /* * @lc app=leetcode.cn id=58 lang=c * * [58] 最后一个单词的长度 * * https://leetcode-cn.com/problems/length ...