ThreadLocal设计模式,线程局部变量,因为每一次请求都对应一个线程,把初始化的分页数据放在这个局部变量中,当用到时,可以直接从当前线程中获取。原理同HibernateOpenSessionInView。
为了避免在Action(呈现层)和Manager(业务逻辑层)之间传递大量的参数,所以我们使用ThreadLocal模式来传递分页参数(包括:offset和pagesize)。同时,将分页逻辑做封装抽取出来,也便于Services重复使用。
- 定义:参考SystemContext.java
-往ThreadLocal中赋值:参考PagerFilter.java
-从ThreadLocal中获取分页参数:参考AbstractManager.java
具体代码如下:
1、使用ThreadLocal存储分页起始索引记录位置与分页页面显示的记录数
SystemContext
public classSystemContext { privatestatic ThreadLocal offset = new ThreadLocal(); privatestatic ThreadLocal pagesize = new ThreadLocal(); publicstatic int getOffset(){ Integeros = (Integer)offset.get(); if(os== null){ return0; } returnos; } publicstatic void setOffset(int offsetvalue){ offset.set(offsetvalue); } publicstatic void removeOffset(){ offset.remove(); } publicstatic int getPagesize(){ Integerps = (Integer)pagesize.get(); if(ps== null){ returnInteger.MAX_VALUE; } returnps; } publicstatic void setPagesize(int pagesizevalue){ pagesize.set(pagesizevalue); } publicstatic void removePagesize(){ pagesize.remove(); } }
2、定义分页数据封装类
PagerModel
importjava.util.List;
public classPagerModel {
/**
* 总记录数
*/
privateint total;
/**
* 当前页结果集
*/
privateList datas;
publicList getDatas() {
returndatas;
}
publicvoid setDatas(List datas) {
this.datas= datas;
}
publicint getTotal() {
returntotal;
}
publicvoid setTotal(int total) {
this.total= total;
}
}
3、通过Filter往ThreadLocal中赋值
PagerFilter
importjava.io.IOException;
importjavax.servlet.Filter;
importjavax.servlet.FilterChain;
importjavax.servlet.FilterConfig;
importjavax.servlet.ServletException;
importjavax.servlet.ServletRequest;
importjavax.servlet.ServletResponse;
importjavax.servlet.http.HttpServletRequest;
importcom.bjsxt.oa.SystemContext;
public classPagerFilter implements Filter {
publicvoid destroy() {
}
publicvoid doFilter(ServletRequest request, ServletResponse response,
FilterChainchain) throws IOException, ServletException {
HttpServletRequesthttpRequest = (HttpServletRequest)request;
SystemContext.setOffset(getOffset(httpRequest));
SystemContext.setPagesize(getPagesize(httpRequest));
try{
chain.doFilter(request,response);
}finally{
//清空ThreadLocal中的值
SystemContext.removeOffset();
SystemContext.removePagesize();
}
}
protectedint getOffset(HttpServletRequest request){
intoffset = 0;
try{
offset= Integer.parseInt(request.getParameter("pager.offset"));
}catch (NumberFormatException ignore) {
}
returnoffset;
}
protectedint getPagesize(HttpServletRequest request){
return10;
}
publicvoid init(FilterConfig arg0) throws ServletException {
}
}
4、定义分页逻辑处理封装类
importjava.util.Iterator;
importjava.util.List;
importorg.hibernate.Query;
importorg.springframework.orm.hibernate3.support.HibernateDaoSupport;
importcom.bjsxt.oa.PagerModel;
importcom.bjsxt.oa.SystemContext;
importcom.bjsxt.oa.manager.SystemException;
public classAbstractManager extends HibernateDaoSupport {
//多种重载形式,便于使用
publicPagerModel searchPaginated(String hql){
returnsearchPaginated(hql,null,SystemContext.getOffset(),SystemContext.getPagesize());
}
publicPagerModel searchPaginated(String hql,Object param){
returnsearchPaginated(hql,newObject[]{param},SystemContext.getOffset(),SystemContext.getPagesize());
}
publicPagerModel searchPaginated(String hql,Object[] params){
returnsearchPaginated(hql,params,SystemContext.getOffset(),SystemContext.getPagesize());
}
publicPagerModel searchPaginated(String hql,int offset,int pagesize){
returnsearchPaginated(hql,null,offset,pagesize);
}
publicPagerModel searchPaginated(String hql,Object obj,int offset,int pagesize){
returnsearchPaginated(hql,new Object[]{obj},offset,pagesize);
}
/**
* 根据HQL语句进行分页查询
* @param hql HQL语句
* @param params HQL语句带的多个参数值
* @param offset 从第几条记录开始查询
* @param pagesize 每页显示多少行
* @return
*/
publicPagerModel searchPaginated(String hql,Object[] params,int offset,int pagesize){
// 使用传递进来的hql语句 构造出查询总记录数的语句
StringcountHql = getCountQuery(hql);
//创建hql查询语句,获取总记录数,要用session,getHibernateTemplate没有此方法
Queryquery = getSession().createQuery(countHql);
if(params!= null && params.length > 0){
for(inti=0; i<params.length; i++){
query.setParameter(i,params[i]);
}
}
inttotal = ((Long)query.uniqueResult()).intValue();
//创建查询语句以获取数据集合
query= getSession().createQuery(hql);
if(params!= null && params.length > 0){
for(inti=0; i<params.length; i++){
query.setParameter(i,params[i]);
}
}
//设置hibernate查询开始索引
query.setFirstResult(offset);
//设置hibernate查询多少条记录
query.setMaxResults(pagesize);
Listdatas = query.list();
//将结果设置到封装好的分页类
PagerModelpm = new PagerModel();
pm.setTotal(total);
pm.setDatas(datas);
returnpm;
}
/**
* 根据HQL语句,获得查找总记录数的HQL语句
* 如:
* select ... from Orgnization o where o.parentis null
* 经过转换,可以得到:
* select count(*) from Orgnization o whereo.parent is null
* @param hql
* @return
*/
privateString getCountQuery(String hql){
intindex = hql.indexOf("from");
if(index!= -1){
return"select count(*) " + hql.substring(index);
}
thrownew SystemException("无效的HQL查询语句!");
}
}
5、在Services中使用
public classOrgManagerImpl extends AbstractManager implements OrgManager {
publicPagerModel findOrgs(int parentId) {
//如果parentId=0,则查找顶级机构列表
if(parentId== 0){
returnsearchPaginated("from Orgnization o where o.parent is null");
}
returnsearchPaginated("from Orgnization o where o.parent.id = ?",parentId);
}
}
在使用中,通过Services中代码,可以发现由于把分页参数(offset、pagesize)放置在了ThreadLocal中,分页查询时,我不再需要在Action(呈现层)和Manager(业务逻辑层)传递分页参数;同时由于AbstractManager的抽象封装,使得Services中的分页查询变得十分简单。