html oload多个函数,如何用extjs实现海量数据的快速分页显示

点击查询按钮,会查询出N万条数据。

后台java方法会把查询出的这N万条数据,以JSON格式传送给前台。

代码如:

view plain

JSONObject object = new JSONObject();

object.put("success", true);

object.put("root", dataList);

object.put("totalProperty", total);

//推送给前台

writeResponse(object.toString());

=======================================

/**

* ajax方式返回字符串

* @param str

* @return

*/

public boolean writeResponse(String str){

boolean ret = true;

try{

HttpServletResponse response = ServletActionContext.getResponse();

response.setContentType("text/html;charset=utf-8");

PrintWriter pw = response.getWriter();

pw.print(str);

pw.close();

}catch (Exception e) {

ret = false;

e.printStackTrace();

}

return ret;

}

=======================================

项目框架:SSH+ExtJs。

客户情况:客户等不起grid显示的loading...

开发人员:不是我的错,是数据太多,慢慢等吧

DBA意见: 不是我的错,Oracle根本不拥塞

好吧,我们来看看实现过程,一定有优化的地方,只是我们还没发现或不愿意去发现而已。

如果一次性查询出的dataList是超过千行甚至万行级的海量数据,若再将dataList以JSON格式传送给前台,势必会影响前台的显示速度。

如果给grid设置了loadMask,你一定会看到那个loading...一直在loading,直到把你loading到不耐烦。

实际上,当JSON打包的数据超过千行时,就已经有明显的等待时间了(当然,与数据库的性能也有关)。

我们知道在EXT中,如果数据量比较大时,通常给Grid配置分页工具栏PageBar,PageBar再配置grid的store,并设置pageSize,来完成数据分页显示的功能。这是最友好的显示方式。其实这也给我们暗示了一种理念,就是gird到底一次需要读取多少条数据。答案是肯定的,那就是pageSize条数据。

以此为出发点,我们会产生疑问,难道我们只需要读取pageSize条数据?那PageBar的总页数岂不是只有pageSize条数据了,这明显与实际是不符的!比如实际上如果有1W条数据,但由于pageSize设置了10条,那按照以上逻辑,只需要去读取top 10条?若数据库中只有这10条数据,那毫无疑问,PageBar的总页数就是10条了。

以上怀疑是正确的,没有错误。错误的是我们在实现上,没看清一个关键问题。那就是gird和PageBar共享同一个store。这个store有多少数据,PageBar就会有多少条数据。也就是说,gird和PageBar都傻傻地依赖着同一个store!

那要是gird和PageBar不是同一个store,且要去完成同一片数据的分页功能,那能实现吗?答案也是肯定的,这也是本文预介绍的内容:用ext实现海量数据的快速分页显示。

既然知道了gird和PageBar有了这层关系(共享同一个store,这个store总是一次性加载完所有的数据),那我们就借位思考,打破它们俩这种藕断丝连的关系:让gird和PageBar分别有自己的store!让这两个store去共享那片数据区(本来就应该这样,数据是共有的,至于谁读不读,那是他自己的事。只是EXTJS把这两个组件通过store联系在一起)。

那怎么实现呢?

原理是:GridPanel的store第一次只装载GRID_PAGE_SIZE条记录即可,PageBar的store第一次只装载总记录数。当需要翻页时,给GridPanel的store传递当前页数和PageBar显示的总条数。

第一步,让gird和PageBar分别有自己的store

view plain

var resultPanel = new top.Ext.grid.GridPanel( {

// title : '搜索结果',

ds : store,

height : 153,// autoHeight:true,

sm : new top.Ext.grid.RowSelectionModel( {

singleSelect : true

}),

cm : cm,

viewConfig : {

forceFit : true

},

// view : new top.Ext.ux.grid.BufferView({

// rowHeight : 20,

// scrollDelay : false

// }),

border : false,

columnLines : false,

frame : false,

autoScroll : true,

trackMouseOver : true,

loadMask : true,

id : 'ridGrid',

stripeRows : true,

bbar : new top.Ext.ux.DynamicPageBar( {

pageSize : GRID_PAGE_SIZE,

store : storeDetailPage,

cls : 'toolbar_bottom',

autoload : true,

displayInfo : true

})

});

可以看到grid和PageBar分别有自己的store。而它们俩的store要共享同一部分数据,就要指定同一个action URL,并且传递同样的参数,即指向同一个java方法即可。

第二步,让gird和PageBar各自的store共享同一片数据区。

其中,grid的store定义为:

view plain

var store = new top.Ext.data.Store( {

proxy : new top.Ext.data.HttpProxy( {

url : path + '/QueryAction!queryDetailData.action',

timeout : EXT_QUERY_TIME_OUT

}),

reader : reader,

listeners : {

load : function() {

isDetailReady = true;// 查询置换标志为已查过

}

}

});

PageBar的store定义为:

view plain

var storeDetailPage = new top.Ext.data.Store( {

proxy : new top.Ext.data.HttpProxy( {

url : path + '/QueryAction!queryDetailData.action',

timeout : EXT_QUERY_TIME_OUT

}),

reader : reader,

listeners : {

load : function() {

if (isDetailReady) {

if (!this.isDetailConfigured) {

// 只在第一次加载完毕的时候,为Grid重新赋数据源

resultPanel.reconfigure(storeDetailPage, cm);

storeDetailPage.baseParams.total = storeDetailPage.getTotalCount();

isDetailConfigured = true;

}

// 下一页的时候就不用重复赋数据源了

} else {

var o = this; // 解决setTimeout的参数中有this的问题

setTimeout(function() {

o.load()

}, VEHICLEPASSTORE_TIMETERVAL);// VEHICLEPASSTORE_TIMETERVAL毫秒

}

上面看到了几个变量,定义为全局变量吧:

view plain

var VEHICLEPASSTORE_TIMETERVAL = 100;// 查询时,轮训判断VehiclePassStore是否加载完毕的时间间隔,毫秒级别

var EXT_QUERY_TIME_OUT = 1200000; // EXT查询超时时间

var isDetailReady = false;// 判断Grid的store是否加载完毕

var isDetailConfigured = false;

第三步,让查询干点活--传递适当的参数

view plain

var btnSearch = new top.Ext.Button( {

width : 70,

height : 23,

text : '查询',

listeners : {

click : function() {

isDetailReady = false;

isDetailConfigured = false;

store.baseParams = {

operate : "Search",

/*参数列表区*/,

limit : 50,//grid第一次查询50条

total : 50

};

store.load();

storeDetailPage.baseParams = {

operate : "Search",

/*参数列表区*/,

limit : 50,

total : -1 //如果total是-1,即count记录数给PageBar

};

storeDetailPage.load();

}

}

});

好了,除了对应的java方法没给出外,上面的JS已经可以实现我们需要的功能了。

当然,上面是点击按钮触发的事件。如果是一打开页面就触发的话,我们就要把click : function() 里面的代码写在某个组件的

view plain

listeners : {

'afterrender' : function() {

/*here*/

}.createDelegate(this)

}

的afterrender里就可以了。

更完整的步骤:

第四步:java实现方法

Action:

view plain

public void queryDetailData() {

// 调用service,进行查询处理

Page page = QueryService.queryDetailData(start, limit,pInfo,total);

if (page != null)

{

vehicleInfo = (List) page.getResult();

if(vehicleInfo != null)

{

。。。 }

total = page.getTotalCount();

}

JSONObject object = new JSONObject();

object.put("success", true);

object.put("totalProperty", vehicleInfo);

object.put("total", page.getTotalCount());

//控制台打印

System.out.println(object.toString());

//推送给前台

writeResponse(object.toString());

// 记录日志

this.addOperationLog(...);

}

Service层:

view plain

public Page queryDetailData(int startIndex, int pageSize,String pInfo,long total){

....

return QueryDAO.queryDetailData(queryCountSql.toString(), queryResultSql.toString(),startIndex, pageSize,total);

}

DAO层:

view plain

@SuppressWarnings("unchecked")

public Page queryDetailData(final String countSql,final String resultSql,final int startIndex, final int pageSize, final long total)

{

Page result = (Page)getHibernateTemplate()

.execute(new HibernateCallback()

{

public Object doInHibernate(Session session) throws HibernateException, SQLException

{

long totalCount = 0;

if(total < 0)

{

List countlist = session.createSQLQuery(countSql).list();

for(int i=0;i

{

totalCount+= Long.parseLong(countlist.get(i).toString());

}

}

else

{

totalCount = total;

}

if (totalCount < 1)

{

return new Page();

}

// 实际查询返回分页对象

Query query = session.createSQLQuery(resultSql)

.addScalar("字段名1", Hibernate.STRING)

.addScalar("字段名2", Hibernate.STRING)

.addScalar("字段名3", Hibernate.STRING)

.addScalar("字段名4", Hibernate.STRING)

.addScalar("字段名5", Hibernate.STRING)

。。。

.setResultTransformer(Transformers.aliasToBean(VehicleInfo.class));

if (pageSize > 0)

{

if (startIndex < 0)

{

query.setFirstResult(0);

}

else if (startIndex >= totalCount)

{

return new Page();

}

else

{

query.setFirstResult(startIndex);

}

if(startIndex+pageSize > totalCount)

{

query.setMaxResults((int)totalCount-startIndex);

}

else

{

query.setMaxResults(pageSize);

}

}

return new Page(startIndex, totalCount, pageSize, query.list());

}

});

return result;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值