最近在开发客服第三方支付功能的时候,发现了主从表分页查询存在问题,然后解决了这个问题后,想将修改后的核心代码迁移到itv、短代、游戏包历史订购等相关接口时,发现这个完全适用于模板模式。好处就是当有类似的主从表分页查询时,只需要继承父类,实现相应的dao方法即可
先贴一个模板模式的图
[img]图在最下面,不会排版:funk: [img]
先说明下使用场景:因为数据量过大,所以在mysql对表进行了按月切分(并且是跨库),那么分页查询这些表时就有点蛋疼了,下面使用java代码来做下分页(有其他更好的方案请各位提供,一定感谢)
先来做一个abstract类
package cn.egame.data.core.common;
import cn.egame.common.exception.ExceptionCommonBase;
import cn.egame.common.model.PageData;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.List;
/**
* Created by dinghw on 2015/4/20.
*
* @desc 此类为模板模式的抽象类,主要用于主从分表查询分页的方法
*/
public abstract class TablesTemplate<B> {
Logger logger = Logger.getLogger(TablesTemplate.class);
/**
* 模板方法的子类必须为此dao赋值,并且相应的类必须实现{@link TemplateOnlineServiceDao}
*/
public TemplateOnlineServiceDao templateOnlineServiceDao;
public TemplateOfflineServiceDao templateOfflineServiceDao;
/**
* @param bean 查询条件对象
* @param currPage
* @param pageSize
* @param <T> 返回对象
* @return
* @throws ExceptionCommonBase
*/
public <T> PageData getPageDataFromOnlineAndOffline(B bean, int currPage, int pageSize) throws ExceptionCommonBase {
int totalCount = 0;
PageData pageData = templateOnlineServiceDao.getPageDataFromOnline(bean, currPage, pageSize);
int onlineTotalCount = pageData.getTotal();
totalCount += onlineTotalCount;
List<String> tableNames = templateOfflineServiceDao.getOfflineTables();
List<T> pageList = (List<T>) pageData.getContent();
for (String tableName : tableNames) {
try {
int offlineTotalCount = templateOfflineServiceDao.totalCount(bean, tableName);
if (offlineTotalCount == 0) continue;
int indexNum = (currPage - 1) * pageSize + 1;
int endNum = currPage * pageSize;
if (totalCount >= endNum) {
totalCount = totalCount + offlineTotalCount;
continue;
}
List<T> offlineTableList = templateOfflineServiceDao.listFromOffline(bean, tableName);
List<T> tempList = getSubList(offlineTableList, pageSize, totalCount, offlineTotalCount, indexNum, endNum);
pageList.addAll(tempList);
totalCount = totalCount + offlineTotalCount;
} catch (ExceptionCommonBase e) {
logger.error(e.getMessage(), e);
}
}
pageData.setContent(pageList);
pageData.setTotal(totalCount);
return pageData;
}
/**
* 分页,获取从表的数据并切分
*
* @param offlineTableList
* @param pageSize
* @param totalCount
* @param offlineTotalCount
* @param indexNum
* @param endNum
* @return
*/
private <T> List<T> getSubList(List<T> offlineTableList, int pageSize, int totalCount, int offlineTotalCount, int indexNum, int endNum) {
if (offlineTableList == null || offlineTableList.size() == 0) {
return new ArrayList();
}
int fromIndex = 0;
int toIndex = 0;
if (totalCount >= indexNum) {
if ((totalCount + offlineTotalCount) > endNum) {
toIndex = endNum - totalCount;
} else {
toIndex = offlineTotalCount;
}
} else if (totalCount < indexNum && (totalCount + offlineTotalCount) >= indexNum) {
fromIndex = indexNum - 1 - totalCount;
if ((totalCount + offlineTotalCount) >= endNum) {
toIndex = fromIndex + pageSize;
} else {
toIndex = offlineTotalCount;
}
}
return offlineTableList.subList(fromIndex, toIndex);
}
}
上面代码实现规则:先从主表中取数据,然后依次从从表中查询表的总数,当满足当前页的数据则加入到tempList中,直至加满(=pageSize),如果数据不满足则不做处理
其中TemplateOnlineServiceDao、TemplateOfflineServiceDao 均为接口提供方法如下
package cn.egame.data.core.common;
import cn.egame.common.exception.ExceptionCommonBase;
import cn.egame.common.model.PageData;
import cn.egame.data.model.itv.ItvFee;
import cn.egame.data.model.itv.ItvFeeBean;
import java.util.List;
/**
* Created by dinghw on 2015/4/20.
*/
public interface TemplateOnlineServiceDao<B> {
/**
* @param bean
* @param currPage
* @param pageSize
* @return
* @throws ExceptionCommonBase
* @throws ExceptionCommonBase
*/
public <T> PageData getPageDataFromOnline(B bean, int currPage, int pageSize) throws ExceptionCommonBase;
/**
* @param bean
* @param <T>
* @return
* @throws ExceptionCommonBase
*/
public <T> List<T> listFromOnline(B bean) throws ExceptionCommonBase;
}
package cn.egame.data.core.common;
import cn.egame.common.exception.ExceptionCommonBase;
import java.util.List;
/**
* Created by dinghw on 2015/4/20.
*/
public interface TemplateOfflineServiceDao<B> {
/**
* 获取线下所有表名
*
* @return
* @throws cn.egame.common.exception.ExceptionCommonBase
*/
public List<String> getOfflineTables() throws ExceptionCommonBase;
/**
* 获取表中的总数
*
* @param bean
* @param tableName
* @return
* @throws ExceptionCommonBase
*/
public int totalCount(B bean, String tableName) throws ExceptionCommonBase;
/**
* 查询出线下库表的数据
*
* @param bean
* @param tableName
* @param <T> 返回类型
* @return
* @throws ExceptionCommonBase
*/
public <T> List<T> listFromOffline(B bean, String tableName) throws ExceptionCommonBase;
}
这边TemplateOfflineServiceDao类中getOfflineTables方法,其实可以放到抽象类TablesTemplate,因为这个方法在一定程度上属于service层而不是dao层
上层的架子搭好了,下面就是具体的实现了,拿itv的代码做例子
/**
*
*/
package cn.egame.data.core.itv;
import cn.egame.common.exception.ExceptionCommonBase;
import cn.egame.common.model.PageData;
import cn.egame.data.core.app.AppServiceFactory;
import cn.egame.data.core.common.TablesTemplate;
import cn.egame.data.core.common.TemplateOfflineServiceDao;
import cn.egame.data.core.common.TemplateOnlineServiceDao;
import cn.egame.data.core.cp.CpServiceFactory;
import cn.egame.data.interfaces.IObjectVisitor;
import cn.egame.data.interfaces.ItvFeeService;
import cn.egame.data.model.ContentProvider;
import cn.egame.data.model.app.AppConsume;
import cn.egame.data.model.app.AppInfo;
import cn.egame.data.model.itv.ItvFee;
import cn.egame.data.model.itv.ItvFeeBean;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
/**
* itv计费相关业务实现类
*
* @author houqq
* @date 2014年11月28日 上午9:43:22
*/
public class ItvFeeServiceImpl extends TablesTemplate<ItvFeeBean> implements ItvFeeService {
Logger logger = Logger.getLogger(ItvFeeServiceImpl.class);
private static ItvFeeServiceImpl instance;
private static byte[] syncRoot = new byte[1];
private ItvFeeServiceDao itvFeeServiceDao;
private ItvFeeOfflineDao itvFeeOfflineDao;
private ItvFeeServiceImpl() throws ExceptionCommonBase {
itvFeeServiceDao = new ItvFeeServiceDao();
itvFeeOfflineDao = new ItvFeeOfflineDao();
templateOnlineServiceDao = new ItvFeeServiceDao();
templateOfflineServiceDao = new ItvFeeOfflineDao();
}
public static ItvFeeServiceImpl getInstance() throws ExceptionCommonBase {
if (instance == null) {
synchronized (syncRoot) {
if (instance == null) {
instance = new ItvFeeServiceImpl();
}
}
}
return instance;
}
/**
* 依据条件查询itv计费列表
*
* @param itvFeeBean itv计费实体
* @return itv计费列表
* @throws ExceptionCommonBase
*/
private List<ItvFee> listItvFee(ItvFeeBean itvFeeBean) throws ExceptionCommonBase {
List<ItvFee> itvFees = itvFeeServiceDao.listFromOnline(itvFeeBean);
List<ItvFee> offLineItvFees = itvFeeOfflineDao.listAllFromOffline(itvFeeBean);
itvFees.addAll(offLineItvFees);
return itvFees;
}
/**
* 从主从表中获取数据
*
* @param appId
* @param userId
* @param itvfeebean
* @param currPage
* @param pageSize
* @return
* @throws RemoteException
*/
public PageData listItvFee(int appId, long userId, ItvFeeBean itvfeebean, int currPage, int pageSize) throws RemoteException {
if (StringUtils.isEmpty(itvfeebean.getLinkageAccountId()) && StringUtils.isEmpty(itvfeebean.getPhone())) {
PageData pageData = new PageData();
pageData.setCurrentPage(currPage);
pageData.setRowsOfPage(pageSize);
return pageData;
}
//此处调用父类方法
return this.getPageDataFromOnlineAndOffline(itvfeebean, currPage, pageSize);
}
}
上述代码有一个让我感觉还不够完美的地方,就是dao定义,我必须得重复定义,一方面为了兼容之前的方法,另外一方面,较少TemplateOnlineServiceDao、TemplateOfflineServiceDao两个接口中的方法数量,让子类的dao可存在自己的特性方法
itvFeeServiceDao = new ItvFeeServiceDao();
itvFeeOfflineDao = new ItvFeeOfflineDao();
templateOnlineServiceDao = new ItvFeeServiceDao();
templateOfflineServiceDao = new ItvFeeOfflineDao();
- 大小: 9.6 KB
分享到:
相关推荐
其次,让学生初识并运用设计模式,如GoF(Gang of Four,设计模式四人组)提出的单例模式和模板方法模式,提高代码的可读性和可维护性;最后,整合数据库,实现图书管理的各项功能,如图书的入库、报废,借书证的...
SSM框架是Java Web开发中常用的三大组件——Spring、Struts2和MyBatis的组合,常用于构建大型企业级应用。在这个项目中,`IntelliJ IDEA`作为强大的Java集成开发环境,被用来进行整个项目的开发与管理。 **Spring...
提到“很好的参考作用”,意味着这些代码是具有实践价值的,可以作为模板或者参照来解决类似问题。此外,“以后会继续上传更新”则暗示这是一个动态的项目,作者可能会定期添加新功能、修复错误或改进现有代码,这为...
例如策略模式、模板方法模式、观察者模式、命令模式、迭代器模式、解释器模式、中介者模式、备忘录模式、状态模式、访问者模式和责任链模式。 设计模式的应用能够提高代码的可读性、可维护性和可扩展性,同时减少...
【标题】"ASP.NET源码——[博客空间]BruceBlog程序源码(采用NHibernate).zip" 提供的是一个基于ASP.NET技术开发的博客系统源代码,该系统使用了NHibernate作为持久化框架。这个博客平台是开发者Bruce创建的一个项目...
- **HQL(Hibernate Query Language)**:类似SQL的查询语言,用于在Java代码中查询数据库。 4. **SSH整合**: - **配置整合**:在Spring配置文件中定义Struts的Action和Hibernate的SessionFactory,实现三者的...
WF支持状态机、顺序流程、活动库和规则引擎等多种工作流模式,可以轻松处理复杂的业务逻辑。WF与WCF和WPF等.NET组件紧密集成,能够构建出具有强大工作流支持的应用程序。 通过学习《精通C# 3.0与.NET 3.5高级编程》...
SSH,是Java Web开发中的三大框架——Struts、Hibernate和Spring的缩写,这三大框架在Web应用程序开发中起着核心支撑作用。本篇笔记汇总将深入探讨这三个框架的原理、配置与应用。 首先,Struts2是MVC(Model-View-...
通过这个项目,你可以学习到如何利用Struts2和Hibernate进行基本的Web开发,理解MVC模式,以及在实际应用中如何处理用户管理相关的业务需求。同时,这也为你提供了实践Struts2拦截器、参数校验、页面交互等技术的...
本文将深入探讨该系统背后的技术实现——Hibernate和Struts2框架的集成应用。 Hibernate,作为Java领域中的一个持久化框架,它简化了数据库操作,使得开发者无需关注SQL语法,而是通过对象关系映射(ORM)来处理...
标题中的"集成Hibernate3.6.8+Spring3.0.6+struts2.2.3.0"指的是一个经典的Java Web开发框架整合,它将三个强大的开源框架——Hibernate、Spring和Struts2结合在一起,以实现高效、模块化且可维护的Web应用程序。...
维尔公司推出的U4000b指纹仪是此类设备中的代表,它提供了强大的硬件支持以及易于集成的二次开发接口,使得开发者可以轻松地将指纹识别功能整合到自己的应用程序中。本篇我们将深入探讨"指纹仪二次开发"这一主题,...
- **查询语言**:Hibernate提供了自己的查询语言——HQL(Hibernate Query Language),这是一种类似于SQL的语言,但它是面向对象的,更加直观易懂。 - **缓存机制**:为了提高性能,Hibernate内部提供了一级缓存和...
### 某铜业集团公司全面Intranet的构建 #### 一、背景介绍 某铜业集团公司成立于1996年,是中国有色金属工业总公司为了组建大型企业集团而成立...此外,本案例的成功经验也为其他类似企业提供了一个有价值的参考模板。
过去,网络软件的开发都采用C/S(client)模式,在这种模式下,主要的业务逻辑都集中于客户端程序,因此,必然导致以下问题: 系统安装、调试、维护和升级困难。由于客户端的硬件配置可能存在差异,软件环能各不相同...