【SSH】——封装参数不确定的分页查询
【前言】
在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】——封装参数不确定的分页查询的更多相关文章
- OracleHelper(对增删改查分页查询操作进行了面向对象的封装,对批量增删改操作的事务封装)
公司的一个新项目使用ASP.NET MVC开发,经理让我写个OracleHelper,我从网上找了一个比较全的OracleHelper类,缺点是查询的时候返回DataSet,数据增删改要写很多代码(当 ...
- Hibernate分页查询小结
通常使用的Hibernate通常是三种:hql查询,QBC查询和QBE查询: 1.QBE(Qurey By Example)检索方式 QBE 是最简单的,但是功能也是最弱的,QBE的功能不是特别强大, ...
- JAVAEE——BOS物流项目04:学习计划、datagrid、分页查询、批量删除、修改功能
1 学习计划 1.datagrid使用方法(重要) n 将静态HTML渲染为datagrid样式 n 发送ajax请求获取json数据创建datagrid n 使用easyUI提供的API创建data ...
- Mybatis 分页查询
该篇博客记录采用pagehelper分页插件实现Mybatis分页功能 一.依赖 pom.xml <!-- pagehelper --> <dependency> <gr ...
- oracle分页查询及原理分析(总结)
oracle分页查询及原理分析(总结) oracle分页查询是开发总为常用的语句之一,一般情况下公司框架会提供只需套用,对于增删改查而言,查是其中最为关键也是最为难的一块,其中就有使用率最高的分页查询 ...
- Oracle使用MyBatis中RowBounds实现分页查询
Oracle中分页查询因为存在伪列rownum,sql语句写起来较为复杂,现在介绍一种通过使用MyBatis中的RowBounds进行分页查询,非常方便. 使用MyBatis中的RowBounds进行 ...
- Mysql系列(五)—— 分页查询及问题优化
一.用法 在Mysql中分页查询使用关键字limit.limit的语法如下: SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15 limit关键字带有 ...
- php 之 分页查询的使用方法及其类的封装
一.分页的使用: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://ww ...
- SpringBoot16 MockMvc的使用、JsonPath的使用、请求参数问题、JsonView、分页查询参数、JsonProperty
1 MockMvc的使用 利用MockMvc可以快速实现MVC测试 坑01:利用MockMvc进行测试时应用上下文路径是不包含在请求路径中的 1.1 创建一个SpringBoot项目 项目脚手架 1. ...
随机推荐
- 高级同步器:交换器Exchanger
引自:https://blog.csdn.net/Dason_yu/article/details/79764467 一.定义每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹 ...
- android 自定义滑动按钮
第一接触公司项目就让我画页面,而且还涉及到我最讨厌的自定义view 但是没办法,讨厌也必须要做啊,经过百度上资源的查找,终于写出了一个滑动控件.废话不多说,上代码. package com.eton ...
- js分割字符串
js分割字符串 我想达到通过 : 分割 只要第一次分割,后面的内容不使用分割 不行,没找到可以直接用的方法,不过可以通过其它方式达到效果 eg: str.split(':',2)[0] (第一个分隔符 ...
- iOS中出现"Check dependenciesWarning: The Copy Bundle Resources build phase contains this target's Info.plist file..."的解决办法A
出现场景 项目中移除info.plist ,后来又重新拖拽回来,同时勾选了Copy items if needed 解决办法 1.删除(删除时选择Remove Reference) 2.重新添加i ...
- python 连接MSSQL
# -*- coding: utf-8 -*- import pymssql conn=pymssql.connect(host=".",user="sa",p ...
- Hadoop(25)-高可用集群配置,HDFS-HA和YARN-HA
一. HA概述 1. 所谓HA(High Available),即高可用(7*24小时不中断服务). 2. 实现高可用最关键的策略是消除单点故障.HA严格来说应该分成各个组件的HA机制:HDFS的HA ...
- 11 非阻塞套接字与IO多路复用(进阶)
1.非阻塞套接字 第一部分 基本IO模型 1.普通套接字实现的服务端的缺陷 一次只能服务一个客户端! 2.普通套接字实现的服务端的瓶颈!!! accept阻塞! 在没有新的套接字来之前,不能处理已经建 ...
- HyperLedger Fabric 1.4 交易流程(6.3)
区块链最主要的特性之一是去中心化,没有了中心机构的集中处理,为了达成数据的一致性,就需要网络中全民参与管理,并以某种方法达成共识,所以区块链的交易流程也就是共识的过程. 在Fabric中, ...
- SQL 公用表表达式(CTE)
1.概念 公用表表达式(Common Table Expression)是SQL SERVER 2005版本之后引入的一个特性.CTE可以看作是一个临时的结果集,可以在接下来的一个SELECT,INS ...
- JS正则表达式笔记
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串.将匹配的子串替换或者从某个串中取出符合某个条件的子串等. 正则 描述 ...