`

基于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实现的源码。

    

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics