一、综述
AjaxRequest是一个非常重要的组件,在一个基于SimpleFramework的项目中,AjaxRequest被使用的概率几乎在50%以上,甚至更多。
在开始介绍AjaxRequest之前,我们首先看看HttpServletRequest,下图介绍一个完整Http请求到响应的生命周期。
一些Web框架(比如:Struts)扩展了Servlet,并通过提供的接口,实现了基于MVC的编程模式,从而取代传统的Servlet编程。如下图:
随着Ajax的流行,基于Ajax的请求变的越来越流行,一般要通过如下几个步骤来实现:
编写客户端代码(javascript)
编写请求代码
通过回调函数处理返回的结果
编写Servlet处理类
返回结果(可以是html、xml、text或json),等待客户端回调函数的处理
一些流行的javascript框架,比如Prototype、jQuery等都提供了对Ajax的封装,您可以很容易的编写客户端的请求代码,这里以Prototype为例:
- new Ajax.Request("/test.action", {
- postBody: "p1=v1&p2=v2",
- encoding: "UTF-8",
- onComplete:function(req) {
- var txt = req.responseText;
- //do data
- }
- );
“/test.action”请求一个Servlet类,并通过业务处理,把需要的数据返回给前端回调函数onComplete。
看似简单的流程,却有很多问题需要关注:
实际的项目有上百个甚至更多Ajax请求,那么前端javascript的数量和Servlet的数量就会增长很快。当javascript出现错误或更改javascript代码都会相当麻烦,至于Servlet,您可以通过Struts等技术替代
提交表单需要拼接参数,有没有更好的办法?
返回数据的解析。建议在Servlet中直接生成json格式
如果返回数据包含javascript文件(脚本)、CSS文件等,如何动态添加到dom中,如果dom中已经存在这些文件,那又该如何处理
需要对返回数据进行缓存,是否可以处理?
解决以上的问题,你需要付出太多的代价,不过,没关系,SimpleFramework提供的AjaxRequest组件,让您用声明的方式,快速完成Ajax请求。
二、原理
三、实践
现在就开始我们的AjaxRequest之旅吧!
3.1 组件的声明
SimpleFramework使用xml文件来描述组件,您可以参考http://simpleframework.net/doc/d2/2.4.1.html获取更为详细的信息。
以下是声明的代码片段:
- <ajaxRequest name="ajaxTestAction" handleClass="net.simpleframework.demo.TestAction"
- handleMethod="testMethod">
- </ajaxRequest>
在组件声明中,名称是必须的,且不能和其它组件名称重复,因为SimpleFramework通过Filter发现如上的定义,就会自动为客户端生成 一个$Actions[“ajaxTestAction”]的javascript对象。在客户端,您就可以通过这个唯一的名称获取其javascript对 象的引用。
如果您不了解$Actions,可以通过http://simpleframework.net/doc/d2/2.4.2.html来了解更多内容。
3.2 与HTML页面元素的事件绑定
HTML页面元素(比如button)如何绑定到AjaxRequest组件“ajaxTestAction”呢?SimpleFramework采用了最原始的方式,代码如下:
- <input type="button" value="提交" onclick="$Actions[‘ajaxTestAction’]();" />
很简单吧,SimpleFramework并没有改变现有的编程习惯,没有标签库,仅仅是简单的HTML和Javascript。
3.3 如何提交数据
Ajax可以通过Get或POST来提交数据,但您必须自己拼接参数序列,这个非常麻烦。SimpleFramework提供了一个属性formSelector,快速提交HTML里您关心的数据区域,参考以下代码:
- <ajaxRequest name="ajaxTestAction" handleClass="net.simpleframework.demo.TestAction"
- handleMethod="testMethod" formSelector=".div1, .div2 select">
再看一下HTML表单的定义:
- <div class="div1">
- ... ...
- </div>
- <div class="div2">
- ... ...
- </div>
- <input type="button" value="提交" onclick="$Actions[‘ajaxTestAction’]();" />
关于selector,如果您了解Prototype、jQuery等javascript框架,那就一定非常熟悉。如果不了解,建议先在网上Google一下,先了解什么是CSS选择器。
上述含义是提交类名为“div1”下的所有表单元素和类名为“div2”下的select元素,这是不是比定义一个form标签要简单很多呢。
注:如果提交二进制文件,需使用submit组件或swfUpload组件。
3.4 编写HandleClass
AjaxRequest组件的HandleClass可以理解为Struts的Action,其接口的定义如下:
- package net.simpleframework.web.page.component.base.ajaxrequest;
- public interface IAjaxRequestHandle extends IComponentHandle {
- IForward ajaxProcess(ComponentParameter compParameter) throws Exception;
- }
如果没有指定handleMethod,则ajaxProcess将会执行,如果指定了handleMethod,则执行名称为handleMethod的方法,其方法结构和ajaxProcess是一样的。
建议您继承AbstractAjaxRequestHandle而不是实现IAjaxRequestHandle,因为抽象父类会提供一些有意义的方法给您使用,对于任何其它组件,这一原则总是适用的。
3.5 IForward介绍
handleClass将会返回IForward接口,类似Struts的ActionForward,但有不同。IForward有三个具体的实现:
TextForward,返回纯文本
JsonForward,返回Json格式的文本,构造时需传递Map、List、Array等类型
UrlForward,返回HTML,构造时需传递url地址
大部分情况,JsonForward是一个更好的选择。
3.6 编写回调脚本
定义回调脚本,参考如下代码:
- <ajaxRequest name="ajaxTestAction" handleClass="net.simpleframework.demo.TestAction"
- handleMethod="testMethod">
- <jsCompleteCallback>
- alert(json);
- alert(responseText);
- </jsCompleteCallback>
- </ajaxRequest>
3.6.1 回调函数原型
在编写jsCompleteCallback的时候,很多用户不知道如何下手,更不知道返回的数据在哪。其实,jsCompleteCallback就是一个javascript函数,只不过采用xml描述,把传递给你的参数省略了。请看jsCompleteCallback原型的定义:
- jsCompleteCallback = function(req, responseText, json) {
- }
解释一下三个参数:
req:原生ajax response对象
responseText:返回的文本对象
json:如果handleClass返回的是JsonForward,则json为解析过的JSON对象
3.6.2 通过属性直接绑定到HTML区域
ajaxRequest很多应用都是返回一段HTML,然后更新到某个区域,如果通过jsCompleteCallback一定会很简单,下面是一段代码样例:
- var div = $("divid");
- div.innerHTML = responseText;
ajaxRequest同时还提供了一个属性updateContainerId,可以不用写jsCompleteCallback,而直接绑定到updateContainerId指定的区域id,不光如此,还能执行responseText中的js函数,代码如下:
- <ajaxRequest name="ajaxTestAction" handleClass="net.simpleframework.demo.TestAction"
- handleMethod="testMethod" updateContainerId="divid">
- </ajaxRequest>
四、高级特性
4.1 动态传递参数
如果提交的数据是变化的,或则ajaxRequest组件是一个,但绑定的HTML元素事件是多个,又该怎么处理呢?
举个实例,比如“发送邮件”,一般分为“保存到草稿”、“直接发送”,因为提交的数据是一样的,则可以通过动态参数传递,在两个按钮的事件上分别绑定到同一个ajaxRequest组件。假设ajaxRequest组件的名称为sentMail,参考如下代码:
- <input type="button" value="保存到草稿" onclick="$Actions[‘sentMail’]('type=0');" />
- <input type="button" value="直接发送" onclick="$Actions[‘sentMail’]('type=1');" />
$Actions[‘sentMail’]其实就是一个函数,你在调用的时候,可以设置参数为拼接的字符串(见代码红色部分),这是一个经常使用的特性。还需要注意一点,参数传递的优先级是高于formSelector的。
4.2 自动加载js及css文件
自动加载js及css文件是ajaxRequest组件一个非常重要的特性,您可以直接在Ajax的返回数据中定义js或css文件,而不必担心它们是否已加载,如何加载等一系列问题。
您可以通过firebug来体验自动加载过程:)
4.3 作为其它组件的引用
组件的引用是SimpleFramework组件体系一个非常实用的功能。比如,window组件通过引用ajaxRequest组件来装载window面板内容,代码如下:
- <ajaxRequest name="ajaxTestPage">
- <urlForward>/window_content.jsp</urlForward>
- </ajaxRequest>
- <window name="testWindow" contentRef="ajaxTestPage" width="480" height="600">
- </window>
当调用了testWindow组件,ajaxTestPage将被触发并返回/window_content.jsp生成的数据到window面板。以后还会对此特性做更多的介绍。
4.4 缓存返回的数据
ajaxRequest组件的缓存功能非常简单,设置属性updateContainerCache=true即可。如果您是注册用户,可以在SimpleFramework站点上体验一下:右上方的个人属性编辑,采用的是标签页,当标签页被打开后,下次将使用缓存功能。
4.5 一些不常用的属性
disabledTriggerAction,当组件被调用时,是否禁止调用元素,默认为true,目的是防止被多次调用,比如用户连续的点击操作
parallel,是否允许并行执行,默认为false,在连续调用ajaxRequest时,在允许并行时,才可同时执行,否则将抛弃当前的调用
jobExecute,执行权限,该属性依赖机构模块
confirmMessage,客户端需要确认的消息
throwException(window、alert),异常的展示方式。提供alert展示或window组件展示,window组件展示可获取更多的异常信息
showLoading,是否显示装载进度(右上角显示),默认为true