一、Server端
1.1、引入依赖
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.0</version>
</dependency>
1.2、创建WsPool类
public class WsPool {
private static final Map<WebSocket, Integer> wsUserMap = new HashMap<WebSocket, Integer>(); //这是用连接对应用户id的Map集合
private static final Map<Integer, WebSocket> wsUserMaps = new HashMap<Integer, WebSocket>(); //这是用户Id对应连接的Map集合
/**
* 通过websocket连接获取其对应的用户
*/
public static Integer getUserByWs(WebSocket conn) {
return wsUserMap.get(conn);
}
public static WebSocket getUserByWss(Integer userId) {
return wsUserMaps.get(userId);
}
/**
* 向连接池中添加连接
*/
public static void addUser(Integer userId, WebSocket conn) {
wsUserMap.put(conn, userId); // 添加连接
}
public static void addUsers(WebSocket conn, Integer userId) {
wsUserMaps.put(userId, conn); // 添加连接
}
/**
* 移除连接池中的连接
*/
public static boolean removeUser(WebSocket conn) {
if (wsUserMap.containsKey(conn)) {
wsUserMap.remove(conn); // 移除连接
return true;
} else {
return false;
}
}
/**
* 向特定的用户发送数据
*/
public static void sendMessageToUser(WebSocket conn, String message) {
if (null != conn && null != wsUserMap.get(conn)) {
conn.send(message);
}
}
/**
* 向所有的用户发送消息
*/
public static void sendMessageToAll(String message) {
Set<WebSocket> keySet = wsUserMap.keySet();
synchronized (keySet) {
for (WebSocket conn : keySet) {
Integer userId = wsUserMap.get(conn);
if (userId != null) {
conn.send(message);
}
}
}
}
1.3、创建MyWebSocket类,继承WebSocket
@Component
public class MyWebScoket extends WebSocketServer {
private int Number;
private static MyWebScoket myWebScoket;
public MyWebScoket() throws UnknownHostException {
super();
}
public MyWebScoket(InetSocketAddress address) {
super(address);
}
@Override
//监听用户连接
public void onOpen(WebSocket conn, ClientHandshake handshake) {
System.out.println("在线人数+1");
Number++;
System.out.println("当前在线人数:" + Number);
System.out.println("连接上");
// ws连接的时候触发的代码,onOpen中我们不做任何操作
}
@Override
//监听用户断开
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
System.out.println("在线人数-1");
Number--;
System.out.println("当前在线人数:" + Number);
Integer userId = WsPool.getUserByWs(conn);
//断开连接时候触发代码
userLeave(conn);
System.out.println(reason);
}
@Override
//监听用户发送的信息
public void onMessage(WebSocket conn, String message) {
//有用户连接进来
Map<String, String> obj = (Map<String, String>) JSONObject.parse(message);
Integer userId = Integer.valueOf(obj.get("userId"));
userJoin(userId,conn); //将连接作为key,将用户id作为value
userJoins(userId,conn); 将用户id作为key,将连接作为value
}
@Override
public void onError(WebSocket conn, Exception ex) {
//错误时候触发的代码
System.out.println("on error");
ex.printStackTrace();
}
/**
* 去除掉失效的websocket链接
*/
private void userLeave(WebSocket conn) {
WsPool.removeUser(conn);
}
/**
* 将websocket加入用户池
*
* @param conn
* @param userId
*/
private void userJoin(Integer userId, WebSocket conn) {
WsPool.addUser(userId, conn);
}
private void userJoins(Integer userId, WebSocket conn) {
WsPool.addUsers(conn, userId);
}
}
1.4、在需要通知客户端的地方向客户端发送通知
调用WsPool类的sendMessageToUser方法
WsPool.sendMessageToUser(WsPool.getUserByWss(equipment.getCreateBy()),"4");
二、Client端,已小程序为例
2.1、首先创建一个连接的全局变量在App.js里
var socketOpen = false; //声明连接状态的全局变量
App({
globalData: {
ipw: "ws://2o464010g0.zicp.vip:33618", //自己的WebSocket服务器网址
limit: 0,
timeout: 10000,
timeoutObj: null,
serverTimeoutObj: null,
callback: function() {}, //监听WebSocket服务器发送过来的
submitTo: function() {}, //向服务器发送数据的方法,可全局调用
header: {
'content-type': 'application/json',
'Cookie': ''
}
},
onLaunch: function() {
//判断连接状态,如果没连接调用连接WebSocket的方法
if (!socketOpen) {
this.linkSocket()
}
},
//连接服务器的方法
linkSocket() {
var that = this
wx.connectSocket({
url: that.globalData.ipw,
success() {
socketOpen = true;
that.initEventHandle()
}
})
},
//绑定事件
initEventHandle() {
var that = this
//向服务器发送数据的方法
wx.onSocketMessage((res) => {
if (res.data == "pong") {
that.reset()
that.start()
} else {
that.globalData.callback(res)
}
})
//监听有没有连接上服务器
wx.onSocketOpen(() => {
console.log('WebSocket连接打开')
})
wx.onSocketError((res) => {
console.log('WebSocket连接打开失败')
// that.reconnect()
socketOpen: false
that.linkSocket()
})
//监听关闭连接
wx.onSocketClose((res) => {
console.log('WebSocket 已关闭!')
socketOpen:false
that.linkSocket()
})
},
//重新连接
reconnect() {
var that = this;
if (that.lockReconnect) return;
that.lockReconnect = true;
clearTimeout(that.timer)
if (that.globalData.limit < 10) {//连接10次后不再重新连接
that.timer = setTimeout(() => {
that.linkSocket();
that.lockReconnect = false;
console.log("次数:" + that.globalData.limit)
}, 5000);//每隔5秒连接一次
that.globalData.limit = that.globalData.limit + 1
}
},
submitTo: function (e) {
let that = this;
var data = {
userId: 17 + "",
body: "啦啦啦",
roomId: 1 + ""
}
if (socketOpen) {
// 如果打开了socket就发送数据给服务器
console.log('通过 WebSocket 连接发送数据', JSON.stringify(data))
SocketTask.send({
data: JSON.stringify(data)
}, function (res) {
console.log('已发送', res)
})
}
},
//心跳包开始
reset: function () {
var that = this;
clearTimeout(that.globalData.timeoutObj);
clearTimeout(that.globalData.serverTimeoutObj);
return that;
},
start: function () {
var that = this;
var randomNum = that.randomWord(false, 16);//生成随机码
that.globalData.timeoutObj = setTimeout(() => {
that.globalData.serverTimeoutObj = setTimeout(() => {
}, that.globalData.timeout);
}, that.globalData.timeout);
},
//心跳包结束
//创建随机数,服务器用来存储是哪个小程序的心跳包的key,由于本案逻辑需要与其它信息存储的key分开,如果逻辑不需要,可以不进行分离,自定义存储的key
randomWord: function (randomFlag, min, max) {
var str = "",
range = min,
arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
// 随机产生
if (randomFlag) {
range = Math.round(Math.random() * (max - min)) + min;
}
for (var i = 0; i < range; i++) {
var pos = Math.round(Math.random() * (arr.length - 1));
str += arr[pos];
}
return str;
}
})
2.2、具体应用到页面
在页面监听服务器发送回来的数据,去请求对应的接口
app.globalData.callback = function(res) { //接收服务器发来的非心跳包数据
/**
*里面写收到服务器发来的非心跳包数据,根据业务需求做后续逻辑处理
*/
console.log(res)
if (res.data == "3") {
//如果是3,查看工人请求
that.getWorking();
} else if (res.data == "4") {
//如果是4,查看预警记录
that.getweichuli();
}
}