`
yourgame
  • 浏览: 356357 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

DWR Server Push(服务器推技术) 实现即时聊天功能(WEB)`

    博客分类:
  • DWR
阅读更多
当你有QQ消息时,QQ的小图标会晃动,我们甚至还可以设定QQ有消息时,自动弹出来!
这些在C/S模式下很容易实现!如果要在B/S模式如何来实现呢?
我们的肯定会想到在客服端调用ajax在后台不断的查询服务器.看是否有关于自己的消息.如果有则查询返回.这种做法肯定会大量的占用系统的资源!不可取!
现在DWR的反转AJAX功能.允许我们从服务器端来控制客服端.而不需要客户端来请求.服务器可以自动把消息发给指定的客户端!

w_e_ibo:
http://t.cn/zjqEaRh  
http://weibo.com/liao27

[img]http://yourgame.iteye.com/upload/picture/pic/16013/4ca7a7b8-4281-3260-a568-235b61d511dd.gif [/img]

我不能把公司的代码贴出来,所以我自己写了一个DEMO,已经实现了对指定用户发送消息的功能,并且即时显示在指定的用户界面上面.当然你可以修改这些,让它弹出来显示,或者像QQ一样在你页面的某个角落让消息的图标闪动:)
下面我做一个简单的说明:

用户的JAVABEAN User.java
package com.lhq;

/**
 * 用户类
 * 
 * @author 廖瀚卿
 * 
 */
public class User {

	private String userid;

	private String username;

	public String getUserid() {
		return userid;
	}

	public void setUserid(String userid) {
		this.userid = userid;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public User(String userid, String username) {
		super();
		this.userid = userid;
		this.username = username;
	}

}


聊天处理类 ChatManager.java
package com.lhq;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.directwebremoting.ScriptSession;
import org.directwebremoting.ServerContext;
import org.directwebremoting.ServerContextFactory;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.proxy.dwr.Util;

/**
 * 处理聊天相关
 * 
 * @author 廖瀚卿
 * 
 */
public class ChatManager {

	/** 保存当前在线用户列表 */
	public static List<User> users = new ArrayList<User>();

	/**
	 * 更新在线用户列表
	 * @param username 待添加到列表的用户名
	 * @param flag 是添加用户到列表,还是只获得当前列表
	 * @param request
	 * @return 用户userid
	 */
	public String updateUsersList(String username, boolean flag, HttpServletRequest request) {
		User user = null;
		if (flag) {	
			// 这里取会话(HttpSession)的id为用户id 
			user = new User(request.getSession().getId(), username);
			//保存用户到列表
			users.add(user);	
			//将用户id和页面脚本session绑定
			this.setScriptSessionFlag(user.getUserid());
		}
		//获得DWR上下文
		ServletContext sc = request.getSession().getServletContext();
		ServerContext sctx = ServerContextFactory.get(sc);
		//获得当前浏览 index.jsp 页面的所有脚本session
		Collection sessions = sctx.getScriptSessionsByPage("/chat/index.jsp");
		Util util = new Util(sessions);
		//处理这些页面中的一些元素
		util.removeAllOptions("users");
		util.addOptions("users", users, "username");
		util.removeAllOptions("receiver");
		util.addOptions("receiver", users,"userid","username");
		if(!flag){
			return null;
		}
		return user.getUserid();
	}

	/**
	 * 将用户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 receiverid 接收者id
	 * @param msg 消息内容
	 * @param request
	 */
	public void send(String sender,String receiverid,String msg,HttpServletRequest request){
		ScriptSession session = this.getScriptSession(receiverid, request);
		Util util = new Util(session);
		util.setStyle("showMessage", "display", "");
		util.setValue("sender", sender);
		util.setValue("msg", msg);
	}
}



聊天主页面 index.jsp
<%@ page language="java" pageEncoding="GBK"%>
<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='/chat/dwr/interface/ChatManager.js'></script>
		<script type='text/javascript' src='/chat/dwr/engine.js'></script>
		<script type='text/javascript' src='/chat/dwr/util.js'></script>
		<script type="text/javascript" src="/chat/chat.js"></script>
	</head>
	<body>
		<input type="hidden" name="userid" />
		<br>
		昵称:
		<input type="text" name="username" />
		<input type="button" value="注册" onclick="register(this);" />
		<br />
		<br />
		我要对
		<select name="receiver" id="receiver" disabled=true" >
		</select>
		说:
		<input type="text" name="message" id="message" disabled="true" />
		<input type="button" value="发送" id="send" name="send" disabled="true"
			onclick="send();" />
		<br />
		<br />
		在线用户列表:
		<ul id="users">
		</ul>

		<div id="showMessage" style="display: none">
			<span id="sender"></span>对你说:
			<span id="msg"></span>
		</div>
	</body>
</html>


JAVASCRIPT 文件 chat.js
/**
 * 注册帐号
 */
function register(button) {
	if ($('username').value == "" || $('username').value.length <= 0) {
		alert("请输入昵称");
		return;
	}

	/* 下面是对一些按钮的禁用和激活操作 */
	$('username').disabled = true;
	button.disabled = true;
	$('message').disabled = false;
	$('send').disabled = false;
	$('receiver').disabled = false;

	/* 把我输入的用户名注册到服务器,并获得用户id(这里用session id 代替) */
	ChatManager.updateUsersList($('username').value, true, function(data) {
		if (data != null && data.length > 0) {
			$('userid').value = data; // 注册成功,把userid放到当前页面
		}
	});
}

/**
 * 页面初始化
 */
function init() {
	dwr.engine.setActiveReverseAjax(true); // 激活反转 重要
	ChatManager.updateUsersList(null, false); // 当你打开界面的时候,先获得在线用户列表.
}

/**
 * 发送消息
 */
function send() {
	var sender = dwr.util.getValue('username'); // 获得发送者名字
	var receiver = dwr.util.getValue('receiver'); // 获得接受者id
	var msg = dwr.util.getValue('message'); // 获得消息内容
	ChatManager.send(sender, receiver, msg); // 发送消息
}

window.onload = init;//页面加载完毕后执行初始化方法init


配置文件 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	<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>
	<servlet-mapping>
		<servlet-name>dwr-invoker</servlet-name>
		<url-pattern>/dwr/*</url-pattern>
	</servlet-mapping>
</web-app>


DWR配置文件 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>

  • chat.rar (827.1 KB)
  • 描述: 附上DEMO源代码
  • 下载次数: 9784
分享到:
评论
39 楼 sjzzqy 2012-04-23  
Collection sessions = sctx.getScriptSessionsByPage("/chat/index.jsp");   为什么我session总是空呢?  各种方法都试过了。
38 楼 fandayrockworld 2011-11-22  
"NetworkError: 500 Internal Server Error - http://localhost:8080/chat/dwr/interface/ChatManager.js"
ChatManager.js
"NetworkError: 500 Internal Server Error - http://localhost:8080/chat/dwr/util.js"
util.js
"NetworkError: 500 Internal Server Error - http://localhost:8080/chat/dwr/engine.js"
engine.js
"NetworkError: 500 Internal Server Error - http://localhost:8080/chat/dwr/engine.js"
engine.js
"NetworkError: 500 Internal Server Error - http://localhost:8080/chat/dwr/util.js"
util.js
dwr is not defined
[在此错误处中断] dwr.engine.setActiveReverseAjax(true); // 激活反转 重要 

楼主,错误···
37 楼 mdc 2011-10-25  
非常感谢楼主的分享!
36 楼 fengzl 2009-05-18  
长连接更不可取,所以这个和鸡肋差不多
35 楼 cwmwss 2009-05-18  
我下了你的源码可以运行出来了。WEB-INF里的很多TLD文件有用的吗?
34 楼 cwmwss 2009-05-18  
为什么我的DWR不支持$()标记,
改成getelementbyid后,无JS错误。
进入页面为什么看不见用户列表,注册后select中的用户还是空的
33 楼 xiaoyu966 2009-04-27  
楼主,这样吧,你看下我的源代码,我发了一个已经实现了的ext在线聊天的,只是没有lib包,当初就是看了你这个例子以后决定用dwr反转的,以前用的是pushlet,感觉要麻烦很多。因为是做毕业设计,这个又比较简单,所以就打算做的完美一点呵呵,个人对个人的聊天我也实现了,现在在加聊天记录,发送离线消息什么的。

http://xiaoyu966.iteye.com/admin/blogs/375509

定期向浏览器推一个信息,然后让浏览器回复一个请求,如果没有请求,则认为已经下线,定期任务的发送,我待会去找找资料。
32 楼 xiaoyu966 2009-04-27  
你好,楼主,你提供的思路倒是也可以考虑一下,但是服务器定期推消息怎么实现啊?我想了下好像没有类似的调用方法。可以提供一个例子吗?谢谢了。

ScriptSession这个对象只要刷新一下浏览器就会新增加一个,我后来解决了这个问题,就是用一个map来存放在线用户对应的ScriptSession,用户刷新和关闭浏览器的时候,也会更新或者删除对应的ScriptSession;

31 楼 xiaoyu966 2009-04-27  
你好楼主,我是这个问题:  fireFox下怎么判断是刷新还是关闭浏览器    的提问者,
刚看了你的回复

引用
希望有高人能解决这个问题,因为我在做一个实时聊天的应用,要监听实时在线的用户。关闭浏览器时,要销毁对应的session,要更新在线用户。


首先,你这种做法就不正确。你不能通过onunload 来检测用户是否已经离线。

你可以采用服务器推技术(server push),来实现检测在线用户。关于推技术。你可以参考我博客里面的一片文章
http://yourgame.iteye.com/blog/199079

我的建议是,也没有必要实时去检测在线用户是否还在线,你可以再用户登录的时候发送一个请求给服务器,让服务器通过推技术来检测当前有多少用户在线。这样效率要高一些。或则你用户点退出系统,也可以发送一个请求给服务器处理



我想你误解我的意思了,我采用了dwr的反转,长连接已经用上了,但是用在用户上线,下线时,实时更新其他用户的浏览器中好友列表,还有就是发送的信息。

你说:你可以采用服务器推技术(server push),来实现检测在线用户。
长连接检测在线用户,这个可行性是不是太低了?ScriptSession刷新一次就会创建一次,用这个来看检测在线的可定不行。


你说:我的建议是,也没有必要实时去检测在线用户是否还在线,你可以再用户登录的时候发送一个请求给服务器,让服务器通过推技术来检测当前有多少用户在线。这样效率要高一些。或则你用户点退出系统,也可以发送一个请求给服务器处理

这个我早就实现了,但是退出的时候分为正常退出和非正常退出两种,正常退出时,当然就是销毁session,并且给其他用户浏览器推入新的在线用户列表。非正常退出就是用户没有点退出按钮,而是直接点关闭,或者右键关闭,我要处理的也就是非正常关闭时,在关闭前销毁对应的session,并且更新在线用户列表。
30 楼 bohemia 2009-04-23  
Cometd目前应该是较好的方式;

Comet的三种实现方式:
1.长连接(ServerPush)
2.Long-Polling
3.轮询

目前Jetty的Cometd由于已经使用了Jetty的异步Servlet方式; 对服务的扩展和并发性能来说更好;
29 楼 IamNull 2009-04-23  
如果是要做网页聊天的功能,可以参考一下其他的开源组件,比如 Openfire
28 楼 arpenker 2009-02-28  
只支持ie浏览器。其它的所有浏览器全都无法正常使用。请大家三思!!!!!!这是一个不符合国际最起码标准的DEMO。


27 楼 yewen0125 2009-02-26  
谢谢, 我找这个好久了
26 楼 dopic 2009-02-21  
感觉,总有点怪,能不能在大量用户下使用啊
25 楼 ren20666041 2009-02-13  
试试看吧.
24 楼 yourgame 2009-02-12  
omeweb 写道
有没有测试过并发连接数?

你可以测试一下,并且希望您公布结果
23 楼 omeweb 2009-02-12  
有没有测试过并发连接数?
22 楼 yourgame 2009-02-05  
hanle3345678 写道
没法用啊  楼主

怎么了?
21 楼 hanle3345678 2009-02-05  
没法用啊  楼主
20 楼 wangzinan 2009-01-14  
太感谢了 正在学习中 谢谢

相关推荐

    DWR Server Push(服务器推技术) 实现即时聊天

    NULL 博文链接:https://yangxh101.iteye.com/blog/684776

    DWR推送技术大全 dwr推送聊天实例

    DWR的主要功能之一是推送技术,这使得服务器可以主动向客户端发送数据,而不仅仅是响应客户端的请求。这种能力在创建实时更新的应用程序,如聊天应用,股票报价或者在线游戏时非常有用。 DWR推送技术的核心在于其...

    dwr实现的服务器推demo

    在这个"**dwr实现的服务器推demo**"中,我们看到一个实例,展示了如何利用DWR的技术来实现实时的、无需刷新的服务器推送功能。 服务器推是一种技术,它允许服务器主动地将数据发送到客户端,而不需要客户端(通常是...

    DWR3实现服务器端向客户端精确推送消息

    在“DWR3实现服务器端向客户端精确推送消息”这一主题中,我们将深入探讨如何利用DWR3进行服务器到客户端的消息推送,以及这种技术的优势和应用。 首先,理解DWR3的工作原理是至关重要的。DWR3通过建立一个安全的...

    dwr推技术实现服务器推送数据

    Direct Web Remoting (DWR) 是一种开源的Java库,它允许JavaScript在浏览器和服务器之间进行交互,从而实现在Web应用程序中的Ajax(异步JavaScript和XML)功能。DWR的独特之处在于它的“反转Ajax”(Reverse Ajax)...

    dwr实现的网页即时聊天

    在这个"使用dwr实现的网页即时聊天"项目中,我们将深入探讨如何利用DWR的服务器推技术来创建一个实时的群聊系统。 1. **DWR框架**: DWR简化了JavaScript与Java之间的通信,通过在浏览器端提供动态生成的JavaScript ...

    服务器推--DWR中的push机制-Reverse_Ajax.docx

    DWR(Direct Web Remoting)是一个开源Java库,它实现了服务器推功能,尤其是其2.0版本开始引入的push机制。 1. **Polling(轮询)** 轮询是最基础的模拟服务器推的方式。客户端以一定的频率(如几秒一次)向...

    dwr服务器推技术

    在描述中提到的"DWR服务器推技术整合Struts2",意味着我们将DWR与流行的MVC框架Struts2相结合,以创建一个具有聊天功能的Web应用。Struts2提供了一个强大的架构来处理HTTP请求,并结合DWR,可以创建一个动态的、交互...

    jsp DWR框架推模式实现的聊天室

    **DWR(Direct Web Remoting)框架是一种在Web应用程序中实现AJAX(Asynchronous JavaScript and XML)技术的工具,它允许JavaScript与服务器端的Java代码进行实时交互,从而创建更动态、更响应式的用户界面。...

    实现 Dwr 服务器推送

    本文将详细介绍如何实现DWR的服务器推送功能。 一、DWR简介 DWR的核心功能是通过AJAX技术创建了一个JavaScript到Java的桥梁,使得开发者可以像操作本地对象一样操作远程服务器上的对象。它支持自动类型转换、错误...

    DWR服务器推送技术实现WebQQ

    **DWR(Direct Web Remoting)服务器推送技术详解与WebQQ实现** DWR,全称为Direct Web Remoting,是一种在JavaScript和Java之间进行远程方法调用(Remote Method Invocation,RMI)的技术,允许Web应用程序实现...

    spring3+dwr3实现聊天功能

    Spring提供稳定的服务层支持,而DWR则负责实现高效的客户端和服务器通信,尤其是Server Push特性,使得聊天功能更加实时和流畅。通过合理的架构设计和安全控制,这样的聊天系统能够为用户提供优秀的交互体验。

    DWR服务器推送技术(实时)

    DWR的核心特性是它支持AJAX(Asynchronous JavaScript and XML)以及服务器推送技术,极大地提高了Web应用的用户体验。 **服务器推送技术**: 传统的HTTP协议是基于请求-响应模型的,即客户端发起请求,服务器响应...

    dwr 实现推技术 实例

    本实例将通过一个点对点聊天功能的实现,深入探讨DWR的推技术。 ### DWR基础 1. **反向Ajax(Reverse Ajax)**:DWR的核心功能之一是实现反向Ajax,即服务器可以主动向客户端推送数据,而不仅仅是响应客户端的请求...

    dwr实现服务器推技术,兼容低版本IE

    "dwr实现服务器推技术,兼容低版本IE"这一主题,表明我们将讨论如何利用DWR实现在旧版Internet Explorer上的服务器推送功能。 1. **DWR基础原理** DWR的核心在于创建一个JavaScript对象,该对象可以直接调用服务器...

    serverpush聊天室

    "ServerPush聊天室"是一种基于DWR(Direct Web Remoting)技术实现的实时通信系统,主要特点是能够实现实时的点对点聊天功能。在这个系统中,服务器主动将信息推送至客户端,而不是传统的客户端发起请求获取数据的...

    DWR服务器推技术Demo

    DWR是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站。它可以允许在浏览器里的代码使用运行在WEB服务器上的JAVA函数,就像它就在浏览器里一样。

    基于DWR框架的Web推送技术实现

    在本项目"基于DWR框架的Web推送技术实现"中,我们将探讨如何利用DWR框架来构建一个实时的Web聊天程序。 首先,理解DWR框架的核心概念是至关重要的。DWR允许开发者在浏览器中直接调用服务器上的Java方法,就像它们是...

    服务器反推技术实现即时聊天系统

    服务器反推技术是一种在Web应用中实现即时通信的策略,它与传统的客户端发起请求、服务器响应的模式相反,由服务器主动向客户端推送数据。在即时聊天系统中,服务器反推技术是至关重要的,因为它能够实现实时的消息...

    基于DWR推送的web聊天系统

    【基于DWR推送的Web聊天系统】是一种利用Direct Web Remoting (DWR) 技术构建的实时交互式在线聊天应用。DWR是一款开源的Java库,它允许JavaScript在浏览器端与服务器端的Java对象进行直接通信,实现了AJAX(异步...

Global site tag (gtag.js) - Google Analytics