`

基于tomcat8+java7+extjs 的webscoket 聊天室实现

 
阅读更多

    由于在网上看到有人用tomcat7+java7+extjs 实现了一个webscoket聊天室功能,我就想用tomcat8重写一遍。

于是就有了一下代码:

   

package com.ibcio;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import net.sf.json.JSONObject;

/**接收所有来自客户端的连接请求,并定义各种事件的回调
 * @author leter
 * @date 2016年3月8日
 * @remark 
 */
@ServerEndpoint(value = "/chat/{user}",configurator=MyConfigurator.class)
public class WebSocketImpl{

	//建立连接的触发的事件
	@OnOpen
	public void start(Session session,@PathParam(value = "user") String user) {
		session.getUserProperties().put("user", user);
		// 触发连接事件,在连接池中添加连接
		JSONObject result = new JSONObject();
		result.element("type", "user_join");
		result.element("user", user);
		//向所有在线用户推送当前用户上线的消息
		WebSocketSessionPool.sendMessage(result.toString(),session);
		result = new JSONObject();
		result.element("type", "get_online_user");
		result.element("list", WebSocketSessionPool.getOnlineUser());
		//向连接池添加当前的连接对象
		WebSocketSessionPool.addMessageInbound(session,user);
		//向当前连接发送当前在线用户的列表
		WebSocketSessionPool.sendMessageToUser(user, result.toString());
	}

	@OnClose
	public void end(Session session) {
		// 触发关闭事件,在连接池中移除连接
		String user = session.getUserProperties().get("user").toString();
		WebSocketSessionPool.removeMessageInbound(user);
		JSONObject result = new JSONObject();
		result.element("type", "user_leave");
		result.element("user", user);
		//向在线用户发送当前用户退出的消息
		WebSocketSessionPool.sendMessage(result.toString(),session);
	}


	//客户端发送消息到服务器时触发事件
	@OnMessage
	public void prcess(String message, Session session){
		//向所有在线用户发送消息
		WebSocketSessionPool.sendMessage(message.toString(),session);
	}
}

    

package com.ibcio;

import javax.websocket.server.ServerEndpointConfig.Configurator;

/**因为每次来一个链接都会生成一个新的WebSocketImpl,这样比较耗费资源。
 * 统一配置只使用一个WebSocketImpl
 * @author leter
 * @date 2016年3月8日
 * @remark 
 */
public class MyConfigurator extends Configurator {
	private WebSocketImpl webSocket = new WebSocketImpl();
	@Override
	public <T> T getEndpointInstance(Class<T> clazz)
			throws InstantiationException {
		return (T) webSocket;
	}
}

    

package com.ibcio;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.websocket.Session;

/**存储所有在线用户的信息,执行上线下线发送消息时需要执行的方法。
 * @author leter
 * @date 2016年3月8日
 * @remark 
 */
public class WebSocketSessionPool {

	// 保存连接的MAP容器
	private static final Map<String, Session> connections = Collections.synchronizedMap(new HashMap<String, Session>());

	// 向连接池中添加连接
	public static void addMessageInbound(Session session, String user) {
		// 添加连接
		System.out.println("user : " + user + " join..");
		connections.put(user, session);
	}

	// 获取所有的在线用户
	public static Set<String> getOnlineUser() {
		return connections.keySet();
	}

	public static void removeMessageInbound(String user) {
		// 移除连接
		System.out.println("user : " + user + " exit..");
		connections.remove(user);
	}

	public static void sendMessageToUser(String user, String message) {
		try {
			// 向特定的用户发送数据
			System.out.println("send message to user : " + user+ " ,message content : " + message);
			Session session = connections.get(user);
			if (session != null) {
				session.getBasicRemote().sendText(message);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	// 向所有的用户发送消息
	public static void sendMessage(String message, Session session) {
		try {
			for (String key : connections.keySet()) {
				connections.get(key).getBasicRemote().sendText(message);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}

 

   

  前台index.jsp代码

 

<%@ page language="java" pageEncoding="UTF-8" import="java.util.UUID"%>
<%
	String user = "user"+UUID.randomUUID();
	pageContext.setAttribute("user", user);
%>
<html>
<head>
	<title>WebSocket 聊天室</title>
	<!-- 引入CSS文件 -->
	<link rel="stylesheet" type="text/css" href="ext4/resources/css/ext-all.css">
	<link rel="stylesheet" type="text/css" href="ext4/shared/example.css" />
	<link rel="stylesheet" type="text/css" href="css/websocket.css" />
	
	<!-- 映入Ext的JS开发包,及自己实现的webscoket. -->
	<script type="text/javascript" src="ext4/ext-all-debug.js"></script>
	<script type="text/javascript" src="websocket.js"></script>
	<script type="text/javascript">
		var user = "${user}";
	</script>
</head>

<body>
	<h1>WebSocket聊天室</h1>
	<p>通过HTML5标准提供的API与Ext富客户端框架相结合起来,实现聊天室,有以下特点:</p>
	<ul class="feature-list" style="padding-left: 10px;">
		<li>实时获取数据,由服务器推送,实现即时通讯</li>
		<li>利用WebSocket完成数据通讯,区别于轮询,长连接等技术,节省服务器资源</li>
		<li>结合Ext进行页面展示</li>
		<li>用户上线下线通知</li>
	</ul>
	<div id="websocket_button"></div>
</body>
</html>

    

   websokect.js

   

//用于展示用户的聊天信息
Ext.define('MessageContainer', {

	extend : 'Ext.view.View',

	trackOver : true,

	multiSelect : false,

	itemCls : 'l-im-message',

	itemSelector : 'div.l-im-message',

	overItemCls : 'l-im-message-over',

	selectedItemCls : 'l-im-message-selected',

	style : {
		overflow : 'auto',
		backgroundColor : '#fff'
	},

	tpl : [
			'<div class="l-im-message-warn">​交谈中请勿轻信汇款、中奖信息、陌生电话。 请遵守相关法律法规。</div>',
			'<tpl for=".">',
			'<div class="l-im-message">',
			'<div class="l-im-message-header l-im-message-header-{source}">{from}  {timestamp}</div>',
			'<div class="l-im-message-body">{content}</div>', '</div>',
			'</tpl>'],

	messages : [],

	initComponent : function() {
		var me = this;
		me.messageModel = Ext.define('Leetop.im.MessageModel', {
					extend : 'Ext.data.Model',
					fields : ['from', 'timestamp', 'content', 'source']
				});
		me.store = Ext.create('Ext.data.Store', {
					model : 'Leetop.im.MessageModel',
					data : me.messages
				});
		me.callParent();
	},

	//将服务器推送的信息展示到页面中
	receive : function(message) {
		var me = this;
		message['timestamp'] = Ext.Date.format(new Date(message['timestamp']),
				'H:i:s');
		if(message.from == user){
			message.source = 'self';
		}else{
			message.source = 'remote';
		}
		me.store.add(message);
		if (me.el.dom) {
			me.el.dom.scrollTop = me.el.dom.scrollHeight;
		}
	}
});

Ext.onReady(function() {
			//创建用户输入框
			var input = Ext.create('Ext.form.field.HtmlEditor', {
						region : 'south',
						height : 120,
						enableFont : false,
						enableSourceEdit : false,
						enableAlignments : false,
						listeners : {
							initialize : function() {
								Ext.EventManager.on(me.input.getDoc(), {
											keyup : function(e) {
												if (e.ctrlKey === true
														&& e.keyCode == 13) {
													e.preventDefault();
													e.stopPropagation();
													send();
												}
											}
										});
							}
						}
					});
			//创建消息展示容器
			var output = Ext.create('MessageContainer', {
						region : 'center'
					});

			var dialog = Ext.create('Ext.panel.Panel', {
						region : 'center',
						layout : 'border',
						items : [input, output],
						buttons : [{
									text : '发送',
									handler : send
								}]
					});
			var websocket;

			//初始话WebSocket
			function initWebSocket() {
				if (window.WebSocket) {
					websocket = new WebSocket(encodeURI('ws://localhost/webscoket/chat/'+user));
					websocket.onopen = function() {
						//连接成功
						win.setTitle(title + '&nbsp;&nbsp;(已连接)');
					}
					websocket.onerror = function() {
						//连接失败
						win.setTitle(title + '&nbsp;&nbsp;(连接发生错误)');
					}
					websocket.onclose = function() {
						//连接断开
						win.setTitle(title + '&nbsp;&nbsp;(已经断开连接)');
					}
					//消息接收
					websocket.onmessage = function(message) {
						var message = JSON.parse(message.data);
						//接收用户发送的消息
						if (message.type == 'message') {
							output.receive(message);
						} else if (message.type == 'get_online_user') {
							//获取在线用户列表
							var root = onlineUser.getRootNode();
							Ext.each(message.list,function(user){
								var node = root.createNode({
									id : user,
									text : user,
									iconCls : 'user',
									leaf : true
								});
								root.appendChild(node);
							});
						} else if (message.type == 'user_join') {
							//用户上线
								var root = onlineUser.getRootNode();
								var user = message.user;
								var node = root.createNode({
									id : user,
									text : user,
									iconCls : 'user',
									leaf : true
								});
								root.appendChild(node);
						} else if (message.type == 'user_leave') {
								//用户下线
								var root = onlineUser.getRootNode();
								var user = message.user;
								var node = root.findChild('id',user);
								root.removeChild(node);
						}
					}
				}
			};

			//在线用户树
			var onlineUser = Ext.create('Ext.tree.Panel', {
						title : '在线用户',
						rootVisible : false,
						region : 'east',
						width : 150,
						lines : false,
						useArrows : true,
						autoScroll : true,
						split : true,
						iconCls : 'user-online',
						store : Ext.create('Ext.data.TreeStore', {
									root : {
										text : '在线用户',
										expanded : true,
										children : []
									}
								})
					});
			var title = '欢迎您:' + user;
			//展示窗口
			var win = Ext.create('Ext.window.Window', {
						title : title + '&nbsp;&nbsp;(未连接)',
						layout : 'border',
						iconCls : 'user-win',
						minWidth : 650,
						minHeight : 460,
						width : 650,
						animateTarget : 'websocket_button',
						height : 460,
						items : [dialog,onlineUser],
						border : false,
						listeners : {
							render : function() {
								initWebSocket();
							}
						}
					});

			win.show();

			//发送消息
			function send() {
				var message = {};
				if (websocket != null) {
					if (input.getValue()) {
						Ext.apply(message, {
									from : user,
									content : input.getValue(),
									timestamp : new Date().getTime(),
									type : 'message'
								});
						websocket.send(JSON.stringify(message));
						//output.receive(message);
						input.setValue('');
					}
				} else {
					Ext.Msg.alert('提示', '您已经掉线,无法发送消息!');
				}
			}
		});

    我使用的开发环境是eclipse kepler + tomcat8.0.32+jdk7.x

 

    以下是tomat7实现和tomcat8实现的源码。

    

分享到:
评论

相关推荐

    基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统,界面美观,适合快速迭代开发

    基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统,界面美观,适合快速迭代开发 项目说明 技术栈: SpringBoot MyBatis Redis MySQL FreeMarker ExtJs 基于SpringBoot+FreeMarker+MyBatis+...

    基于SpringBoot+FreeMarker+MyBatis+ExtJs的一个通用后台管理系统源码(适合快速迭代开发).zip

    1、基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统源码(适合快速迭代开发).zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计...

    Tomcat WebSocket

    1. **WebSocket协议**:WebSocket基于TCP,通过HTTP/1.1的Upgrade头字段进行初始化,之后建立一个长期存在的连接,允许双向数据流。 2. **Tomcat的WebSocket支持**:Tomcat从7.0版本开始内置了对WebSocket的支持,...

    Extjs实现的聊天室

    在本项目中,“Extjs实现的聊天室”利用了ExtJS的组件化特性和WebSocket技术,构建了一个实时的在线聊天平台。 WebSocket是一种在客户端和服务器之间建立长连接的协议,允许双方进行全双工通信,即数据可以在任意...

    基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统.zip

    《基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的通用后台管理系统详解》 在当前的IT领域,SpringBoot框架已经成为开发企业级应用的首选工具,尤其在构建后台管理系统时,其便捷性和高效性尤为突出。本项目“基于...

    基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统,界面美观,.zip

    本资源中的源码都是经过本地编译过可运行的,下载后按照文档配置好环境就可以运行。资源项目的难度比较适中,内容都是经过助教老师审定过的,应该能够满足学习、使用需求,如果有需要的话可以放心下载使用。...

    基于SpringBoot+FreeMarker+MyBatis+ExtJs的通用后台管理系统完整源码(适合快速迭代开发).zip

    【资源说明】 1、该资源内项目代码都是经过测试运行成功,功能正常的情况下才上传的,请放心下载使用。...基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统源码(适合快速迭代开发).zip

    spring+mvc+mybatis+extjs整合

    【标题】"spring+mvc+mybatis+extjs整合"是一个经典的Java Web开发框架组合,广泛应用于企业级应用。这个项目结合了Spring MVC作为控制层,MyBatis作为数据访问层,以及ExtJS作为前端展示层,构建了一个完整的三层...

    基于Tomcat7、Java、Ext、WebSocket的聊天室

    该项目是一个实时聊天应用程序,利用了Java技术栈与现代Web通信技术WebSocket,构建在Tomcat7服务器上,并且前端界面采用了ExtJS框架。以下是对这些关键知识点的详细解释: 1. **WebSocket**: WebSocket是一种在...

    easyjweb+jpa+spring+extjs续

    easyjweb+jpa+spring+extjs续:实现了综合配货系统后台管理,由于时间关系,有些细节没有考虑到,但是框架打气来,没有什么大问题,由于时间关系现在就更新到这,需要的请下载,认真学完现在更新的和以后更新的,项目...

    Java+Extjs实现单文件上传

    本话题主要关注如何使用Java后端和ExtJS前端框架来实现单文件上传的流程。下面将详细讲解这个过程涉及的关键知识点。 首先,我们来看Java文件上传。在Java中,处理文件上传主要依赖于Servlet API中的`Part`接口,这...

    Extjs+java+swf多文件上传进度条显示项目

    标题中的“Extjs+java+swf多文件上传进度条显示项目”是一个综合性的Web开发实践,涉及到前端的用户界面、后端的数据处理以及文件上传过程中进度反馈的实现。这个项目利用了Extjs库来构建用户界面,Java作为服务器端...

    基于SpringBoot+FreeMarker+MyBatis+ExtJs实现的一个通用后台管理系统

    用Java写的项目,项目真实可靠,可用作本科毕业设计,欢迎大家下载学习。用Java写的项目,项目真实可靠,可用作本科毕业设计,欢迎大家下载学习。用Java写的项目,项目真实可靠,可用作本科毕业设计,欢迎大家下载...

    Java + ExtJs示例

    8. **异常处理**:Java后端需要良好的异常处理机制,确保错误能够被妥善处理,并向ExtJS前端发送有意义的错误信息。 在实际项目中,开发者需要熟练掌握Java和ExtJS的API,理解它们的交互方式,以便创建出高效且用户...

    (基于JSP的完整java毕业设计)ExtJS 2.2 图书管理系统-bmsh(附源码).rar

    (基于JSP的完整java毕业设计)ExtJS 2.2 图书管理系统(基于JSP的完整java毕业设计)ExtJS 2.2 图书管理系统(基于JSP的完整java毕业设计)ExtJS 2.2 图书管理系统(基于JSP的完整java毕业设计)ExtJS 2.2 图书管理...

    基于WebSocket的企业级即时通讯WebIM,使用EXTJS做为前端设计工具

    它可以基于诸如Node.js的Socket.IO库或者Java的Jetty等WebSocket实现。 2. **EXTJS前端**:通过EXTJS的组件库,构建用户界面,如聊天窗口、好友列表、消息输入框等,并通过WebSocket API与服务器保持实时通信。 3....

    基于webSocket的聊天室

    基于HTML5,extjs、webSocket的聊天室源代码

Global site tag (gtag.js) - Google Analytics