主题:客户端在装载页面时调用 dwr 的方法连接服务端,服务端记录下WebContext 的特征,并启动一个永远run的线程,用以查看是否有新的通知,如果有新的通知就通过 dwr 调用所有停留在该页面的客户端的脚本,以达到推送通知的目的。
1, web.xml
<web-app>
<listener>
<listener-class>org.directwebremoting.servlet.DwrListener</listener-class>
</listener>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWRServlet</display-name>
<description>Direct WebRemoter Servlet</description>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>pollAndCometEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>initApplicationScopeCreatorsAtStartup</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>jsonpEnabled</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
……
</web-app>
2,dwr.xml
<dwr>
<allow>
<createcreator="new"javascript="newNotification">
<paramname="class"value="com.myself.NewNotification"/>
</create>
</allow>
</dwr>
3, com.myself.NewNotification
public class NewNotification{
/**
* 客户端刷新html 时将会在javascript中调用该方法。
* 参考页面js->newNotification.execute();
* @throwsInterruptedException
*/
public void execute()throws InterruptedException {
WebContext context = WebContextFactory.get();
if (NewNotification.webContext ==null) {
// 获得DWR上下文
webContext =context;
}
HttpServletRequest request =context.getHttpServletRequest();
String jid =(String)request.getSession().getAttribute(XMPPConstants.JID_ATTR_NAME);
// 把接收者记录下来
synchronized (receivers) {
receivers.add(jid);
}
// 把接收者与客户端脚本 session对应
context.getScriptSession().setAttribute(XMPPConstants.JID_ATTR_NAME, jid);
}
/**
* DWR上下文
*/
private static WebContext webContext;
/**
* 所有的用户,即通知的接收者,当用户进入到页面时,receivers就记录下用户的jid。
* 以便过后通过jid向用户所有的客户端推送通知。
* 这里有一个弊端就是 receivers中的元素只会不断的增加,上限是xmpp服务端所注册的jid的总数。
*/
private static Set<String> receivers =new HashSet<String>();
/**
* 推送通知的线程,会一直不停地跑。
* 首先用 receivers中的jid去xmpp服务器读取属于该jid的通知。
* 然后将读取到的通知推送给客户端
*/
private static Thread notification =new Thread() {
MtReceiveAction action = new MtReceiveAction();
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()){
try {
Thread.sleep(XMPPConstants._MT_PERIOD);
Map<String, String> jsonMap = newHashMap<String, String>();
synchronized (receivers) {
Iterator<String> iter = receivers.iterator();
/*
* 让每个客户端都从xmpp服务器端去获取新的通知,如果获取到新的通知
*/
while(iter.hasNext()) {
String receiver = iter.next();
// 从xmpp读取新的通知
String jsonResult = action.receiveNotification(receiver);
/*
* 如果读取到新的通知,那么把客户端标记及通知内容记录下来
*/
if (jsonResult !=null) {
jsonMap.put(receiver, jsonResult);
}
}
}
// 获取当前页面URL,比如/ext3/test_tag.jsp
String currentPage = webContext.getCurrentPage();
// 所有浏览当前页面的脚本session
Collection<ScriptSession>sessions = webContext.getScriptSessionsByPage(currentPage);
/*
* 将通知推送给对应的接收者
*/
for(Iterator<String> jiter = jsonMap.keySet().iterator(); jiter.hasNext();){
// 接收者
String receiver = jiter.next();
// 通知内容
String jsonResult =jsonMap.get(receiver);
// 客户端脚本
ScriptBuffer script = new ScriptBuffer();
script.appendScript("pollingMsg(").appendData(jsonResult)
.appendScript(");");
for(ScriptSession session : sessions) {
/*
* 脚本session要与接收者对应
*/
if(receiver.equals(session.getAttribute(XMPPConstants.JID_ATTR_NAME))) {
//执行客户端脚本
session.addScript(script);
break;
}
}
}
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
} catch (MtReceiveExceptione) {
e.printStackTrace();
Log.error("推送通知失败:\n" +e.getMessage());
}
}
}
};
static {
notification.start();
}
}
4,test.html
<scripttype="text/javascript" src="http://localhost:8080/asmack/dwr/engine.js"></script>
<scripttype="text/javascript" src="http://localhost:8080/asmack/dwr/util.js"></script>
<scripttype="text/javascript" src="http://localhost:8080/asmack/dwr/interface/newNotification.js"></script>
<!—注:此处的newNotification.js,其名字与 dwr.xml中的javascript值对应-->
题外话,如果作为客户端的test.html不在 asmack项目下,那么script的src属性就不能用相对路径,而必须用绝对的web路径,如上。
然后在该文件的onload中加入:
newNotification.execute();//com.myself.NewNotification中的方法
dwr.engine.setActiveReverseAjax(true);
当然还要定义一个function,即服务端的 dwr 将会调用的function:
function pollingMsg(jsonData){
……//省略处理通知的代码
}
以上就是具体步骤及代码。
这个方法的好处是,客户端不用去不停地使用ajax访问服务端,
只需要在装载页面时向服务端登记一下,然后由服务端不断地调用客户端的脚本以向客户端传递消息。