b/s模式下的即时通讯,使用ajax框架dwr实现
b/s模式下的即時(shí)通訊,使用ajax框架dwr實(shí)現(xiàn)
?
了解java的發(fā)展史可以知道,客戶端編程在基于瀏覽器的編程方面,以前的做法是用applet實(shí)現(xiàn)客戶端編程,在當(dāng)時(shí)算是流行的做法,但是隨著IE的不一致,尤其是微軟的不支持,
Applet沒(méi)有發(fā)展起來(lái),還有一個(gè)原因就是在瀏覽器中要下載java運(yùn)行時(shí)插件,這幾M的大小,對(duì)于以前網(wǎng)速就慢的網(wǎng)絡(luò),無(wú)疑斷送了它的性命。現(xiàn)在應(yīng)用與客戶端瀏覽器的技術(shù)主要為一些牛人自己開(kāi)發(fā)的插件,通過(guò)下載實(shí)現(xiàn)自己的功能?,F(xiàn)在最通用最新的做法是利用XmlHttpRequext,異步實(shí)現(xiàn)客戶端請(qǐng)求,也就是通常所說(shuō)的ajax(異步的JavaScript和xml)技術(shù),可以使用封裝好的dwr框架簡(jiǎn)化開(kāi)發(fā),另一種方式就是使用Flex技術(shù),就是Flash腳本編程,只是聽(tīng)說(shuō),自己還沒(méi)有用過(guò)。
?
自己寫(xiě)了一個(gè)使用ajax框架dwr實(shí)現(xiàn)簡(jiǎn)易的即時(shí)通信程序。
首先什么是dwr呢?DWR是一個(gè)框架,簡(jiǎn)單的說(shuō)就是能夠在javascript直接調(diào)用java方法,而不必去寫(xiě)一大堆的javascript代碼。它的實(shí)現(xiàn)是基于ajax的,可以實(shí)現(xiàn)無(wú)刷新效果。
一、?????????? dwr配置篇
1.web.xml
<servlet>
?????? <servlet-name>dwr-invoker</servlet-name>
?????? <servlet-class>
?????????? org.directwebremoting.servlet.DwrServlet
?????? </servlet-class>
?????? <init-param>
?????????? <description>調(diào)試DWR,發(fā)布系統(tǒng)時(shí)應(yīng)將其設(shè)為false</description>
?????????? <param-name>debug</param-name>
?????????? <param-value>true</param-value>
?????? </init-param>
?????? <init-param>
?????????? <description>使用服務(wù)器推技術(shù)(反轉(zhuǎn)AJAX)</description>
?????????? <param-name>activeReverseAjaxEnabled</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>maxWaitAfterWrite</param-name>
?????????? <param-value>100</param-value>
?????? </init-param>
?????? <load-on-startup>4</load-on-startup>
??? </servlet>
??? <servlet-mapping>
?????? <servlet-name>dwr-invoker</servlet-name>
?????? <url-pattern>/dwr/*</url-pattern>
??? </servlet-mapping>
這個(gè)參數(shù)DWR默認(rèn)是false。如果選擇true,我們可以通過(guò)http://localhost:port/app/dwr看到你部署的每個(gè)DWR class。并且可以測(cè)試java代碼的每個(gè)方法是否運(yùn)行正常。為了安全考慮,在正式環(huán)境下你一定把這個(gè)參數(shù)設(shè)為false。
2.使用dwr還要由一個(gè)dwr.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr/dwr20.dtd">
<dwr>
??? <allow>
?????? <convert converter="bean" match="com.lhq.User" />
?????? <create creator="new" javascript="ChatManager">
?????????? <param name="class" value="com.lhq.ChatManager" />
?????? </create>
??? </allow>
</dwr>
二.Dwr使用篇
實(shí)例:b/s模式下的即時(shí)通訊,使用ajax框架dwr實(shí)現(xiàn)
1.?????? 首先把dwr.jar包放在項(xiàng)目lib目錄下。
2.?????? 進(jìn)行上述web.xml相關(guān)配置,上述配置就是本實(shí)例的配置。
3.?????? 為實(shí)現(xiàn)功能寫(xiě)的javabean,可能還有servlet,但本實(shí)例沒(méi)有牽涉到servlet。代碼如下:
package com.lhq;
?
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
?
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
?
import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ServerContext;
import org.directwebremoting.ServerContextFactory;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.proxy.dwr.Util;
?
/**
?*處理聊天相關(guān)
?*
?*@authorlhq
?*
?*/
publicclass ChatManager {
?
??? /**保存當(dāng)前在線用戶列表*/
??? publicstatic List<User> users = new ArrayList<User>();
?
??? /**
??? ?*更新在線用戶列表
??? ?*
??? ?*@paramusername
??? ?*??????????? 待添加到列表的用戶名
??? ?*@paramflag
??? ?*??????????? 是添加用戶到列表,還是只獲得當(dāng)前列表
??? ?*@paramrequest
??? ?*@return用戶userid
??? ?*/
??? public String updateUsersList(String username, boolean flag,
?????????? HttpServletRequest request) {
?????? User user = null;
?????? if (flag) {
?????????? // 這里取會(huì)話(HttpSession)的id為用戶id
?????????? System.out.println("aauserid:" + request.getSession().getId());
?????????? user = new User(request.getSession().getId(), username);
?????????? // 保存用戶到列表
?????????? users.add(user);
?????????? // 將用戶id和頁(yè)面腳本session綁定
?????????? this.setScriptSessionFlag(user.getUserid());
?????? }
?????? // 獲得DWR上下文
?????? ServletContext sc = request.getSession().getServletContext();
?????? ServerContext sctx = ServerContextFactory.get(sc);
?????? // 獲得當(dāng)前瀏覽 index.jsp 頁(yè)面的所有腳本session
?????? Collection sessions = sctx
????????????? .getScriptSessionsByPage("/BalanceCenter/index.jsp");
?????? System.out.println("session的記錄數(shù):" + sessions.size());
?????? // 消除不存在的頁(yè)面session
?????? System.out.println("session的記錄數(shù)(消除后):" + sessions.size());
?????? Util util = new Util(sessions);
?????? // 處理這些頁(yè)面中的一些元素
?????? util.removeAllOptions("users");
?????? util.addOptions("users", users, "username");
?????? util.removeAllOptions("receiver");
?????? util.addOptions("receiver", users, "userid", "username");
?????? if (!flag) {
?????????? returnnull;
?????? }
?????? return user.getUserid();
??? }
?
??? /**
??? ?*
??? ?*當(dāng)退出時(shí)更新user
??? ?*
??? ?*
??? ?*/
??? publicvoid delUser(HttpServletRequest request) {
?????? String userid = request.getSession().getId();// 與userid相等,呵呵
?????? System.out.println("userIdaa:" + userid);
?????? Iterator it = users.iterator();
?????? while (it.hasNext()) {
?????????? User user = (User) it.next();
?????????? System.out.println(user.getUsername());
?????????? System.out.println("userId:" + user.getUserid());
?????????? if (user.getUserid().equals(userid)) {
????????????? users.remove(user);
????????????? break;
?????????? }
?????? }
?????? updateUsersList(null, false,request) ;
??? }
?
??? /**
??? ?*將用戶id和頁(yè)面腳本session綁定
??? ?*
??? ?*@paramuserid
??? ?*/
??? publicvoid setScriptSessionFlag(String userid) {
?????? WebContextFactory.get().getScriptSession().setAttribute("userid",
????????????? userid);
??? }
?
??? /**
??? ?*根據(jù)用戶id獲得指定用戶的頁(yè)面腳本session
??? ?*
??? ?*@paramuserid
??? ?*@paramrequest
??? ?*@return
??? ?*/
??? @SuppressWarnings("unchecked")
??? public ScriptSession getScriptSession(String userid,
?????????? HttpServletRequest request) {
?????? ScriptSession scriptSessions = null;
?????? Collection<ScriptSession> sessions = new HashSet<ScriptSession>();
?????? sessions.addAll(ServerContextFactory.get(
????????????? request.getSession().getServletContext())
????????????? .getScriptSessionsByPage("/BalanceCenter/index.jsp"));
?????? for (ScriptSession session : sessions) {
?????????? String xuserid = (String) session.getAttribute("userid");
?????????? if (xuserid != null && xuserid.equals(userid)) {
????????????? scriptSessions = session;
?????????? }
?????? }
?????? return scriptSessions;
??? }
?
??? /**
??? ?*發(fā)送消息
??? ?*
??? ?*@paramsender
??? ?*??????????? 發(fā)送者
??? ?*@paramreceiverid
??? ?*??????????? 接收者id
??? ?*@parammsg
??? ?*??????????? 消息內(nèi)容
??? ?*@paramrequest
??? ?*/
??? publicvoid send(String sender, String receiverid, String msg,
?????????? HttpServletRequest request) {
?????? ScriptSession session = this.getScriptSession(receiverid, request);
?????? Util util = new Util(session);
?
?????? util.setStyle("showMessage", "display", "");
?????? ScriptBuffer script = new ScriptBuffer();
?????? script.appendScript("receiveMessages(").appendData(
????????????? sender + "說(shuō):" + msg + "/n").appendScript(");");
?????? session.addScript(script);
??? }
}
4.?????? 進(jìn)行dwr.xml相對(duì)于javabean的相關(guān)配置,及提供客戶端JavaScript腳本對(duì)于java方法的可見(jiàn)性。上述代碼及為本實(shí)例代碼。
5.?????? 客戶端javascript中調(diào)用
自定義一個(gè)chat.js文件,用來(lái)跟后臺(tái)進(jìn)行交互。代碼如下:
/**
?* 注冊(cè)
?*/
function register(button) {
???
??? if ($('username').value == "" || $('username').value.length <= 0) {
?????? alert("請(qǐng)輸入昵稱");
?????? return;
??? }
?
??? /*相應(yīng)按鈕處理 */
??? $('username').disabled = true;
??? button.disabled = true;
??? //$('message').disabled = false;
??? $('send').disabled = false;
??? $('receiver').disabled = false;
??? $('send').disabled = false;
??? $('exit').disabled = false;
??? /*調(diào)用后臺(tái)ChatManager類的updateUsersList方法,并取得返回值元數(shù)據(jù)放在data中*/
??? ChatManager.updateUsersList($('username').value, true, function(data) {
?????? if (data != null && data.length > 0) {
?????????? $('userid').value = data; //??? 把當(dāng)前sessionId放在隱藏表單
}
??? });
}
?
/**
?*初始化
?*/
function init() {
??? dwr.engine.setActiveReverseAjax(true); // 激活反轉(zhuǎn)
??? ChatManager.updateUsersList(null, false); //和上面那個(gè)方法一樣
}
function delUser(button) {
??? ChatManager.delUser(); //當(dāng)退出是調(diào)用,消除該在線用戶
/**
?*并對(duì)相應(yīng)按鈕進(jìn)行相應(yīng)處理
?*/
?
??? $('username').disabled = false;
??? $('register').disabled = false;
??? button.disabled=true;
??? $('receiver').disabled = true;
??? $('send').disabled = true;
??? $('areaMessage').innerHTML = "";
}
/**
?* 當(dāng)發(fā)送信息是調(diào)用
?*/
function send() {
??? var sender = dwr.util.getValue('username'); //取得該用戶的名字
??? var receiver = dwr.util.getValue('receiver'); // 取得接收者
??? var msg = FCKeditorAPI.GetInstance("message").EditorDocument.body.innerHTML; // 取得文本編輯器的文本
??? ChatManager.send(sender, receiver, msg); //調(diào)用后臺(tái)方法
}
/**
*這是后臺(tái)推技術(shù)調(diào)用的方法,接受信息
*/
function receiveMessages(message) {
//取得聊天信息中文本
??? var messages=document.getElementById("areaMessage").innerHTML;
??? document.getElementById("areaMessage").innerHTML=message+"<hr/>"+messages;
???
}
?
window.onload = init;//頁(yè)面加載時(shí)
?
6.?????? html代碼
需要導(dǎo)入必須的js文件,在文本編輯時(shí),我用了一個(gè)fckEditor文本編輯器,上網(wǎng)下一個(gè)就可以了,放在根目錄下,本人美感欠缺,頁(yè)面不太好看,請(qǐng)見(jiàn)諒!具體代碼如下:
<%@ page language="java" pageEncoding="GBK"%>
<% String context=request.getContextPath();
?? pageContext.setAttribute("ctx",context);
%>
<html>
??? <head>
?????? <title>chat</title>
?????? <meta http-equiv="pragma" content="no-cache">
?????? <meta http-equiv="cache-control" content="no-cache">
?????? <meta http-equiv="expires" content="0">
?????? <script type='text/javascript' src='/BalanceCenter/dwr/interface/ChatManager.js'></script>
?????? <script type='text/javascript' src='/BalanceCenter/dwr/engine.js'></script>
?????? <script type='text/javascript' src='/BalanceCenter/dwr/util.js'></script>
?????? <script type="text/javascript" src="/BalanceCenter/chat.js"></script>
?????? <script type="text/javascript" src="${ctx}/fckeditor/fckeditor.js"></script>
??? </head>
??? <body>
?????? <input type="hidden" name="userid" />
?????? <br>
?????? 昵稱:
?????? <input type="text" name="username" id="username" />
?????? <input type="button" value="注冊(cè)" onclick="register(this);" id="register"/>
?????? <input type="button" value="退出" onclick="delUser(this);" id="exit"/>
?????? <br />
?????? <br />
?????? 我要對(duì)
?????? <select name="receiver" id="receiver" disabled=true" >
?????? </select>
?????? 說(shuō):
?????? <script type="text/javascript">
????????????? var oFCKeditor = new FCKeditor("message");
????????????? oFCKeditor.BasePath? = '${ctx}/fckeditor/' ;
????????????? oFCKeditor.Height = 300 ;
????????????? oFCKeditor.ToolbarSet = 'Default';
????????????? oFCKeditor.Create() ;
????????????? </script>
??????
?????? <input type="button" value="發(fā)送" id="send" name="send" disabled="true"
?????????? onclick="send();" />
?????? <br />
?????? <br />
?????? 在線用戶列表:
??????
?????? <ul id="users">
?????? </ul>
??????
??????
?????? <div id="showMessage" style="display: none">
?
?????? <div id="areaMessage" style="position:absolute;
??? width:600px;
??? height:300px;
??? z-index:1;
??? border:solid;
??? overflow:auto;
??? ">
??? </div>
?????? </div>
??????
??? </body>
</html>
好了,終于寫(xiě)完了,首先要說(shuō)明一下,本程序不是很完善,具體在:用戶只有點(diǎn)擊“退出”按鈕才可以實(shí)現(xiàn)把該在線人員刪除掉,可能利用js也可以實(shí)現(xiàn)關(guān)閉頁(yè)面也可以把該在線人員刪除掉,但是如果用戶刷新了,怎么辦呢???就是怎么記錄有效地scriptsession呢?有人說(shuō)用map保存。本人沒(méi)有試過(guò),還望高手指點(diǎn),不勝感激!!!
總結(jié)
以上是生活随笔為你收集整理的b/s模式下的即时通讯,使用ajax框架dwr实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ACCESS数据库连接字符串
- 下一篇: mysql锁机制总结