加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

DWR详解(二)——反向AJAX

发布时间:2020-12-15 20:58:24 所属栏目:百科 来源:网络整理
导读:上一篇文章(DWR详解一)提到DWR允许javascript访问服务器端的Java方法,这使得AJAX使用起来会比较容易,而在DWR2.0里面添加了一个非常强大的功能——反向AJAX,也就是说,服务器端的Java方法可以取得浏览器端的Web上下文,并可以调用javascript的方法,将服
上一篇文章(DWR详解一)提到DWR允许javascript访问服务器端的Java方法,这使得AJAX使用起来会比较容易,而在DWR2.0里面添加了一个非常强大的功能——反向AJAX,也就是说,服务器端的Java方法可以取得浏览器端的Web上下文,并可以调用javascript的方法,将服务器端的数据异步地传输给浏览器。本文将通过一个demo展示这种特性。这个demo实现了类似股票交易系统中实时更新数据的功能,事实上是通过发布-订阅模式去实现的。也就是说,客户端订阅一个主题,服务器端通过一个线程向订阅这个主题的浏览器定时、异步地发送数据,从而实现了这种实时更新的功能。工程代码请点击这里 下载reverseAjaxDemo

我们知道,客户端浏览器可以随时连接到web服务器,并向服务器请求资源,而服务器却没有这种能力,它不能主动地于客户端浏览器建立连接,并主动地将数据发送给浏览器。DWR支持3种从服务器端发送数据给客户端的方式:

1、轮询。客户端在每个时间周期内向服务器发送请求,看看服务器端有没有数据更新,如果有,就向服务器请求数据。

2、Comet:基于HTTP长连接的服务器推动方式。客户端向服务器发送请求后,服务器将数据通过response发送给客户端,但并不会将此response关闭,而是一直通过response将最新的数据发送给客户端浏览器,直到客户端浏览器关闭。

3、PiggyBack(回传)。服务器端将最新的数据排成队列,然后等待客户端下一次请求,接收到请求后就将等待更新的数据发给客户端。

这3种方式各有优劣,而DWR可以同时支持轮询和Comet。

首先,我们要让DWR程序支持反向AJAX。只需要在web.xml中DWRServlet里添加一个初始化参数:

<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
...
</servlet>

另外,这个demo使用了TIBCO General Interface(GI)的AJAX框架,因此需要引入JSX这个组件库以及在gidemo目录下在config.xml和appCanvas.xml定义需要使用的组件(主要是用到Matrix数据表格这个组件),关于TIBCO GI,请参考http://www.tibco.com/devnet/index.html

这个demo的核心之处在于服务器端的发布者——Publisher.java,在这个类里面,首先通过org.directwebremoting.WebContext来获得访问这个应用的Web上下文:

WebContext webContext = WebContextFactory.get();
ServletContext servletContext = webContext.getServletContext();
serverContext = ServerContextFactory.get(servletContext);

webContext.getScriptSessionsByPage("");

这里主要通过WebContext类获得DWR应用的WEB上下文,用ServletContext获得DWRServlet的上下文,以及通过WEB上下文获取访问本应用的客户端浏览器的ScriptSession。通过ScriptSession,可以在服务器端向客户端浏览器发出执行js方法的指令,并把服务器端数据传送给js方法,具体的用法如下:

Collection sessions = serverContext.getScriptSessionsByPage("/reverseAjaxDemo/index.html");
ScriptProxy proxy = new ScriptProxy(sessions);
Corporation corp = corporations.getNextChangedCorporation();
proxy.addFunctionCall("OpenAjax.publish","gidemo","corporation",corp);

这段代码首先通过getScriptSessionsByPage方法获得所有访问/reverseAjaxDemo/index.html这个资源的客户端浏览器的ScriptSession,并为这些session建立代理(ScriptProxy),通过这个代理,让客户端执行OpenAjax.publish的js方法(见OpenAjax.js)。其中addFunctionCall就是向客户端发送执行js方法的服务器端方法,第一个参数是js方法的签名,后面的都是js方法的参数。其中"gidemo"是服务器端发布的主题(topic),"coporation"是要发布的变量,而corp则是要发布的即时数据。corp这个对象是随机生成的(见Corporation和Corporations类),Publish.java这个类启动了一个线程(worker),这个线程不断地生成corporation的数据,并发布给客户端。

以下是html页面的核心部分的代码:

<div style="width:100%; height:280px;" id="gidemo">
<script. type="text/javascript"
src="JSX/js/JSX30.js"
jsxapppath="gidemo"
jsxlt="true"> </script>
</div>

这一块代码主要是使用了GI的matrix组件,该组件可以动态加载数据。另外,页面引入了index.js,里面有两个个主要方法:


function giLoaded() {
OpenAjax.subscribe("gidemo",objectPublished);
dwr.engine.setActiveReverseAjax(true);
}

function objectPublished(prefix,name,handlerData,corporation) {
var matrix = giApp.getJSXByName("matrix");
var inserted = matrix.getRecordNode(corporation.jsxid);
matrix.insertRecord(corporation,null,inserted == null);

// There are many ways to get a table to repaint.
// One easy way is to ask it to repaint:
// matrix.repaintData();

// But we are going for a fancy option that does highlighting
for (var property in corporation) {
if (property != "jsxid") {
var x = matrix.getContentElement(corporation.jsxid,property);
if (ox) {
var current = ox.innerHTML;
if (current != "" + corporation[property]) {
ox.style.backgroundColor = "#FDE4EB";
var callback = function(ele) {
return function() { ele.style.backgroundColor = "#FFFFFF"; };
}(ox);
setTimeout(callback,1000);
ox.innerHTML = corporation[property];
}
}
}
}
}

giLoaded方法通过OpenAjax.subscribe方法订阅主题为"gidemo"的数据(这些数据由服务器端的Java方法进行发布)。其中objectPublished是一个回调方法,表示取得数据后页面的改变。该回调方法非常简单,只是将matrix组件中发生变化的数据改变一下颜色,实现了实时提醒数据更新的功能。

另外,服务器端还有一个监听器PublisherServletContextListener,这是为了在适当的时候关闭发布者的线程。这个监听器要结合其他两个DWR的监听器使用,只需在web.xml里面声明就行了:

<listener>
<listener-class>org.directwebremoting.servlet.EfficientShutdownServletContextAttributeListener</listener-class>
</listener>
<listener>
<listener-class>org.directwebremoting.servlet.EfficientShutdownServletContextListener</listener-class>
</listener>
<listener>
<listener-class>gidemo.PublisherServletContextListener</listener-class>
</listener>

最后,看一下dwr的映射关系dwr.xml:

<dwr>
<allow>
<create creator="new" javascript="JDate">
<param name="class" value="java.util.Date"/>
</create>
<create creator="new" javascript="Publisher" scope="application">
<param name="class" value="gidemo.Publisher"/>
</create>
<convert converter="bean" match="gidemo.Corporation"/>

<!-- this is a bad idea for live,but can be useful in testing -->
<convert converter="exception" match="java.lang.Exception"/>
<convert converter="bean" match="java.lang.StackTraceElement"/>
</allow>
</dwr>

注意红色部分的配置,dwr允许将自定义的Java类型与js对象进行相互转换,但要声明转换器。

以下是程序运行的结果:


这个例子比较复杂,旨在让大家对反向AJAX的原理有所了解。下一篇文章开始,将用一些简单的例子来说明DWR反向AJAX的用法。

参考资料:

http://getahead.org/dwr/reverse-ajax

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读