DWR會在頁面鏈接后台時,創建一個對應的ScriptSession對象,通過調用對應ScriptSession的scriptSession.addScript(script);方法來進行消息推送。
可以在相應的scriptSession中添加“name“屬性來區分推送的目標,實現精確推送。
org.directwebremoting.Browser :http://directwebremoting.org/dwr/javadoc/org/directwebremoting/Browser.html
以下代碼是在 DWR實現消息廣播 的基礎上進行改造的。
一、后台改造
1.在后台代碼中增加onPageLoad方法,在scriptSession中增加推送的唯一標識。
2.利用ScriptSessionFilter對所有的scriptSession進行過濾。
3.向符合條件的頁面進行推送
com.test.Message.java
package com.test; import java.util.Collection; import org.directwebremoting.Browser; import org.directwebremoting.ScriptBuffer; import org.directwebremoting.ScriptSession; import org.directwebremoting.ScriptSessionFilter; import org.directwebremoting.WebContextFactory; public class Message { // 載入頁面時調用,傳入name值作為推送的標識 public void onPageLoad(String name) { ScriptSession session = WebContextFactory.get().getScriptSession(); session.setAttribute("name", name); } public void addMessage(String userid, String message) { final String userId = userid; final String autoMessage = message; ScriptSession session = WebContextFactory.get().getScriptSession(); final String from = session.getAttribute("name").toString(); System.out.println("From: " + from + ", To: " + userid + ", Msg: " + message); // 通過ScriptSessionFilter篩選符合條件的ScriptSession Browser.withAllSessionsFiltered(new ScriptSessionFilter() { // 實現match方法,條件為真為篩選出來的session public boolean match(ScriptSession session) { String name = session.getAttribute("name").toString(); return name == null ? false : userId.equals(name); } }, new Runnable() { private ScriptBuffer script = new ScriptBuffer(); public void run() { // 設定前台接受消息的方法和參數 script.appendCall("receiveMessages", autoMessage); Collection<ScriptSession> sessions = Browser .getTargetSessions(); // 向所有符合條件的頁面推送消息 for (ScriptSession scriptSession : sessions) { if (scriptSession.getAttribute("name").equals(userId)) { scriptSession.addScript(script); } } } }); } }
二、前台改造
1.引入了jquery,方便dom操作,由DwrServlet生成的 util.js 也具有dom操作功能。
2.在頁面加載完畢之后,做了三件事:
2.1.dwr.engine.setActiveReverseAjax(true),開啟逆向Ajax模式,在 DWR實現消息廣播 例子中,寫在body標簽的onload方法中
2.2.dwr.engine.setNotifyServerOnPageUnload(true),這個方法設置DWR在頁面關閉時銷毀后台無效的ScriptSession,也可以使用setNotifyServerOnPageUnload(true, true)方法異步通知后台該ScriptSession無效。如果設置為false或者通知后台失敗,將會采用延時銷毀策略,以保證后台的ScriptSession都是有效的。
2.3.調用后台的onPageLoad方法,設置url中的name屬性為推送唯一標識
在我本機的訪問地址為 http://localhost:8080/Dwr-comet/index.jsp?name=a
index.jsp
<html> <head> <title>DWR - cometDemo</title> <script type="text/javascript" src="./dwr/engine.js"></script> <script type="text/javascript" src="./dwr/util.js"></script> <script type="text/javascript" src="./dwr/interface/Message.js"></script> <script type="text/javascript" src="js/jquery-1.4.2.js"></script> <script type="text/javascript"> var chatlog = ""; function sendMessage() { var message = $("#message").val(); var user = $("#user").val(); // 通過代理調用后台的addMessage方法發送消息 Message.addMessage(user, message); } // 前台接受消息的方法,由后台調用 function receiveMessages(messages) { var lastMessage = messages; chatlog = "<p>" + lastMessage + "</p>" + chatlog; $("#list").html(chatlog); } //讀取name值作為推送的唯一標示 function onPageLoad(){ // 獲取URL中的name屬性為唯一標識符 var userId = getQueryString("name"); $("#myName").html(userId); // 通過代理,傳入區別本頁面的唯一標識符 Message.onPageLoad(userId); } //獲取url中的參數 function getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i"); var r = window.location.search.substr(1).match(reg); if (r != null) return unescape(r[2]); return null; } $(document).ready(function(){ dwr.engine.setActiveReverseAjax(true);// 開啟逆向Ajax,也可寫在body標簽的onload方法中 dwr.engine.setNotifyServerOnPageUnload(true); onPageLoad(); }); </script> </head> <body> My name is:<span id="myName" style="color:red"></span><br/> To:<br/> <input id="user" type="text" /><br/> input message:<br/> <input id="message" type="text" value="hey" /> <input type="button" value="send" onclick="sendMessage()" /> <br> <div id="list"></div> </body> </html>
三、運行效果
打開一個name為a的窗口,兩個name為b的窗口,a向b發送的消息兩個b窗口都能收到推送,而b發給a的消息,只有a窗口接收到了推送。
控制台顯示如下:
可以維護一個在線用戶的Map來控制用戶的唯一性,這需要定義一個簡單的協議,以區分消息是通知用戶下線還是發送的消息,稍后我會寫一篇博客來實現這個Demo。