花了20分钟,给女朋友们写了一个web版群聊程序
WebSocket詳解
WebSocket 是 HTML5 開(kāi)始提供的一種在單個(gè) TCP 連接上進(jìn)行全雙工通訊的協(xié)議。WebSocket 使得客戶(hù)端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡(jiǎn)單,允許服務(wù)端主動(dòng)向客戶(hù)端推送數(shù)據(jù)。在 WebSocket API 中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸??梢哉f(shuō)WebSocket的出現(xiàn),使得瀏覽器具備了實(shí)時(shí)雙向通信的能力
在 WebSocket API 中,瀏覽器和服務(wù)器只需要做一個(gè)握手的動(dòng)作,然后,瀏覽器和服務(wù)器之間就形成了一條快速通道。兩者之間就直接可以數(shù)據(jù)互相傳送。
原來(lái)為了實(shí)現(xiàn)推送,很多公司用的是Ajax 輪詢(xún),即按照特定的時(shí)間間隔,由瀏覽器對(duì)服務(wù)器發(fā)出HTTP請(qǐng)求,然后由服務(wù)器返回最新的數(shù)據(jù)給客戶(hù)端的瀏覽器。這種傳統(tǒng)的模式帶來(lái)很明顯的缺點(diǎn),即瀏覽器需要不斷的向服務(wù)器發(fā)出請(qǐng)求,然而HTTP請(qǐng)求可能包含較長(zhǎng)的頭部,其中真正有效的數(shù)據(jù)可能只是很小的一部分,顯然這樣會(huì)浪費(fèi)很多的帶寬等資源。而websocket就可以解決這些問(wèn)題。
在Spring Boot中使用WebSocket
1.pom文件增加依賴(lài)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency>2.增加配置
@Configuration public?class?WebSocketConfig?{@Beanpublic?ServerEndpointExporter?serverEndpointExporter()?{return?new?ServerEndpointExporter();}}3.Java代碼
@Component @ServerEndpoint("/websocket") public?class?WebSocketServerController?{//?收到消息調(diào)用的方法@OnMessagepublic?void?onMessage(String?message)?{System.out.println("收到的消息為?"?+?message);}//?建立連接調(diào)用的方法@OnOpenpublic?void?onOpen()?{System.out.println("Client?connected");}//?關(guān)閉連接調(diào)用的方法@OnClosepublic?void?onClose()?{System.out.println("Connection?closed");}//?傳輸消息錯(cuò)誤調(diào)用的方法@OnErrorpublic?void?OnError(Throwable?error)?{System.out.println("Connection?error");} }4.前端代碼
<!DOCTYPE?html> <html> <head> <title>Testing?websockets</title> </head> <body><div><textarea?rows="3"?cols="20"?id="content"></textarea><br><input?type="submit"?value="Start"?onclick="start()"?/></div><div?id="messages"></div><script?type="text/javascript">var?webSocket?=?new?WebSocket('ws://localhost:8080/websocket');webSocket.onerror?=?function(event)?{onError(event)};webSocket.onopen?=?function(event)?{onOpen(event)};webSocket.onmessage?=?function(event)?{onMessage(event)};webSocket.onclose?=?function(event)?{onClose(event)};function?onMessage(event)?{document.getElementById('messages').innerHTML?+=?'<br?/>'?+?event.data;}function?onOpen(event)?{document.getElementById('messages').innerHTML?=?'Connection?established';}function?onError(event)?{alert(event);}function?onClose(event)?{alert(event);}function?start()?{var?text?=?document.getElementById('content').value;webSocket.send(text);}</script> </body> </html>所以你看websocket其實(shí)很簡(jiǎn)單,前后端各寫(xiě)4個(gè)事件方法就行了(當(dāng)然你也可以省略一些方法)
1.建立連接
2.收到消息
3.傳輸消息失敗
4.關(guān)閉連接
事件和具體會(huì)話(huà)關(guān)聯(lián)
如果事件想和具體會(huì)話(huà)關(guān)聯(lián),方法上只要加Session參數(shù)就行(4種事件類(lèi)型的方法上都可加)
舉個(gè)例子,直接將用戶(hù)發(fā)送給服務(wù)端的話(huà)再返回給客戶(hù)端
//?收到消息調(diào)用的方法 @OnMessage public?void?onMessage(Session?session,?String?message)?{try?{session.getBasicRemote().sendText(message);}?catch?(IOException?e)?{e.printStackTrace();} }傳遞參數(shù)
方法上加@PathParam參數(shù)即可
@Component @ServerEndpoint("/websocket/{sid}") public?class?WebSocketServerController @OnOpen public?void?onOpen(@PathParam("sid")?String?sid)?{System.out.println("Client?connected"); }實(shí)現(xiàn)一個(gè)在線(xiàn)群聊
后端接口
@Slf4j @Component @ServerEndpoint("/groupChat/{sid}/{username}") public?class?GroupChatController?{//?保存?組id->組成員?的映射關(guān)系private?static?ConcurrentHashMap<String,?List<Session>>?groupMemberInfoMap?=?new?ConcurrentHashMap<>();//?收到消息調(diào)用的方法,群成員發(fā)送消息@OnMessagepublic?void?onMessage(@PathParam("sid")?String?sid,@PathParam("username")?String?username,?String?message)?{List<Session>?sessionList?=?groupMemberInfoMap.get(sid);//?先一個(gè)群組內(nèi)的成員發(fā)送消息sessionList.forEach(item?->?{try?{String?text?=?username?+?":?"?+?message;item.getBasicRemote().sendText(text);}?catch?(IOException?e)?{e.printStackTrace();}});}//?建立連接調(diào)用的方法,群成員加入@OnOpenpublic?void?onOpen(Session?session,?@PathParam("sid")?String?sid)?{List<Session>?sessionList?=?groupMemberInfoMap.get(sid);if?(sessionList?==?null)?{sessionList?=?new?ArrayList<>();groupMemberInfoMap.put(sid,sessionList);}sessionList.add(session);log.info("Connection?connected");log.info("sid:?{},?sessionList?size:?{}",?sid,?sessionList.size());}//?關(guān)閉連接調(diào)用的方法,群成員退出@OnClosepublic?void?onClose(Session?session,?@PathParam("sid")?String?sid)?{List<Session>?sessionList?=?groupMemberInfoMap.get(sid);sessionList.remove(session);log.info("Connection?closed");log.info("sid:?{},?sessionList?size:?{}",?sid,?sessionList.size());}//?傳輸消息錯(cuò)誤調(diào)用的方法@OnErrorpublic?void?OnError(Throwable?error)?{log.info("Connection?error");} }前端代碼很簡(jiǎn)單,放github了
地址為:https://github.com/erlieStar/spring-boot-websocket
下面來(lái)看效果
注意先連接,后發(fā)送
在線(xiàn)開(kāi)房地址:
http://www.javashitang.com:8090/
有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號(hào)
好文章,我在看??
總結(jié)
以上是生活随笔為你收集整理的花了20分钟,给女朋友们写了一个web版群聊程序的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: NYOJ 636 世界末日
- 下一篇: 性能优越的轻量级日志收集工具,微软、亚马