ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【功能】实现websocket/设计线程安全

【功能】实现websocket/设计线程安全 一、 所需jar包dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-websocket/artifactId/dependencydependencygroupIdorg.apache.commons/groupIdartifactIdcommons-lang3/artifactIdversion3.5/version/dependencydependencygroupIdcom.google.code.gson/groupIdartifactIdgson/artifactIdversion2.8.6/version/dependencydependencygroupIdcom.github.wnameless.json/groupIdartifactIdjson-flattener/artifactIdversion0.8.1/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency二、实现方式packagecom.xiaobai.ws;importcom.github.wnameless.json.flattener.JsonFlattener;importcom.google.gson.Gson;importcom.xiaobai.utils.GsonUtil;importorg.apache.commons.lang3.StringUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.messaging.simp.SimpMessagingTemplate;importorg.springframework.stereotype.Component;importjavax.websocket.*;importjavax.websocket.server.ServerEndpoint;importjava.io.*;importjava.util.HashMap;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;/** * Author xiaobai * Date 2023/3/28 16:18 * description: * Title: WebSocketServer * Package com.xiaobai.ws */ServerEndpoint(/websocket/test)ComponentpublicclassWebSocketServer{privatestaticLoggerlogLoggerFactory.getLogger(WebSocketServer.class);//静态变量用来记录当前在线连接数。应该把它设计成线程安全的。privatestaticintonlineCount0;//concurrent包的线程安全Mep用来存放每个客户端对应的MyWebSocket对象。privatestaticConcurrentHashMapWebSocketServer,SessionwebSocketServerSessionConcurrentHashMapnewConcurrentHashMap();//与某个客户端的连接会话需要通过它来给客户端发送数据privateSessionsession;//消息发送模板AutowiredprivateSimpMessagingTemplatesimpMessageSendingOperations;// 发送睡眠时间 5000LValue(${websocket.timeout})publicStringsleepTime;// 文件路径Value(${websocket.file})privateFilefile;/** * 对文件数据循环且递归发送 */publicvoidsendMessageValue(WebSocketServerwebSocketServer,Sessionsession){// 如果文件不存在if(!file.exists()){return;}BufferedReaderbufferedReadernull;try{FileReaderfrnewFileReader(file);bufferedReadernewBufferedReader(fr);Stringlinenull;// 判断当前是否是空行while(StringUtils.isNotEmpty(linebufferedReader.readLine())){// 发送消息synchronized(session){Thread.sleep(sleepTime);if(session.isOpen()){webSocketServer.sendMessage(line);// log.info(发送消息 message {} 消息-socket {} session-id {} inline {}, value.get(id), webSocketServer, session.getId(), getOnlineCount());}}}// 闭流if(fr!null){fr.close();}if(bufferedReader!null){bufferedReader.close();}// 继续递归this.sendMessageValue(this,session);}catch(FileNotFoundExceptione){thrownewRuntimeException(e);}catch(IOExceptione){thrownewRuntimeException(e);}catch(IllegalStateExceptione){thrownewRuntimeException(e);}catch(InterruptedExceptione){// 当传输数据与jvm数据不一致时会有此异常thrownewRuntimeException(e);}}/** * 连接建立成功调用的方法 */OnOpenpublicvoidonOpen(Sessionsession){this.sessionsession;webSocketServerSessionConcurrentHashMap.put(this,session);//加入map中addOnlineCount();//在线数加1log.info(有新窗口开始监听,当前在线人数为getOnlineCount());// 以下代码若无需复用可以进行注销仅做为示例参考try{// sendMessage(连接成功);synchronized(session){sendMessageValue(this,session);}}catch(Exceptione){log.error(websocket IO异常);}}/** * 连接关闭调用的方法 */OnClosepublicvoidonClose(Sessionsession){try{webSocketServerSessionConcurrentHashMap.remove(this);//从map中删除subOnlineCount();//在线数减1session.close();log.info(有一连接关闭当前在线人数为getOnlineCount());}catch(IOExceptione){e.printStackTrace();}}/** * 收到客户端消息后调用的方法 * * param message 客户端发送过来的消息 */OnMessagepublicvoidonMessage(Stringmessage,Sessionsession){log.info(收到的信息:message);MapString,ObjectmapsnewHashMap();maps.put(type,message);this.sendInfo(maps);}/** * param session * param error */OnErrorpublicvoidonError(Sessionsession,Throwableerror){log.error(发生错误);//发生错误后会断开当前主机连接error.printStackTrace();}/** * 实现服务器主动推送 */publicvoidsendMessage(Objectobj){try{synchronized(this.session){this.session.getBasicRemote().sendText((GsonUtil.obj2GsonString(obj)));}}catch(IllegalStateExceptione){log.error(java.lang.IllegalStateException: 推送信息不同步请确保网络连接稳定);}catch(Exceptione){e.printStackTrace();}}/** * 群发自定义消息 */publicvoidsendInfo(Objectobj){for(Map.EntryWebSocketServer,Sessionitem:webSocketServerSessionConcurrentHashMap.entrySet()){try{item.getKey().sendMessage(obj);}catch(Exceptione){continue;}}}publicstaticsynchronizedintgetOnlineCount(){returnonlineCount;}publicstaticsynchronizedvoidaddOnlineCount(){WebSocketServer.onlineCount;}publicstaticsynchronizedvoidsubOnlineCount(){WebSocketServer.onlineCount--;}}packagecom.xiaobai.utils;importcom.google.gson.*;importcom.google.gson.reflect.TypeToken;importjava.util.ArrayList;importjava.util.List;importjava.util.Map;/** * ClassName:GsonUtil * Author: xiaobai * Date:2020-04-10 4:16 PM * Description: */publicclassGsonUtil{privatestaticGsongson;static{gsonnewGsonBuilder().setDateFormat(yyyy-MM-dd HH:mm:ss).create();}privateGsonUtil(){}/** * 将object对象转成json字符串 * * param object * return */publicstaticStringobj2GsonString(Objectobject){StringgsonStringnull;if(gson!null){gsonStringgson.toJson(object);}returngsonString;}/** * 将gsonString转成泛型bean * * param gsonString * param cls * return */publicstaticTTgsonToBean(StringgsonString,ClassTcls){Ttnull;if(gson!null){tgson.fromJson(gsonString,cls);}returnt;}/** * 转成list * 泛型在编译期类型被擦除导致报错 * param gsonString * param cls * return */// public static T ListT GsonToList(String gsonString, ClassT cls) {// ListT list null;// if (gson ! null) {// list gson.fromJson(gsonString, new TypeTokenListT() {// }.getType());// }// return list;// }/** * 转成list * 解决泛型在编译期类型被擦除导致报错 * * param json * param cls * param T * return */publicstaticTListTjsonToList(Stringjson,ClassTcls){GsongsonnewGson();ListTlistnewArrayList();JsonArrayarrayJsonParser.parseString(json).getAsJsonArray();for(finalJsonElementelem:array){list.add(gson.fromJson(elem,cls));}returnlist;}/** * 转成list中有map的 * * param gsonString * return */publicstaticTListMapString,TgsonToListMaps(StringgsonString){ListMapString,Tlistnull;if(gson!null){listgson.fromJson(gsonString,newTypeTokenListMapString,T(){}.getType());}returnlist;}/** * 转成map的 * * param gsonString * return */publicstaticTMapString,TgsonToMaps(StringgsonString){MapString,Tmapnull;if(gson!null){mapgson.fromJson(gsonString,newTypeTokenMapString,T(){}.getType());}returnmap;}}
返回列表