根據網上一些reverse ajax例子,自己隨便寫了個羣內聊天的例子,只實現了羣聊天,其它一些雜七雜八的都沒實現,寫這麼個功能只是學習下reverse ajax而已,瞭解服務器推技術。
開發工具:eclipse 3.4 純淨版
環境:tomcat 6
技術:DWR
工程類說明:
ChatManager.java 聊天實現類
Message.java 消息封裝類
OnlineCounter.java 在線人數計算方法
OnlineCounterListener.java 統計在線人數
User.java 用戶bean
頁面:
index.jsp --輸入http:127.0.0.1:8080/ichat自動訪問此頁面
ShowModel_Frames.jsp --登錄之後羣聊天的主界面
example.jsp --FCKEDIT編輯器頁面
excute_sent.jsp -- 消息發送頁面
online_list.jsp --在線列表頁面
show_msg.jsp --顯示消息頁面
代碼:
ChatManager.java 聊天實現類:
package com.ccic.chat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.directwebremoting.ScriptSession;
import org.directwebremoting.ServerContextFactory;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.proxy.dwr.Util;
/**
* 處理聊天相關
*
*
*
*/
public class ChatManager {
/** 保存當前在線用戶列表 */
public static List<User> users = new ArrayList<User>();
/**
* 更新在線用戶列表
* @param request
*/
public void updateUsersList(HttpServletRequest request) {
User user = null;
String flag="0";//標識用戶,0:不存在 1:已存在
String name= request.getSession().getAttribute("uname").toString();
String pwd= request.getSession().getAttribute("pwd").toString();
System.out.println("用戶ID="+name+" 用戶密碼="+pwd);
user = new User(pwd, name);
//保存用戶到列表
//如果列表中無任何用戶則添加,否則循環查找列表中是否已存在該用戶,
//如果不存在,則添加。如果存在,則不添加
if(users.size() == 0){
users.add(user);
}else{
for(int i=0;i<users.size();i++){
User us =(User)users.get(i);
if(us.getUsername().equals(name)){
flag="1";
break;
}
}
if(flag.equals("0")){
users.add(user);
}
}
/*//統計在線人數
long count=OnlineCounter.getOnline();
StringBuffer sb=new StringBuffer();
sb.append("<script language='JavaScript' defer='defer'>");
sb.append("d = new dTree(\'d\');");
sb.append("d.add(0,-1,'在線用戶列表(當前"+count+"人)');");
for(int i=0;i<users.size();i++){
User us =(User)users.get(i);
sb.append("d.add("+(i+1)+",0,'"+us.getUsername()+"','','','');");
}
sb.append("document.write(d);");
sb.append("d.config.useCookies=false;");
sb.append("d.config.closeSameLevel=true;");
sb.append("</script");//注意這裏並不是好了“>”括號,而是在頁面另有處理
System.out.println("dd="+sb.toString());*/
//將用戶id和頁面腳本session綁定
//this.setScriptSessionFlag(user.getUsername());
// 獲得WEB上下文
WebContext wctx = WebContextFactory.get();
//獲得在線列表 頁面的所有腳本session
Collection sessions = wctx.getScriptSessionsByPage("/ichat/pages/main/online_list.jsp");
Util util = new Util(sessions);
//處理這些頁面中的一些元素
//util.addFunctionCall("cBack_list", sb.toString());
util.removeAllOptions("users");
util.addOptions("users", users, "username");
}
/**
* 將用戶id和頁面腳本session綁定
* @param userid
*/
public void setScriptSessionFlag(String userid) {
WebContextFactory.get().getScriptSession().setAttribute("userid", userid);
}
/**
* 根據用戶id獲得指定用戶的頁面腳本session
* @param userid
* @param request
* @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("/chat/index.jsp"));
for (ScriptSession session : sessions) {
String xuserid = (String) session.getAttribute("userid");
if (xuserid != null && xuserid.equals(userid)) {
scriptSessions = session;
}
}
return scriptSessions;
}
/**
* 發送消息
* @param sender 發送人
* @param msg 發送內容
* @param request 發送請求
*/
public void send(String sender,String msg,HttpServletRequest request){
System.out.println("sender="+sender+" msg="+msg);
LinkedList<Message> messages = new LinkedList<Message>();
if (msg != null && msg.trim().length() > 0) {
//AA 說(2010-07-13): <br/>你好!
messages.addFirst(new Message(sender,msg));
while (messages.size() > 3) {
messages.removeLast();
}
}
// 獲得WEB上下文
WebContext wctx = WebContextFactory.get();
//向指定頁面推送消息
Collection sessions = wctx.getScriptSessionsByPage("/ichat/pages/main/show_msg.jsp");
Util utilAll = new Util(sessions);
utilAll.addFunctionCall("callBack", messages);
}
//獲得離線消息,思路:當A發消息給B時,將A用戶發送的消息保存到B用戶的ScriptSession中,
//當B用戶上線時把已經保持在B的ScriptSession中的消息讀取處理並全部推送到頁面。
public void getOfflineMsg(){
}
}
Message.java 消息封裝類
package com.ccic.chat;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.directwebremoting.Security;
public class Message {
DateFormat df = new SimpleDateFormat("HH:mm:ss");
private String serverTime = df.format(new Date());
private String text;
private String online;
public String getOnline() {
return online;
}
public void setOnline(String online) {
this.online = online;
}
public Message(String sender,String newtext) {
text = newtext;
if (text.length() > 256) {
text = text.substring(0, 256);
}
text = sender+" 說 "+"("+serverTime+"):<br/>"+text;
}
public String getText() {
return text;
}
}
OnlineCounter.java 在線人數計算方法
package com.ccic.chat;
public class OnlineCounter {
private static long online = 0;
public static long getOnline() {
return online;
}
public static void raise() {
online++;
}
public static void reduce() {
online--;
}
}
OnlineCounterListener.java 統計在線人數
package com.ccic.chat;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 統計在線用戶數量
*
*/
public class OnlineCounterListener implements HttpSessionListener{
/**
* 當SESSION創建時,自動增加
*/
public void sessionCreated(HttpSessionEvent hse) {
OnlineCounter.raise();
}
/**
* 當SESSION銷燬時,自動減少
*/
public void sessionDestroyed(HttpSessionEvent hse){
OnlineCounter.reduce();
}
}
User.java 用戶bean
package com.ccic.chat;
/**
* 用戶
*
*
*
*/
public class User {
private String password;
private String username;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public User(String password, String username) {
super();
this.password = password;
this.username = username;
}
}
index.jsp --輸入http:127.0.0.1:8080/ichat自動訪問此頁面
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="GBK"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<title>Insert title here</title>
<script language="javascript" type="text/javascript">
function subm(){
var uname=document.form1.username.value;
var pwd=document.form1.password.value;
if (uname == "") {
alert("請輸入用戶ID");
return;
}
window.location="<%=request.getContextPath() %>/pages/frames/ShowModel_Frames.jsp?uname="+uname+"&pwd="+pwd;
}
</script>
</head>
<body>
<form id="ff" name="form1">
<fieldset>
<legend>登錄</legend>
<table align="center">
<tr>
<td>username:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>password:</td>
<td><input type="text" name="password"></td>
</tr>
<tr align="center">
<td colspan="2"><input type="button" name="sub" value="登錄" οnclick="subm();"><input type="reset" name="res" value="重置"></td>
</tr>
</table>
</fieldset>
</form>
</body>
</html>
ShowModel_Frames.jsp --登錄之後羣聊天的主界面
<%@ page language="java" pageEncoding="GB2312"%>
<%
//(模擬)獲取登錄的唯一用戶ID,放到SESSION供online_list.jsp加載在線用戶列表
String uname = request.getParameter("uname");
uname=new String(uname.getBytes("ISO-8859-1"),"gbk");
String pwd = request.getParameter("pwd");
request.getSession().setAttribute("uname",uname);
request.getSession().setAttribute("pwd",pwd);
%>
<html>
<head>
<meta HTTP-EQUIV="Pragma" CONTENT="no-cache">
<title>聊天主界面框架</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<frameset cols="*,230" frameborder="yes" border="0" framespacing="0">
<frameset rows="400,*" frameborder=yes border="5" framespacing="5">
<frame src="<%=request.getContextPath() %>/pages/main/show_msg.jsp" name="main_one" scrolling=yes noresize>
<frame src="<%=request.getContextPath() %>/pages/main/excute_sent.jsp" name="main_two" scrolling=yes noresize>
</frameset>
<frame src="<%=request.getContextPath() %>/pages/main/online_list.jsp" name="main_top" scrolling=no noresize>
</frameset>
<noframes>
<body>
很抱謙,您使用的瀏覽器不支持框架功能,請採用新版本的瀏覽器。
</body>
</noframes>
</html>
example.jsp --FCKEDIT編輯器頁面
excute_sent.jsp -- 消息發送頁面
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="GBK"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Insert title here</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="<%=request.getContextPath() %>/fckeditor/fckeditor.js"></script>
<script type='text/javascript' src='/ichat/dwr/interface/ChatManager.js'></script>
<script type='text/javascript' src='/ichat/dwr/engine.js'></script>
<script type='text/javascript' src='/ichat/dwr/util.js'></script>
<script language="javascript">
/**
* 發送消息
*/
function send() {
var sender = '<%=request.getSession().getAttribute("uname").toString() %>'; // 獲得發送者名字
//var receiver = dwr.util.getValue('receiver'); // 獲得接受者id
var msg = getEditorHTMLContents('edt1'); // 獲得消息內容
ChatManager.send(sender, msg); // 發送消息
SetEditorContents('edt1','');//清空編輯器中發送的消息
}
//獲取編輯器中HTML內容
function getEditorHTMLContents(EditorName)
{
var oEditor = FCKeditorAPI.GetInstance(EditorName);
return oEditor.GetXHTML(true);
}
//設置編輯器中內容
function SetEditorContents(EditorName, ContentStr)
{
var oEditor = FCKeditorAPI.GetInstance(EditorName) ;
oEditor.SetHTML(ContentStr) ;
}
</script>
</head>
<body style="margin: 0px;">
<form method="post" name="frm1">
<script type="text/javascript">
var oFCKeditor = new FCKeditor("edt1");
oFCKeditor.BasePath = "<%=request.getContextPath() %>/fckeditor/";
oFCKeditor.ToolbarSet="ichat";
oFCKeditor.Height='160';
oFCKeditor.Value="";
oFCKeditor.Create();
</script>
<input type="button" value="發 送" οnclick="send();">
</form>
</body>
</html>
online_list.jsp --在線列表頁面
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="GBK" import="com.ccic.chat.OnlineCounter" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Insert title here</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<link rel="stylesheet" href="<%=request.getContextPath()%>/include/css/dtree.css" type="text/css">
<script src="<%=request.getContextPath()%>/include/js/dtree.js"></script>
<script type='text/javascript' src='/ichat/dwr/interface/ChatManager.js'></script>
<script type='text/javascript' src='/ichat/dwr/engine.js'></script>
<script type='text/javascript' src='/ichat/dwr/util.js'></script>
</head>
<script language="javascript">
function register() {
//把我輸入的用戶名註冊到服務器
ChatManager.updateUsersList();
}
//頁面初始化
function init() {
dwr.engine.setActiveReverseAjax(true); // 激活反轉 重要
register();
}
//回調函數
//function cBack_list(data){
//document.getElementById("online_list").insertAdjacentHTML("afterBegin","");
//var str="aa"+data+">";
//document.getElementById("online_list").insertAdjacentHTML("afterBegin",str);
//}
</script>
<body οnlοad="init();">
在線用戶列表(當前<%=OnlineCounter.getOnline() %>人):
<ul id="users">
</ul>
<!--<div id="online_list">
</div>
-->
</body>
</html>
show_msg.jsp --顯示消息頁面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Insert title here</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='/ichat/dwr/interface/ChatManager.js'></script>
<script type='text/javascript' src='/ichat/dwr/engine.js'></script>
<script type='text/javascript' src='/ichat/dwr/util.js'></script>
</head>
<script language="javascript">
//頁面初始化
function init() {
dwr.engine.setActiveReverseAjax(true); // 激活反轉 重要
}
function callBack(data){
DWRUtil.addRows("tbodyId", data, cellFunctions,{escapeHtml:false});
}
var cellFunctions = [
function(item) {
return item.text;
}
];
</script>
<body οnlοad="init();">
<table>
<tbody id="tbodyId">
</tbody>
</table>
</body>
</html>
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.ccic.chat.User"/> <create creator="new" javascript="ChatManager"> <param name="class" value="com.ccic.chat.ChatManager"/> </create> <convert converter="bean" match="com.ccic.chat.Message"/> </allow> </dwr>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>ichat</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class> org.directwebremoting.servlet.DwrServlet </servlet-class> <init-param> <description>調試DWR,發佈系統時應將其設爲false</description> <param-name>debug</param-name> <param-value>true</param-value> </init-param> <init-param> <description>使用服務器推技術(反轉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> <listener> <listener-class> com.ccic.chat.OnlineCounterListener </listener-class> </listener> <servlet-mapping> <servlet-name>dwr-invoker</servlet-name> <url-pattern>/dwr/*</url-pattern> </servlet-mapping> </web-app>
關於FCKEDIT編輯器,我已經刪除多餘的一些東西了,收集:
----------------------FCKEDIT HTML在線編輯器------------------------------
配置:http://blog.csdn.net/xiaokuang513204/archive/2010/07/06/5715029.aspx
插件開發:http://blog.csdn.net/flying_huang/archive/2007/03/23/1539206.aspx
火狐 兼容fckedt:http://www.wangzhanweb.com/html/2010-05/231.html
FCKEditor的賦值和取值操作 :http://www.blogjava.net/feingto/archive/2008/01/09/173963.html
我參考的網上兩個例子,見附件!名稱“chat”
一個是所有對象間聊天的,訪問時對應得頁面是index.jsp.
一個是點對點對象聊天的,訪問時對應得頁面是sample.jsp.
兩者都只是簡單的例子實現。
自己實現的羣聊天簡單例子,見附件!名稱“ichat”
運行:輸入http://127.0.0.1:8080/ichat/ 進入登錄界面,輸入“AA” 或者別的就行了。
參考:
開源的comet實現:pushlet,dwr 2.0的reverse ajax和dojo的io.bind(),
簡單例子(reverse ajax):http://blog.sina.com.cn/s/blog_5bd96d520100gau4.html
談談webIM :http://akalius.iteye.com/blog/192727