当前位置: 代码迷 >> Web前端 >> dwr 2.0(reverse ajax)兑现推的web IM例子
  详细解决方案

dwr 2.0(reverse ajax)兑现推的web IM例子

热度:462   发布时间:2012-11-10 10:48:50.0
dwr 2.0(reverse ajax)实现推的web IM例子

根据网上一些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="登录" onclick="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="发  送" onclick="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 onload="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 onload="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

?

?

1 楼 xuezhongde 2010-09-25  
非常好的例子
Thanks
2 楼 caofackri 2011-07-14  
有demo真好!
3 楼 allanpoe 2011-08-12  
我使用的AOM框架,这是基于jsf的,我在里面使用
WebContext context = WebContextFactory.get();
   Collection<ScriptSession> sessions = context.getScriptSessionsByPage("/dwrpush/index.jsp");
总是报空指针错误

我看你的例子比如通过WebContext实现session与userid的绑定,怎么办呢?在jsf里怎么构造WebContext呢?
  相关解决方案