Ext.data.Store若干问题的探讨

前几年做个社区的时候,一哥们用它做了后台,导航、Grid都很方便,他都搭好环境了,也就没有仔细研究了。最近自己想做一个项目,验证一下ExtJS。只是做了三个样例的验证:

1. 登录对话框

2. 基于Accordion Layout的首页

3. Grid分页

前面两个都比较顺利了,第三个Grid遇到了一个大家经常碰到的问题:Server回来数据,但Grid一直没有显示。这个问题纠结了我一下午。网上搜索了一大堆,这个问题比较常见。现在总结一下可能的原因有:

1. 返回的数据格式不正确

2. 定义的Ext.data.Model不正确

3. 并未按照ExtJS规范使用远程数据源

前面两个问题一般都是编码问题,这个简单的Human Error我们就不讨论了。第三个问题是我碰到的,也比较有意义,就跟大家探讨一番。我用的ExtJS版本是ext-4.0.7-gpl,新版本上有些类已经改变了名字。

我们知道,要构造一个Ext.grid.Panel需要一个Ext.data.Store。Ext.data.Store类封装了客户端的数据模型(Ext.data.Model),它通过Ext.data.proxy.Proxy来加载数据,Store自身也还提供了排序、过滤、查询数据的功能。我们看个示例:

Ext.define('User', {
    extend: 'Ext.data.Model',
    fields: [
        {name: 'firstName', type: 'string'},
        {name: 'lastName',  type: 'string'},
        {name: 'age',       type: 'int'},
        {name: 'eyeColor',  type: 'string'}
    ]
});
var store = Ext.create('Ext.data.Store', {
    autoLoad: true,
    model: "User",
    proxy: {
        type: 'ajax',
        url : 'users.json',
        reader: {
            type: 'json',
            root: 'users'
        }
    }
});

 

前面首先定义了一个数据模型User,下面创建一个Store,通过model指定数据模型(我们也可以在创建Store时通过设置data属性来指定数据模型),通过proxy指定了数据访问代理。Ext.data.proxy.Proxy的type指定了Proxy的类型,reader指定了数据解析器,用来解析服务器端返回的数据。

Proxy的类型可以分为两大类:Client和Server。

 Client  LocalStorageProxy - saves its data to localStorage if the browser supports it type: 'localstorage' 
 Client  SessionStorageProxy - saves its data to sessionStorage if the browsers supports it type: 'sessionstorage'
 Client  MemoryProxy - holds data in memory only, any data is lost when the page is refreshed type: 'memory'
 Server  Ajax - sends requests to a server on the same domain type: 'ajax'
 Server  JsonP - uses JSON-P to send requests to a server on a different domain type: 'jsonp'
 Server  Direct - uses Ext.direct.Manager to send requests type: 'direct'

 

Ext.data.reader.Reader比较简单,经常使用的两种JSON和XML。

我的Grid没有显示数据的原因在于使用了跨域的数据来源。如果你不是跟我类似的问题,也记得坚持Proxy是否配置正确。从上面Proxy的类型来看,跨域的访问只有选择JSONP了,我开始错误的使用了Ajax。JSON和JSONP有啥区别呢?这有篇文章介绍【注1】,JSONP的出现主要是解决Ajax跨域访问无权限的问题,JS具有跨域的能力。Ajax和JSONP的本质区别在于,Ajax的核心是通过XmlHttpRequest获取非本页内容,而JSONP的核心则是动态添加添加<script>标签来调用服务器提供的js脚本。

真正使用JSONP需要一个回调函数和<script>标签的,但ExtJS和jQuery都做了封装,让你可以像Ajax一样在客户端使用。服务器端并不能直接使用,对于使用JSONP类型的Proxy,Server端需要给JSON数据添加上括号('(',')')。

完整的Demo代码:

JS:

Ext.onReady(function(){
	var itemsPerPage = 2;
	// Set up a model to use in our Store
	Ext.define('User', {
	    extend: 'Ext.data.Model',
	    fields: [
	        {name: 'email', type: 'string'},
	        {name: 'name',  type: 'string'},
	        {name: 'phone', type: 'int'}
	    ]
	});
	var store = Ext.create('Ext.data.Store', {
	    id:'simpsonsStore',
	    autoLoad: false,
	    model: 'User',
	    pageSize: itemsPerPage, // items per page
	    proxy: {
	        type: 'jsonp',
	        url: 'http://127.0.0.1:8080/services//servlet/ExtJSPageTest',  // url that will load data with respect to start and limit params
	        reader: {
	            type: 'json',
	            root: 'items',
	            totalProperty: 'total',
	            failure : function() {    
					Ext.Msg.alert("数据加载失败!");    
				}
	        }
	    }
	});
	
	// specify segment of data you want to load using params
	store.load({
	    params:{
	        start:0,
	        limit: itemsPerPage
	    },
	    callback: function(records, operation, success) {
	        //the operation object contains all of the details of the load operation
	        console.log(records);
	    }
	});
	
	Ext.create('Ext.grid.Panel', {
	    title: 'Simpsons',
	    store: store,
	    columns: [
	        {header: 'Email',  dataIndex: 'email'},
	        {header: 'Name', dataIndex: 'name'},
	        {header: 'Phone', dataIndex: 'phone'}
	    ],
	    width: 400,
	    height: 125,
	    loadMask: { msg: '正在加载数据,请稍侯……' }, 
	    dockedItems: [{
	        xtype: 'pagingtoolbar',
	        store: store,   // same store GridPanel is using
	        dock: 'bottom',
	        displayInfo: true
	    }],
	    renderTo: Ext.getBody()
	});
});

Java Server:

protected void service(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {
	int start = Integer.parseInt(request.getParameter("start"));
	int limit = Integer.parseInt(request.getParameter("limit"));
	String cb = request.getParameter("callback");
	List userList = new ArrayList();
	User user1 = new User("Lisa", "[email protected]", "555-111-1224");
	User user2 = new User("Lisa", "[email protected]", "555-111-1224");
	User user3 = new User("Bart", "[email protected]", "555-111-1224");
	User user4 = new User("Lisa", "[email protected]", "555-111-1224");
	userList.add(user1);
	userList.add(user2);
	userList.add(user3);
	userList.add(user4);
	List currentList = new ArrayList();
	if (start + limit <= userList.size()) {
		for (int i = start; i < start + limit; i++) {
			currentList.add(userList.get(i));
			System.out.println(userList.get(i));
		}
	} else {
		for (int i = start; i < userList.size(); i++) {
			currentList.add(userList.get(i));
			System.out.println(userList.get(i));
		}

	}		
	boolean jsonP = false;		
	if (cb != null) {
	    jsonP = true;
	    response.setContentType("text/javascript");
	} else {
	    response.setContentType("application/x-json");
	}
	if (jsonP) {
		response.getWriter().write(cb + "(");
	}		
	JSONArray jsonList = JSONArray.fromObject(currentList);
	response.setCharacterEncoding("utf-8");
	response.getWriter().print(
			"{\"total\":" + limit + ",\"items\":" + jsonList + "}");
	if (jsonP) {
		response.getWriter().write(");");
	}
}

 

注1:http://blog.jobbole.com/18012/

你可能感兴趣的:(Ext.data.Store若干问题的探讨)