1. 后台 启动类,执行main方法启动
package com.fh; import java.io.IOException; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Date; import net.sf.json.JSONObject; import org.java_websocket.WebSocket; import org.java_websocket.WebSocketImpl; import org.java_websocket.framing.Framedata; import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.server.WebSocketServer; /** * @author FH * from fhadmin.cn * 2021-5-16 */ public class ChatServer extends WebSocketServer{ public ChatServer(int port) throws UnknownHostException { super(new InetSocketAddress(port)); } public ChatServer(InetSocketAddress address) { super(address); } /** * 触发连接事件 */ @Override public void onOpen( WebSocket conn, ClientHandshake handshake ) { //this.sendToAll( "new connection: " + handshake.getResourceDescriptor() ); //System.out.println( conn.getRemoteSocketAddress().getAddress().getHostAddress()); } /** * 触发关闭事件 */ @Override public void onClose( WebSocket conn, int code, String reason, boolean remote ) { userLeave(conn); } /** * 客户端发送消息到服务器时触发事件 */ @Override public void onMessage(WebSocket conn, String message){ message = message.toString(); if(null != message && message.startsWith("FHadmin313596790")){ this.userjoin(message.replaceFirst("FHadmin313596790", ""),conn); }if(null != message && message.startsWith("LeaveFHadmin313596790")){ this.userLeave(conn); }if(null != message && message.contains("fhadmin886")){ String toUser = message.substring(message.indexOf("fhadmin886")+10, message.indexOf("fhfhadmin888")); message = message.substring(0, message.indexOf("fhadmin886")) +"[私信] "+ message.substring(message.indexOf("fhfhadmin888")+12, message.length()); ChatServerPool.sendMessageToUser(ChatServerPool.getWebSocketByUser(toUser),message);//向所某用户发送消息 ChatServerPool.sendMessageToUser(conn, message);//同时向本人发送消息 }else{ ChatServerPool.sendMessage(message.toString());//向所有在线用户发送消息 } } public void onFragment( WebSocket conn, Framedata fragment ) { } /** * 触发异常事件 */ @Override public void onError( WebSocket conn, Exception ex ) { ex.printStackTrace(); if( conn != null ) { //some errors like port binding failed may not be assignable to a specific websocket } } /** * 用户加入处理 * @param user */ public void userjoin(String user, WebSocket conn){ JSONObject result = new JSONObject(); result.element("type", "user_join"); result.element("user", "<a onclick=\"toUserMsg('"+user+"');\">"+user+"</a>"); ChatServerPool.sendMessage(result.toString()); //把当前用户加入到所有在线用户列表中 String joinMsg = "{\"from\":\"[系统]\",\"content\":\""+user+"上线了\",\"timestamp\":"+new Date().getTime()+",\"type\":\"message\"}"; ChatServerPool.sendMessage(joinMsg); //向所有在线用户推送当前用户上线的消息 result = new JSONObject(); result.element("type", "get_online_user"); ChatServerPool.addUser(user,conn); //向连接池添加当前的连接对象 result.element("list", ChatServerPool.getOnlineUser()); ChatServerPool.sendMessageToUser(conn, result.toString()); //向当前连接发送当前在线用户的列表 } /** * 用户下线处理 * @param user */ public void userLeave(WebSocket conn){ String user = ChatServerPool.getUserByKey(conn); boolean b = ChatServerPool.removeUser(conn); //在连接池中移除连接 if(b){ JSONObject result = new JSONObject(); result.element("type", "user_leave"); result.element("user", "<a onclick=\"toUserMsg('"+user+"');\">"+user+"</a>"); ChatServerPool.sendMessage(result.toString()); //把当前用户从所有在线用户列表中删除 String joinMsg = "{\"from\":\"[系统]\",\"content\":\""+user+"下线了\",\"timestamp\":"+new Date().getTime()+",\"type\":\"message\"}"; ChatServerPool.sendMessage(joinMsg); //向在线用户发送当前用户退出的消息 } } public static void main( String[] args ) throws InterruptedException , IOException { WebSocketImpl.DEBUG = false; int port = 8887; //端口 ChatServer s = new ChatServer(port); s.start(); //System.out.println( "服务器的端口" + s.getPort() ); } }
2.ChatServerPool.java
package com.fh; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.java_websocket.WebSocket; /** * @author FH * from fhadmin.cn * 2021-5-16 */ public class ChatServerPool { /*保存连接的MAP容器*/ private static final Map<WebSocket,String> userconnections = new HashMap<WebSocket,String>(); /** * 获取用户名 * @param session */ public static String getUserByKey(WebSocket conn){ return userconnections.get(conn); } /** * 获取WebSocket * @param user */ public static WebSocket getWebSocketByUser(String user){ Set<WebSocket> keySet = userconnections.keySet(); synchronized (keySet) { for (WebSocket conn : keySet) { String cuser = userconnections.get(conn); if(cuser.equals(user)){ return conn; } } } return null; } /** * 向连接池中添加连接 * @param inbound */ public static void addUser(String user, WebSocket conn){ userconnections.put(conn,user); //添加连接 } /** * 获取所有的在线用户 * @return */ public static Collection<String> getOnlineUser(){ List<String> setUsers = new ArrayList<String>(); Collection<String> setUser = userconnections.values(); for(String u:setUser){ setUsers.add("<a onclick=\"toUserMsg('"+u+"');\">"+u+"</a>"); } return setUsers; } /** * 移除连接池中的连接 * @param inbound */ public static boolean removeUser(WebSocket conn){ if(userconnections.containsKey(conn)){ userconnections.remove(conn); //移除连接 return true; }else{ return false; } } /** * 向特定的用户发送数据 * @param user * @param message */ public static void sendMessageToUser(WebSocket conn,String message){ if(null != conn && null != userconnections.get(conn)){ conn.send(message); } } /** * 向所有的用户发送消息 * @param message */ public static void sendMessage(String message){ Set<WebSocket> keySet = userconnections.keySet(); synchronized (keySet) { for (WebSocket conn : keySet) { String user = userconnections.get(conn); if(user != null){ conn.send(message); } } } } }
3.前端
var websocket; var isCreatw = false; var title=""; var win; var input; var isQj = true; var toUser=""; function toUserMsg(toU){ if((!isQj && toUser == toU) || toU == user){ win.setTitle(title + " (已连接) 【现在全局对话】"); isQj = true; toUser = ""; }else{ win.setTitle(title + " (已连接) 【现在单独与"+toU+"对话】"); isQj = false; toUser = toU; } } function creatw() { if(isCreatw){ alert("已经启动"); return; }else{ isCreatw = true; } //创建用户输入框 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 }] }); //初始话WebSocket function initWebSocket() { if (window.WebSocket) { websocket = new WebSocket(encodeURI('ws://127.0.0.1:8887')); websocket.onopen = function() { //连接成功 win.setTitle(title + ' (已连接) 【现在全局对话】'); websocket.send('FHadmin313596790'+user); } websocket.onerror = function() { //连接失败 win.setTitle(title + ' (连接发生错误)'); } websocket.onclose = function() { //连接断开 win.setTitle(title + ' (已经断开连接)'); } //消息接收 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 : [] } }) }); title = '欢迎您:' + user; //展示窗口 win = Ext.create('Ext.window.Window', { title : title + ' (未连接)', 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(); win.on("close",function(){ websocket.send('LeaveFHadmin313596790'); isCreatw = false; }); //发送消息 function send() { var content = input.getValue(); if(toUser != ""){content = "fhadmin886"+toUser+"fhfhadmin888" + content;} var message = {}; if (websocket != null) { if (input.getValue()) { Ext.apply(message, { from : user, content : content, timestamp : new Date().getTime(), type : 'message' }); websocket.send(JSON.stringify(message)); //output.receive(message); input.setValue(''); } } else { Ext.Msg.alert('提示', '您已经掉线,无法发送消息!'); } } }; //用于展示用户的聊天信息 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">欢迎使用FH Admin 即时通讯系统。</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; } } });