WebSocket系列之的网页端即时通讯实现
【摘要】 本博客介绍基于html5的Websocket网页即时通讯技术,前端开发采用ExtJS前端框架 JavaEE框架:Mybatis、SpringMVC 先去官网下载ExtJS框架的资料文件: https://www.sencha.com/products/extjs/evaluate/ 可以参考中文翻译过来的官网查看API: http://extjs-doc-cn.gith...
本博客介绍基于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="plugins/websocket/ext4/ext-all-debug.js"></script>
<script type="text/javascript" src="plugins/websocket/websocket.js"></script>
<!--引入属于此页面的js -->
<script type="text/javascript" src="source/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即时通讯系统
文章来源: smilenicky.blog.csdn.net,作者:smileNicky,版权归原作者所有,如需转载,请联系作者。
原文链接:smilenicky.blog.csdn.net/article/details/54093181
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)