今天就跟大家聊聊有關(guān)SpringBoot中怎么利用WebSocket實現(xiàn)即時消息,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
成都創(chuàng)新互聯(lián)從2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目網(wǎng)站建設(shè)、網(wǎng)站制作網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元湘鄉(xiāng)做網(wǎng)站,已為上家服務(wù),為湘鄉(xiāng)各地企業(yè)和個人服務(wù),聯(lián)系電話:028-86922220
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
抽象消息對象
public class AbstractMessage { /** * 消息類型 */ protected String type ; /** * 消息內(nèi)容 */ protected String content ; /** * 消息日期 */ protected String date ; }
消息對象子類
1、Ping檢查消息
public class PingMessage extends AbstractMessage { public PingMessage() {} public PingMessage(String type) { this.type = type ; } }
2、系統(tǒng)消息
public class SystemMessage extends AbstractMessage { public SystemMessage() {} public SystemMessage(String type, String content) { this.type = type ; this.content = content ; } }
3、點對點消息
public class PersonMessage extends AbstractMessage { private String fromName ; private String toName ; }
消息類型定義
public enum MessageType { /** * 系統(tǒng)消息 0000;心跳檢查消息 0001;點對點消息2001 */ SYSTEM("0000"), PING("0001"), PERSON("2001") ; private String type ; private MessageType(String type) { this.type = type ; } public String getType() { return type; } public void setType(String type) { this.type = type; } }
該類作用就是定義客戶端連接的地址
@ServerEndpoint(value = "/message/{username}", encoders = {WsMessageEncoder.class}, decoders = {WsMessageDecoder.class}, subprotocols = {"gmsg"}, configurator = MessageConfigurator.class) @Component public class GMessageListener { public static ConcurrentMap<String, UserSession> sessions = new ConcurrentHashMap<>(); private static Logger logger = LoggerFactory.getLogger(GMessageListener.class) ; private String username ; @OnOpen public void onOpen(Session session, EndpointConfig config, @PathParam("username") String username){ UserSession userSession = new UserSession(session.getId(), username, session) ; this.username = username ; sessions.put(username, userSession) ; logger.info("【{}】用戶進入, 當(dāng)前連接數(shù):{}", username, sessions.size()) ; } @OnClose public void onClose(Session session, CloseReason reason){ UserSession userSession = sessions.remove(this.username) ; if (userSession != null) { logger.info("用戶【{}】, 斷開連接, 當(dāng)前連接數(shù):{}", username, sessions.size()) ; } } @OnMessage public void pongMessage(Session session, PongMessage message) { ByteBuffer buffer = message.getApplicationData() ; logger.debug("接受到Pong幀【這是由瀏覽器發(fā)送】:" + buffer.toString()); } @OnMessage public void onMessage(Session session, AbstractMessage message) { if (message instanceof PingMessage) { logger.debug("這里是ping消息"); return ; } if (message instanceof PersonMessage) { PersonMessage personMessage = (PersonMessage) message ; if (this.username.equals(personMessage.getToName())) { logger.info("【{}】收到消息:{}", this.username, personMessage.getContent()); } else { UserSession userSession = sessions.get(personMessage.getToName()) ; if (userSession != null) { try { userSession.getSession().getAsyncRemote().sendText(new ObjectMapper().writeValueAsString(message)) ; } catch (JsonProcessingException e) { e.printStackTrace(); } } } return ; } if (message instanceof SystemMessage) { logger.info("接受到消息類型為【系統(tǒng)消息】") ; return ; } } @OnError public void onError(Session session, Throwable error) { logger.error(error.getMessage()) ; } }
WsMessageEncoder.java類
該類的主要作用是,當(dāng)發(fā)送的消息是對象時,該如何轉(zhuǎn)換
public class WsMessageEncoder implements Encoder.Text<AbstractMessage> { private static Logger logger = LoggerFactory.getLogger(WsMessageDecoder.class) ; @Override public void init(EndpointConfig endpointConfig) { } @Override public void destroy() { } @Override public String encode(AbstractMessage tm) throws EncodeException { String message = null ; try { message = new ObjectMapper().writeValueAsString(tm); } catch (JsonProcessingException e) { logger.error("JSON處理錯誤:{}", e) ; } return message; } }
WsMessageDecoder.java類
該類的作用是,當(dāng)接收到消息時如何轉(zhuǎn)換成對象。
public class WsMessageDecoder implements Decoder.Text<AbstractMessage> { private static Logger logger = LoggerFactory.getLogger(WsMessageDecoder.class) ; private static Set<String> msgTypes = new HashSet<>() ; static { msgTypes.add(MessageType.PING.getType()) ; msgTypes.add(MessageType.SYSTEM.getType()) ; msgTypes.add(MessageType.PERSON.getType()) ; } @Override @SuppressWarnings("unchecked") public AbstractMessage decode(String s) throws DecodeException { AbstractMessage message = null ; try { ObjectMapper mapper = new ObjectMapper() ; Map<String,String> map = mapper.readValue(s, Map.class) ; String type = map.get("type") ; switch(type) { case "0000": message = mapper.readValue(s, SystemMessage.class) ; break; case "0001": message = mapper.readValue(s, PingMessage.class) ; break; case "2001": message = mapper.readValue(s, PersonMessage.class) ; break; } } catch (JsonProcessingException e) { logger.error("JSON處理錯誤:{}", e) ; } return message ; } // 該方法判斷消息是否可以被解碼(轉(zhuǎn)換) @Override @SuppressWarnings("unchecked") public boolean willDecode(String s) { Map<String, String> map = new HashMap<>() ; try { map = new ObjectMapper().readValue(s, Map.class); } catch (JsonProcessingException e) { e.printStackTrace(); } logger.debug("檢查消息:【" + s + "】是否可以解碼") ; String type = map.get("type") ; if (StringUtils.isEmpty(type) || !msgTypes.contains(type)) { return false ; } return true ; } @Override public void init(EndpointConfig endpointConfig) { } @Override public void destroy() { } }
MessageConfigurator.java類
該類的作用是配置服務(wù)端點,比如配置握手信息
public class MessageConfigurator extends ServerEndpointConfig.Configurator { private static Logger logger = LoggerFactory.getLogger(MessageConfigurator.class) ; @Override public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { logger.debug("握手請求頭信息:" + request.getHeaders()); logger.debug("握手響應(yīng)頭信息:" + response.getHeaders()); super.modifyHandshake(sec, request, response); } }
WebSocke配置類
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter (){ return new ServerEndpointExporter(); } }
當(dāng)以jar包形式運行時需要配置該bean,暴露我們配置的@ServerEndpoint;當(dāng)我們以war獨立tomcat運行時不能配置該bean。
<!doctype html> <html> <head> <meta charset="UTF-8"> <meta name="Author" content=""> <meta name="Keywords" content=""> <meta name="Description" content=""> <script src="g-messages.js?v=1"></script> <title>WebSocket</title> <style type="text/css"> </style> <script> let gm = null ; let username = null ; function ListenerMsg({url, protocols = ['gmsg'], options = {}}) { if (!url){ throw new Error("未知服務(wù)地址") ; } gm = new window.__GM({ url: url, protocols: protocols }) ; gm.open(options) ; } ListenerMsg.init = (user) => { if (!user) { alert("未知的當(dāng)前登錄人") ; return ; } let url = `ws://localhost:8080/message/${user}` ; let msg = document.querySelector("#msg") ListenerMsg({url, options: { onmessage (e) { let data = JSON.parse(e.data) ; let li = document.createElement("li") ; li.innerHTML = "【" + data.fromName + "】對你說:" + data.content ; msg.appendChild(li) ; } }}) ; } function enter() { username = document.querySelector("#nick").value ; ListenerMsg.init(username) ; document.querySelector("#chat").style.display = "block" ; document.querySelector("#enter").style.display = "none" ; document.querySelector("#cu").innerText = username ; } function send() { let a = document.querySelector("#toname") ; let b = document.querySelector("#content") ; let toName = a.value ; let content = b.value ; gm.sendMessage({type: "2001", content, fromName: username, toName}) ; a.value = '' ; b.value = '' ; } </script> </head> <body> <div id="enter"> <input id="nick"/><button type="button" onclick="enter()">進入</button> </div> <hr/> <div id="chat" style="display:none;"> 當(dāng)前用戶:<b id="cu"></b><br/> 用戶:<input id="toname" name="toname"/><br/><br/> 內(nèi)容:<textarea id="content" rows="3" cols="22"></textarea><br/> <button type="button" onclick="send()">發(fā)送</button> </div> <div> <ul id="msg"> </ul> </div> </body> </html>
到此所有的代碼完畢,接下來測試
打開兩個標(biāo)簽頁,以不同的用戶進入。
輸入對方用戶名發(fā)送消息
看完上述內(nèi)容,你們對SpringBoot中怎么利用WebSocket實現(xiàn)即時消息有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。
網(wǎng)站名稱:SpringBoot中怎么利用WebSocket實現(xiàn)即時消息
網(wǎng)頁網(wǎng)址:http://jinyejixie.com/article22/ijcocc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、網(wǎng)站收錄、定制開發(fā)、響應(yīng)式網(wǎng)站、網(wǎng)站設(shè)計、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)