多線程方式發生數據到前端(防止堵塞)
package com.chuangqi.core.socket;
import com.chuangqi.jna.DllMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 流程:
* 1. 前端先和後臺建立連接,url:/websocket/{當前瀏覽器用戶id};
* 2. 前端調用send()方法發送數據到後臺,方法(內容參數,當前瀏覽器用戶uuid),後臺進行輪詢調用態勢顯示;
* 注:通過“當前瀏覽器用戶id”進行區分推送消息到那個客戶端
*
* @author qizhentao
* @version V1.0
*/
@Controller
@Component
//訪問服務端的url地址
@ServerEndpoint(value = "/websocket/{id}")
public class WebSocketServer {
/**
* 在線數
*/
private static int onlineCount = 0;
private static ConcurrentHashMap<String, WebSocketServer> webSocketSet = new ConcurrentHashMap<>();
//與某個客戶端的連接會話,需要通過它來給客戶端發送數據
private Session session;
private String id = "";
private boolean isRun = true;// 判斷是否結束死循環-結束數據傳輸
private static Logger log = LogManager.getLogger(WebSocketServer.class);
/**
* 連接建立成功調用的方法
*/
@OnOpen
public void onOpen(@PathParam(value = "id") String id, Session session) {
this.session = session;
this.id = id;//接收到發送消息的人員編號
webSocketSet.put(id, this); //加入set中
addOnlineCount(); //在線數加1
log.info("用戶" + id + "加入!當前在線人數爲" + getOnlineCount());
try {
// 相應客戶端
sendMessage("連接成功");
} catch (IOException e) {
log.error("websocket IO異常");
}
}
/**
* 連接關閉調用的方法,前端調用onClone方法進行關閉
* http://tieba.baidu.com/p/6173318895?traceid=
*/
@OnClose
public void onClose() {
log.info("執行socket的onClose(),關閉id爲{}的用戶", id);
// 關閉當前用戶連接
webSocketSet.remove(this); //從set中刪除當前用戶
subOnlineCount(); //在線數減1
isRun = false;// fasle=關閉socket連接,停止while循環
log.info("有一連接關閉!當前在線人數爲" + getOnlineCount());
}
/**
* 收到客戶端消息後調用的方法
* - 態勢顯示服務初始化後前端調用send()方法告訴後臺可以輪詢發送數據,格式爲:數據|建立socket連接時傳入的id
*
* @param message 客戶端發送過來的消息
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("來自客戶端的消息:" + message);
//可以自己約定字符串內容,比如 “進行輪詢態勢|0“ 表示信息羣發, “進行輪詢態勢|x“ 表示信息發給id爲X的用戶
String sendMessage = message.split("[|]")[0];
String sendUserId = message.split("[|]")[1];
try {
if (sendUserId.equals("0"))
sendtoAll(sendMessage);
else
sendtoUser(sendMessage, sendUserId);
} catch (IOException e) {
e.printStackTrace();
}
}
@OnError
public void onError(Session session, Throwable error) {
log.error("發生錯誤");
error.printStackTrace();
}
/**
* 響應客戶端消息
*
* @param message
* @throws IOException
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 發送信息給指定ID用戶,如果用戶不在線則返回不在線信息給自己
*
* @param message
* @param sendUserId
* @throws IOException
*/
public void sendtoUser(String message, String sendUserId) throws IOException {
if (webSocketSet.get(sendUserId) != null) {
ExecutorService ex = Executors.newCachedThreadPool();
ex.execute(new Runnable() {
@Override
public void run() {
try {
while (isRun) {
// 調用動態庫,接收數據(實時數據發送給前端!!!)
String data = DllMap.instance.GetInteractiveData(false);
if(!id.equals(sendUserId)){
webSocketSet.get(sendUserId).sendMessage(data);
}else{
webSocketSet.get(sendUserId).sendMessage(data);
}
try {Thread.sleep(800);} catch (InterruptedException e) {e.printStackTrace();}
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
} else {
//如果用戶不在線則返回不在線信息給自己
//sendtoUser("當前用戶不在線",id);
}
}
/**
* 發送信息給所有人
*
* @param message
* @throws IOException
*/
public void sendtoAll(String message) throws IOException {
for (String key : webSocketSet.keySet()) {
try {
webSocketSet.get(key).sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}