最近在开发客服第三方支付功能的时候,发现了主从表分页查询存在问题,然后解决了这个问题后,想将修改后的核心代码迁移到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
分享到:
相关推荐
XXX系统——程序源代码模板.pdfXXX系统——程序源代码模板.pdfXXX系统——程序源代码模板.pdfXXX系统——程序源代码模板.pdfXXX系统——程序源代码模板.pdfXXX系统——程序源代码模板.pdf
模板分析——SVG黑科技互动排版『左右滑动』模板代码
404错误页面模板————仿window登陆页面
模板分析——SVG排版公众号文章『长图手动滚动』模板代码
模板ACM———浙江大学与吉林大学 模板ACM———浙江大学与吉林大学 模板ACM———浙江大学与吉林大学 模板ACM———浙江大学与吉林大学 模板ACM———浙江大学与吉林大学
项目文档模板——概要设计项目文档模板——概要设计项目文档模板——概要设计项目文档模板——概要设计项目文档模板——概要设计项目文档模板——概要设计项目文档模板——概要设计项目文档模板——概要设计
实验报告模板——实验1:类和简单对象.pdf实验报告模板——实验1:类和简单对象.pdf实验报告模板——实验1:类和简单对象.pdf实验报告模板——实验1:类和简单对象.pdf实验报告模板——实验1:类和简单对象.pdf实验...
工作总结报告模板——业务部.doc
网页模板——扣代码工具 javascript事件 捕获者2.0
网页模板——html5在线代码编辑器输入爆炸动画特效源码
C++入门学习——模板,相关教程链接如下: http://blog.csdn.net/tennysonsky/article/details/46625115
旅游ppt模板资源——计算机综合实验七
基础算法 —— 代码模板链接 常用代码模板1——基础算法 排序 二分 高精度 前缀和与差分 双指针算法 位运算 离散化 区间合并 数据结构 —— 代码模板链接 常用代码模板2——数据结构 链表与邻接表:树与图的存储 ...
国家标准软件开发文档模板————可以帮助一些不喜欢些项目文档的或者是不知道怎么写文档的朋友解决很大的问题!~试试看
基础算法 —— 代码模板链接 常用代码模板1——基础算法 排序 二分 高精度 前缀和与差分 双指针算法 位运算 离散化 区间合并 数据结构 —— 代码模板链接 常用代码模板2——数据结构 链表与邻接表:树与图的存储 ...
ppt资源模板
网页模板——vue实现动态表格数据查询筛选代码
秘书处工作计划模板2020——范文..doc
优秀个人简历模板列表——都是格式.doc
关于提交述职报告的通知(参考模板)——【精品模板】..doc