websocket 连接框架(基于WebSocket的网页端即时通讯技术)
websocket 连接框架(基于WebSocket的网页端即时通讯技术)@CHARSET "UTF-8"; .l-im-message-warn { font-family: "微软雅黑"; cursor: default; width: 100%; padding: 5px 0px 5px 25px; -webkit-user-select : none; background: url("../images/information.png") no-repeat 5; } .l-im-message { font-family: "微软雅黑"; cursor: default; width: 100%; } .l-im-message-over { background-color: rgba(233 233 233 0.5); } .l-im-message-selected { background-color: rgba(
基于html5的Websocket网页即时通讯技术,前端开发采用ExtJS前端框架
JavaEE框架:Mybatis、SpringMVC
先去官网下载ExtJS框架的资料文件:
https://www.sencha.com/products/extjs/evaluate/
可以参考中文翻译过来的官网查看API:
http://extjs-doc-cn.github.io/ext4api/
下载集成的jar:
websocket.css:
@CHARSET "UTF-8"; .l-im-message-warn { font-family: "微软雅黑"; cursor: default; width: 100%; padding: 5px 0px 5px 25px; -webkit-user-select : none; background: url("../images/information.png") no-repeat 5; } .l-im-message { font-family: "微软雅黑"; cursor: default; width: 100%; } .l-im-message-over { background-color: rgba(233 233 233 0.5); } .l-im-message-selected { background-color: rgba(250 218 90 0.5); } .l-im-message-header { font-size: 12px; padding: 5px 0px 5px 10px; } .l-im-message-header-self { color: green; } .l-im-message-header-remote { color: blue; } .l-im-message-body { font-size: 12px; padding: 2px 0px 2px 20px; } .user-win { background-image: url( ../images/user_win.png ) !important; } .user-online { background-image: url( ../images/group.png ) !important; } .user { background-image: url( ../images/user.gif ) !important; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
websocket.js:
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://' wimadress)); websocket.onopen = function() { //连接成功 win.setTitle(title ' (已连接) 【现在全局对话】'); websocket.send('admin' 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('LeaveAdmin'); isCreatw = false; }); //发送消息 function send() { var content = input.getValue(); if(toUser != ""){content = "admin886" toUser "admin888" 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">欢迎使用即时通讯系统。</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; } } }); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
业务代码编写:
ChatServer.java
package com.appms.websocket; 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; /** * 即时通讯 */ 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 ) { } /** * 触发关闭事件 */ @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("admin")){ this.userjoin(message.replaceFirst("admin" "") conn); }if(null != message && message.startsWith("LeaveAdmin")){ this.userLeave(conn); }if(null != message && message.contains("admin886")){ String toUser = message.substring(message.indexOf("admin886") 8 message.indexOf("admin888")); message = message.substring(0 message.indexOf("admin886")) "[私信] " message.substring(message.indexOf("admin888") 8 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() ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
ChatServerPool.java:
package com.appms.websocket; 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; /** * 即时通讯 */ public class ChatServerPool { 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); } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
写个过滤器,在项目执行时启动:
package com.appms.filter; import java.io.IOException; import java.net.UnknownHostException; import java.util.Calendar; import java.util.Date; import java.util.Timer; import java.util.TimerTask; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.java_websocket.WebSocketImpl; import com.appms.base.BaseController; import com.appms.base.Const; import com.appms.utils.Tools; import com.appms.websocket.ChatServer; import com.appms.websocket.OnlineChatServer; public class StartFilter extends BaseController implements Filter{ /** * 初始化 */ public void init(FilterConfig fc) throws ServletException { this.startWebsocketInstantMsg(); this.startWebsocketOnline(); } /** * 启动即时聊天服务 */ public void startWebsocketInstantMsg(){ WebSocketImpl.DEBUG = false; ChatServer s = null; try { String strWEBSOCKET = Tools.readTxtFile(Const.WEBSOCKET);//读取WEBSOCKET配置 获取端口配置 if(null != strWEBSOCKET && !"".equals(strWEBSOCKET)){ String strIW[] = strWEBSOCKET.split(" fh "); if(strIW.length == 4){ s = new ChatServer(Integer.parseInt(strIW[1])); s.start(); } } System.out.println( "websocket服务器启动 端口" s.getPort() ); } catch (UnknownHostException e) { e.printStackTrace(); } } /** * 启动在线管理服务 */ public void startWebsocketOnline(){ WebSocketImpl.DEBUG = false; OnlineChatServer s = null; try { String strWEBSOCKET = Tools.readTxtFile(Const.WEBSOCKET);//读取WEBSOCKET配置 获取端口配置 if(null != strWEBSOCKET && !"".equals(strWEBSOCKET)){ String strIW[] = strWEBSOCKET.split(" fh "); if(strIW.length == 4){ s = new OnlineChatServer(Integer.parseInt(strIW[3])); s.start(); } } System.out.println( "websocket服务器启动 端口" s.getPort() ); } catch (UnknownHostException e) { e.printStackTrace(); } } //计时器 public void timer() { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY 9); // 控制时 calendar.set(Calendar.MINUTE 0); // 控制分 calendar.set(Calendar.SECOND 0); // 控制秒 Date time = calendar.getTime(); // 得出执行任务的时间 Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { public void run() { //PersonService personService = (PersonService)ApplicationContext.getBean("personService"); } } time 1000*60*60*24);// 这里设定将延时每天固定执行 } public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest arg0 ServletResponse arg1 FilterChain arg2) throws IOException ServletException { // TODO Auto-generated method stub } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
在web.xml里配置:
<filter> <filter-name>startFilter</filter-name> <filter-class>com.appms.filter.StartFilter</filter-class> </filter> 1 2 3 4
在jsp页面进行调用:
<script type="text/javascript">var wimadress="127.0.0.1:8887";</script> <script type="text/javascript">var oladress="127.0.0.1:8889";</script> <link rel="stylesheet" type="text/css" href="plugins/websocket/ext4/resources/css/ext-all.css"> <link rel="stylesheet" type="text/css" href="plugins/websocket/css/websocket.css" /> <script type="text/javascript" src="https://img.aigexing.complugins/websocket/ext4/ext-all-debug.js"></script> <script type="text/javascript" src="https://img.aigexing.complugins/websocket/websocket.js"></script> <!--引入属于此页面的js --> <script type="text/javascript" src="https://img.aigexing.comsource/js/jquery-1.8.3.js"></script> 1 2 3 4 5 6 7 8 9
点击li标签跳出聊天页面
ul class="am-avg-sm-1 am-avg-md-4 am-margin am-padding am-text-center admin-content-list "> <li onclick="creatw();"><a href="javascript:;"><span class="am-icon-btn am-icon-file-text"></span><br/>即时通讯<br/></a></li> <li><a href="fusioncharts/index.do" class="am-text-warning"><span class="am-icon-btn am-icon-briefcase"></span><br/>图表统计<br/></a></li> <li><a href="#" class="am-text-danger"><span class="am-icon-btn am-icon-recycle"></span><br/>昨日访问<br/>80082</a></li> <li><a href="#" class="am-text-secondary"><span class="am-icon-btn am-icon-user-md"></span><br/>在线用户<br/>3000</a></li> </ul> 1 2 3 4 5 6
私聊:
群聊:
基于ExtJS前端框架的Websocket即时通讯系统