0
点赞
收藏
分享

微信扫一扫

Ext Js中数据代理的学习


1:Ext.data.DataProxy

     DataProxy的意思就是数据代理,基类是DataProxy,在Ext Js中,数据代理类又扩展了三个数据代理类:MemoryProxy, HttpProxy和ScriptTagProxy,数据代理类是一个纯虚类,主要用于生成Ext.data.Record对象,没有公共的属性和方法,只是规定了子类需要处理三个事件:

beforeload: {Object this, Object params}
load: {Object this, Object o, Object arg}
loadexception: {Object this, Object o, Object arg, Object e}


2:Ext.data.MemoryProxy

   

/**
* @class Ext.data.MemoryProxy
* @extends Ext.data.DataProxy
* An implementation of Ext.data.DataProxy that simply passes the data specified in its constructor
* to the Reader when its load method is called.
* @constructor
* @param {Object} data The data object which the Reader uses to construct a block of Ext.data.Records.
*/
Ext.data.MemoryProxy = function(data){
// Must define a dummy api with "read" action to satisfy DataProxy#doRequest and Ext.data.Api#prepare *before* calling super
var api = {};
api[Ext.data.Api.actions.read] = true;
Ext.data.MemoryProxy.superclass.constructor.call(this, {
api: api
});
this.data = data;
};

Ext.extend(Ext.data.MemoryProxy, Ext.data.DataProxy, {
/**
* @event loadexception
* Fires if an exception occurs in the Proxy during data loading. Note that this event is also relayed
* through {@link Ext.data.Store}, so you can listen for it directly on any Store instance.
* @param {Object} this
* @param {Object} arg The callback's arg object passed to the {@link #load} function
* @param {Object} null This parameter does not apply and will always be null for MemoryProxy
* @param {Error} e The JavaScript Error object caught if the configured Reader could not read the data
*/

/**
* MemoryProxy implementation of DataProxy#doRequest
* @param {String} action
* @param {Ext.data.Record/Ext.data.Record[]} rs If action is load, rs will be null
* @param {Object} params An object containing properties which are to be used as HTTP parameters
* for the request to the remote server.
* @param {Ext.data.DataReader} reader The Reader object which converts the data
* object into a block of Ext.data.Records.
* @param {Function} callback The function into which to pass the block of Ext.data.Records.
* The function must be passed <ul>
* <li>The Record block object</li>
* <li>The "arg" argument from the load function</li>
* <li>A boolean success indicator</li>
* </ul>
* @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed.

Defaults to the browser window.
* @param {Object} arg An optional argument which is passed to the callback as its second parameter.
*/
doRequest : function(action, rs, params, reader, callback, scope, arg) {
// No implementation for CRUD in MemoryProxy. Assumes all actions are 'load'
params = params || {};
var result;
try {
result = reader.readRecords(this.data);
}catch(e){
// @deprecated loadexception
this.fireEvent("loadexception", this, null, arg, e);

this.fireEvent('exception', this, 'response', action, arg, null, e);
callback.call(scope, null, arg, false);
return;
}
callback.call(scope, result, arg, true);
}
});


load方法是被store调用的,MemoryProxy调用store传入的DataReader读取构造函数中传入的数据对象,这样就可以证明传入的数据的格式必须可以被DataReader读取,如果要传入一个Array数组对象,那么DataReader就得到了一个ArrayReader


load(Object params, Ext.data.DataReader reader, Function callback, Object scope, Object arg);用来取数据,和HttpProxy相似,只是params参数没有被使用。

   使用实例:

   

var proxy = new Ext.data.MemoryProxy([[
1, 'Bill', 'Gardener'
], [
2, 'Ben', 'Horse'
]]);
var reader = new Ext.data.ArrayReader({id: 0}, [
{name: 'name', mapping: 1},
{name: 'occupation', mapping: 2}
]);
var metadata;
function callback(data, arg, success) {
metadata = data;
}

proxy.load(null, reader, callback, this);


3:Ext.data.HttpProxy


An implementation of Ext.data.DataProxy that processes data requests within the same domain of the originating page.

Note: this class cannot be used to retrieve data from a domain other than the domain from which the running page was served. For cross-domain requests, use a ScriptTagProxy.

Be aware that to enable the browser to parse an XML document, the server must set the Content-Type header in the HTTP response to "text/xml".


      HttpProxy使用HTTP协议,通过Ajax去后台取数据,构造它时需要设置url: 'xxx.jsp'参数,这里的url可以替换任何一个合法的地址,这样HttpProxy才知道去哪里获取数据,

如下所示:

/**
* @class Ext.data.HttpProxy
* @extends Ext.data.DataProxy
* <p>An implementation of {@link Ext.data.DataProxy} that processes data requests within the same
* domain of the originating page.</p>
* <p><b>Note</b>: this class cannot be used to retrieve data from a domain other
* than the domain from which the running page was served. For cross-domain requests, use a
* {@link Ext.data.ScriptTagProxy ScriptTagProxy}.</p>
* <p>Be aware that to enable the browser to parse an XML document, the server must set
* the Content-Type header in the HTTP response to "<tt>text/xml</tt>".</p>
* @constructor
* @param {Object} conn
* An {@link Ext.data.Connection} object, or options parameter to {@link Ext.Ajax#request}.
* <p>Note that if this HttpProxy is being used by a {@link Ext.data.Store Store}, then the
* Store's call to {@link #load} will override any specified <tt>callback</tt> and <tt>params</tt>
* options. In this case, use the Store's {@link Ext.data.Store#events events} to modify parameters,
* or react to loading events. The Store's {@link Ext.data.Store#baseParams baseParams} may also be
* used to pass parameters known at instantiation time.</p>
* <p>If an options parameter is passed, the singleton {@link Ext.Ajax} object will be used to make
* the request.</p>
*/
Ext.data.HttpProxy = function(conn){
Ext.data.HttpProxy.superclass.constructor.call(this, conn);

/**
* The Connection object (Or options parameter to {@link Ext.Ajax#request}) which this HttpProxy
* uses to make requests to the server. Properties of this object may be changed dynamically to
* change the way data is requested.
* @property
*/
this.conn = conn;

// nullify the connection url. The url param has been copied to 'this' above. The connection
// url will be set during each execution of doRequest when buildUrl is called. This makes it easier for users to override the
// connection url during beforeaction events (ie: beforeload, beforewrite, etc).
// Url is always re-defined during doRequest.
this.conn.url = null;

this.useAjax = !conn || !conn.events;

// A hash containing active requests, keyed on action [Ext.data.Api.actions.create|read|update|destroy]
var actions = Ext.data.Api.actions;
this.activeRequest = {};
for (var verb in actions) {
this.activeRequest[actions[verb]] = undefined;
}
};

Ext.extend(Ext.data.HttpProxy, Ext.data.DataProxy, {
/**
* Return the {@link Ext.data.Connection} object being used by this Proxy.
* @return {Connection} The Connection object. This object may be used to subscribe to events on
* a finer-grained basis than the DataProxy events.
*/
getConnection : function() {
return this.useAjax ? Ext.Ajax : this.conn;
},

/**
* Used for overriding the url used for a single request. Designed to be called during a beforeaction event. Calling setUrl
* will override any urls set via the api configuration parameter. Set the optional parameter makePermanent to set the url for
* all subsequent requests. If not set to makePermanent, the next request will use the same url or api configuration defined
* in the initial proxy configuration.
* @param {String} url
* @param {Boolean} makePermanent (Optional) [false]
*
* (e.g.: beforeload, beforesave, etc).
*/
setUrl : function(url, makePermanent) {
this.conn.url = url;
if (makePermanent === true) {
this.url = url;
this.api = null;
Ext.data.Api.prepare(this);
}
},

/**
* HttpProxy implementation of DataProxy#doRequest
* @param {String} action The crud action type (create, read, update, destroy)
* @param {Ext.data.Record/Ext.data.Record[]} rs If action is load, rs will be null
* @param {Object} params An object containing properties which are to be used as HTTP parameters
* for the request to the remote server.
* @param {Ext.data.DataReader} reader The Reader object which converts the data
* object into a block of Ext.data.Records.
* @param {Function} callback
* <div class="sub-desc"><p>A function to be called after the request.
* The <tt>callback</tt> is passed the following arguments:<ul>
* <li><tt>r</tt> : Ext.data.Record[] The block of Ext.data.Records.</li>
* <li><tt>options</tt>: Options object from the action request</li>
* <li><tt>success</tt>: Boolean success indicator</li></ul></p></div>
* @param {Object} scope The scope (<code>this</code> reference) in which the callback function is executed. Defaults to the browser window.
* @param {Object} arg An optional argument which is passed to the callback as its second parameter.
* @protected
*/
doRequest : function(action, rs, params, reader, cb, scope, arg) {
var o = {
method: (this.api[action]) ? this.api[action]['method'] : undefined,
request: {
callback : cb,
scope : scope,
arg : arg
},
reader: reader,
callback : this.createCallback(action, rs),
scope: this
};

// If possible, transmit data using jsonData || xmlData on Ext.Ajax.request (An installed DataWriter would have written it there.).
// Use std HTTP params otherwise.
if (params.jsonData) {
o.jsonData = params.jsonData;
} else if (params.xmlData) {
o.xmlData = params.xmlData;
} else {
o.params = params || {};
}
// Set the connection url. If this.conn.url is not null here,
// the user must have overridden the url during a beforewrite/beforeload event-handler.
// this.conn.url is nullified after each request.
this.conn.url = this.buildUrl(action, rs);

if(this.useAjax){

Ext.applyIf(o, this.conn);

// If a currently running request is found for this action, abort it.
if (this.activeRequest[action]) {

// Disabled aborting activeRequest while implementing REST. activeRequest[action] will have to become an array
// TODO ideas anyone?
//
//Ext.Ajax.abort(this.activeRequest[action]);
}
this.activeRequest[action] = Ext.Ajax.request(o);
}else{
this.conn.request(o);
}
// request is sent, nullify the connection url in preparation for the next request
this.conn.url = null;
},

/**
* Returns a callback function for a request. Note a special case is made for the
* read action vs all the others.
* @param {String} action [create|update|delete|load]
* @param {Ext.data.Record[]} rs The Store-recordset being acted upon
* @private
*/
createCallback : function(action, rs) {
return function(o, success, response) {
this.activeRequest[action] = undefined;
if (!success) {
if (action === Ext.data.Api.actions.read) {
// @deprecated: fire loadexception for backwards compat.
// TODO remove
this.fireEvent('loadexception', this, o, response);
}
this.fireEvent('exception', this, 'response', action, o, response);
o.request.callback.call(o.request.scope, null, o.request.arg, false);
return;
}
if (action === Ext.data.Api.actions.read) {
this.onRead(action, o, response);
} else {
this.onWrite(action, o, response, rs);
}
};
},

/**
* Callback for read action
* @param {String} action Action name as per {@link Ext.data.Api.actions#read}.
* @param {Object} o The request transaction object
* @param {Object} res The server response
* @fires loadexception (deprecated)
* @fires exception
* @fires load
* @protected
*/
onRead : function(action, o, response) {
var result;
try {
result = o.reader.read(response);
}catch(e){
// @deprecated: fire old loadexception for backwards-compat.
// TODO remove
this.fireEvent('loadexception', this, o, response, e);

this.fireEvent('exception', this, 'response', action, o, response, e);
o.request.callback.call(o.request.scope, null, o.request.arg, false);
return;
}
if (result.success === false) {
// @deprecated: fire old loadexception for backwards-compat.
// TODO remove
this.fireEvent('loadexception', this, o, response);

// Get DataReader read-back a response-object to pass along to exception event
var res = o.reader.readResponse(action, response);
this.fireEvent('exception', this, 'remote', action, o, res, null);
}
else {
this.fireEvent('load', this, o, o.request.arg);
}
// TODO refactor onRead, onWrite to be more generalized now that we're dealing with Ext.data.Response instance
// the calls to request.callback(...) in each will have to be made identical.
// NOTE reader.readResponse does not currently return Ext.data.Response
o.request.callback.call(o.request.scope, result, o.request.arg, result.success);
},
/**
* Callback for write actions
* @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
* @param {Object} trans The request transaction object
* @param {Object} res The server response
* @fires exception
* @fires write
* @protected
*/
onWrite : function(action, o, response, rs) {
var reader = o.reader;
var res;
try {
res = reader.readResponse(action, response);
} catch (e) {
this.fireEvent('exception', this, 'response', action, o, response, e);
o.request.callback.call(o.request.scope, null, o.request.arg, false);
return;
}
if (res.success === true) {
this.fireEvent('write', this, action, res.data, res, rs, o.request.arg);
} else {
this.fireEvent('exception', this, 'remote', action, o, res, rs);
}
// TODO refactor onRead, onWrite to be more generalized now that we're dealing with Ext.data.Response instance
// the calls to request.callback(...) in each will have to be made similar.
// NOTE reader.readResponse does not currently return Ext.data.Response
o.request.callback.call(o.request.scope, res.data, res, res.success);
},

// inherit docs
destroy: function(){
if(!this.useAjax){
this.conn.abort();
}else if(this.activeRequest){
var actions = Ext.data.Api.actions;
for (var verb in actions) {
if(this.activeRequest[actions[verb]]){
Ext.Ajax.abort(this.activeRequest[actions[verb]]);
}
}
}
Ext.data.HttpProxy.superclass.destroy.call(this);
}
});


实例代码:

   

var store = new Ext.data.store({
r1: 'xxx.jsp',
reader: new Ext.data.xmlReader({
record: 'plant'
}, Plant),
sortInfo: {
field: 'common',
direction: 'asc'
}
});
store.load();


store的load方法调用proxy的load方法,传入的参数如下

    *params:store.load(options)时传入的参数对象options,在store的load方法中会对options进行封装。

    *reader: store中DataReader, 此处为Ext.data.XmlReader

    *callback:store的loadRecords方法

    *scope:回调函数执行的作用域,如是让loadRecords方法在store方法中执行,还是在其他对象中执行。

    *arg: store.load(options)时传入的参数对象options,没有进行封装的options。

在HttpProxy的load方法中,首先发起一个新的请求,在获取数据前触发beforeload事件


4:Ext.data.ScriptTagProxy


An implementation of ​​Ext.data.DataProxy​​ that reads a data object from a URL which may be in a domain other than the originating domain of the running page.

Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain of the running page, you must use this class, rather than HttpProxy.

must

In order for the browser to process the returned data, the server must wrap the data object with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy. Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy depending on whether the callback name was passed:

     Ext.data.ScriptTagProxy是解决跨域访问的,在服务器端需要做一些处理,而不是单纯的返回JSON字符串,下面是实例:

     

boolean scriptTag = false;
String cb = request.getParameter("callback");
if (cb != null) {
scriptTag = true;
response.setContentType("text/javascript");
} else {
response.setContentType("application/x-json");
}
Writer out = response.getWriter();
if (scriptTag) {
out.write(cb + "(");
}
out.print(dataBlock.toJsonString());
if (scriptTag) {
out.write(");");
}

     代码中通过判断请求中是否包含callback参数来决定返回何种数据类型,如果包含,就返回ScriptTagProxy需要的数据,否则就当作HttpProxy处理。

<!--省略部分代码-->
String cb = request.getParameter("callback");
response.setContentType("text/javascript");
Writer out = response.getWriter();
out.write(cb + "(");
out.print("[" +
"['id1', 'name1', 'descn1']" +
"['id2', 'name2', 'descn2']" +
"]");

out.write(");");
<!--省略部分代码-->


   其中的关键就在于从请求中获得的callback参数,这个参数就叫做回调函数。ScriptTagProxy会在当前的HTML页面里添加一个<script type="text/javascript" src="xxx.jsp"></script>的标签,然后把后台返回的内容添加到这个标签中,这样就可以解决跨域访问数据的问题,为了让后台返回的内容可以在动态生成的标签中运行,Ext Js会生成一个名为callback的回调函数,并把回调函数的名称传递到后台,由后台生成callback(data)形式的响应内容,然后返回给前台自动运行。





  

 

举报

相关推荐

0 条评论