SpringBoot+websocket實(shí)現(xiàn)消息對話功能
什么是websocket?
WebSocket是一種在Web應(yīng)用程序中實(shí)現(xiàn)實(shí)時雙向通信的技術(shù)。Web應(yīng)用程序通常是基于HTTP協(xié)議的,HTTP是一種請求/響應(yīng)式的協(xié)議,客戶端發(fā)起請求,服務(wù)器響應(yīng)請求并發(fā)送響應(yīng),客戶端收到響應(yīng)后關(guān)閉連接。這意味著,如果客戶端需要不斷地從服務(wù)器獲取更新,它必須定期發(fā)送請求以檢查更新,這將導(dǎo)致大量的網(wǎng)絡(luò)流量和不必要的服務(wù)器負(fù)載。
WebSocket通過在客戶端和服務(wù)器之間創(chuàng)建持久化連接,允許雙向?qū)崟r通信。這意味著服務(wù)器可以主動向客戶端推送更新,而不必等待客戶端不停地請求。WebSocket連接始于HTTP握手,然后升級到WebSocket協(xié)議。在升級過程中,客戶端和服務(wù)器之間的數(shù)據(jù)傳輸方式從HTTP變成了WebSocket協(xié)議,這樣可以降低傳輸數(shù)據(jù)的延遲和提高傳輸數(shù)據(jù)的可靠性。
在WebSocket協(xié)議中,數(shù)據(jù)是以幀的形式傳輸?shù)?,幀包括?shù)據(jù)頭和數(shù)據(jù)體兩個部分。數(shù)據(jù)頭指示數(shù)據(jù)類型,數(shù)據(jù)傳輸?shù)姆较虻刃畔?,?shù)據(jù)體則包括實(shí)際傳輸?shù)臄?shù)據(jù)。WebSocket支持文本類型和二進(jìn)制類型的數(shù)據(jù)。文本類型的數(shù)據(jù)使用UTF-8編碼,而二進(jìn)制類型的數(shù)據(jù)可以包括任何二進(jìn)制數(shù)據(jù),如圖像、音頻、視頻等。
WebSockets是非常適合實(shí)時通信的技術(shù)。它可以用于在線游戲、在線聊天、推送通知、實(shí)時監(jiān)控等,并且比傳統(tǒng)的輪詢技術(shù)更加高效和可靠。對于現(xiàn)代Web應(yīng)用程序而言,WebSockets已經(jīng)成為不可或缺的技術(shù)之一。
websocket和Socket區(qū)別
區(qū)別 | WebSocket | Socket |
---|---|---|
應(yīng)用層協(xié)議 | 基于HTTP協(xié)議,升級為WebSocket協(xié)議 | 沒有明確的應(yīng)用層協(xié)議,常用于傳輸TCP或UDP數(shù)據(jù) |
傳輸數(shù)據(jù)類型 | 支持文本和二進(jìn)制類型的數(shù)據(jù) | 通常用于傳輸二進(jìn)制數(shù)據(jù),如圖片、視頻等 |
客戶端和服務(wù)器通信 | 支持實(shí)時雙向通信 | 支持雙向通信,但通常需要進(jìn)行輪詢或長連接 |
傳輸效率 | 比傳統(tǒng)的輪詢技術(shù)更加高效和可靠,不會頻繁請求服務(wù)器 | 傳輸效率較低,需要進(jìn)行輪詢或者長連接來保持連接,會頻繁請求服務(wù)器 |
應(yīng)用場景 | 適用于實(shí)時通信,如在線游戲、在線聊天、推送通知、實(shí)時監(jiān)控等 | 適用于需要傳輸大量二進(jìn)制數(shù)據(jù)的場景,如文件傳輸、圖片處理等 |
代碼部分
引入maven依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
說明:默認(rèn)版本為1.5.10RELEASE,可自定義版本,加入“<version">"”標(biāo)簽即可
常量類
package com.dmsdbj.itoo.utils; public class Constant { //webSocket相關(guān)配置 //鏈接地址 public static String WEBSOCKETPATHPERFIX = "/ws-push"; public static String WEBSOCKETPATH = "/endpointWisely"; //消息代理路徑 public static String WEBSOCKETBROADCASTPATH = "/topic"; //前端發(fā)送給服務(wù)端請求地址 public static final String FORETOSERVERPATH = "/welcome"; //服務(wù)端生產(chǎn)地址,客戶端訂閱此地址以接收服務(wù)端生產(chǎn)的消息 public static final String PRODUCERPATH = "/topic/getResponse"; //點(diǎn)對點(diǎn)消息推送地址前綴 public static final String P2PPUSHBASEPATH = "/user"; //點(diǎn)對點(diǎn)消息推送地址后綴,最后的地址為/user/用戶識別碼/msg public static final String P2PPUSHPATH = "/msg"; }
接收前端消息實(shí)體
package com.dmsdbj.itoo.vo; public class WiselyMessage { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
后臺發(fā)送消息實(shí)體
package com.dmsdbj.itoo.vo; public class WiselyResponse { private String responseMessage; public WiselyResponse(String responseMessage){ this.responseMessage = responseMessage; } public String getResponseMessage() { return responseMessage; } public void setResponseMessage(String responseMessage) { this.responseMessage = responseMessage; } }
配置websocket
package com.dmsdbj.itoo.config; import com.dmsdbj.itoo.utils.Constant; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; @Configuration // @EnableWebSocketMessageBroker注解用于開啟使用STOMP協(xié)議來傳輸基于代理(MessageBroker)的消息,這時候控制器(controller) // 開始支持@MessageMapping,就像是使用@requestMapping一樣。 @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) { //注冊一個Stomp的節(jié)點(diǎn)(endpoint),并指定使用SockJS協(xié)議。 stompEndpointRegistry.addEndpoint(Constant.WEBSOCKETPATH).withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { //服務(wù)端發(fā)送消息給客戶端的域,多個用逗號隔開 registry.enableSimpleBroker(Constant.WEBSOCKETBROADCASTPATH, Constant.P2PPUSHBASEPATH); //定義一對一推送的時候前綴 registry.setUserDestinationPrefix(Constant.P2PPUSHBASEPATH); //定義websoket前綴 registry.setApplicationDestinationPrefixes(Constant.WEBSOCKETPATHPERFIX); } }
采用JPA方法進(jìn)行操作數(shù)據(jù)庫DAO層
package com.dmsdbj.itoo.repository; import com.dmsdbj.itoo.entity.TbUser; import org.springframework.data.jpa.repository.JpaRepository; public interface TbUseRepository extends JpaRepository<TbUser,Long> {}
sql語句
CREATE TABLE `tb_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(50) DEFAULT NULL COMMENT '用戶名', `password` varchar(32) DEFAULT NULL COMMENT '密碼,加密存儲', `phone` varchar(20) DEFAULT NULL COMMENT '注冊手機(jī)號', `email` varchar(50) DEFAULT NULL COMMENT '注冊郵箱', `created` datetime DEFAULT NULL, `updated` datetime DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) USING BTREE, UNIQUE KEY `phone` (`phone`) USING BTREE, UNIQUE KEY `email` (`email`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=18333611875 DEFAULT CHARSET=utf8 COMMENT='用戶表';
TbUser實(shí)體類
package com.dmsdbj.itoo.entity; import lombok.Data; import javax.persistence.Entity; import javax.persistence.Id; import java.io.Serializable; @Entity @Data public class TbUser implements Serializable { @Id private Long id; private String username; private String password; private String phone; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } }
Service實(shí)現(xiàn)類
@Service public class TbUseServiceImpl implements TbUseService { @Autowired TbUseRepository repository; /** * 從數(shù)據(jù)庫查詢用戶,給訂閱者發(fā)送消息 * @return */ @Override public List<Long> send2Users() { return repository.findAll().stream().map(s -> s.getId()).collect(Collectors.toList()); } }
Service接口類
public interface TbUseService { List<Long> send2Users(); }
Façade實(shí)現(xiàn)類
@Service public class TbUseFacadeImpl implements TbUseFacade { @Autowired TbUseService tbUseService; @Override public List<Long> send2Users() { return tbUseService.send2Users(); } }
Façade接口類
public interface TbUseFacade { List<Long> send2Users(); }
Controller類
@Controller public class SendInfoController { @Reference TbUseFacade tbUseFacade; @Autowired private SimpMessagingTemplate template; @Resource WebSocketService webSocketService; @MessageMapping(Constant.FORETOSERVERPATH)//@MessageMapping和@RequestMapping功能類似,用于設(shè)置URL映射地址,瀏覽器向服務(wù)器發(fā)起請求,需要通過該地址。 // @SendTo(Constant.PRODUCERPATH)//如果服務(wù)器接受到了消息,就會對訂閱了@SendTo括號中的地址傳送消息。 public WiselyResponse say(WiselyMessage message) throws Exception { List<Long> userId = tbUseFacade.send2Users(); userId.forEach(s->{ template.convertAndSendToUser(s.toString(),Constant.P2PPUSHPATH, new WiselyResponse(message.getName())); }); return null; } }
前端頁面
sendws.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>Spring Boot+WebSocket+廣播式</title> </head> <body onload="disconnect()"> <noscript><h2 style="color: #ff0000">貌似你的瀏覽器不支持websocket</h2></noscript> <div> <div> <button id="connect" onclick="connect();">連接</button> <button id="disconnect" disabled="disabled" onclick="disconnect();">斷開連接</button> </div> <div id="conversationDiv"> <label>輸入要發(fā)送的消息</label><input type="text" id="name" /> <button id="sendName" onclick="sendName();">發(fā)送</button> <p id="response"></p> <p id="response1"></p> </div> </div> <!--<script th:src="@{sockjs.min.js}"></script> <script th:src="@{stomp.min.js}"></script> <script th:src="@{jquery.js}"></script>--> <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script> <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script th:inline="javascript"> var stompClient = null; //此值有服務(wù)端傳遞給前端,實(shí)現(xiàn)方式?jīng)]有要求 //var userId = [[${userId}]]; var userId = 'd892bf12bf7d11e793b69c5c8e6f60fb'; function setConnected(connected) { document.getElementById('connect').disabled = connected; document.getElementById('disconnect').disabled = !connected; document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden'; $('#response').html(); } function connect() { var socket = new SockJS('/endpointWisely'); //1連接SockJS的endpoint是“endpointWisely”,與后臺代碼中注冊的endpoint要一樣。 stompClient = Stomp.over(socket);//2創(chuàng)建STOMP協(xié)議的webSocket客戶端。 stompClient.connect({}, function(frame) {//3連接webSocket的服務(wù)端。 setConnected(true); console.log('開始進(jìn)行連接Connected: ' + frame); }); } function disconnect() { if (stompClient != null) { stompClient.disconnect(); } setConnected(false); console.log("Disconnected"); } function sendName() { var name = $('#name').val(); console.log(name); //通過stompClient.send()向地址為"/welcome"的服務(wù)器地址發(fā)起請求,與@MessageMapping里的地址對應(yīng)。因?yàn)槲覀兣渲昧藃egistry.setApplicationDestinationPrefixes(Constant.WEBSOCKETPATHPERFIX);所以需要增加前綴/ws-push/ stompClient.send("/ws-push/welcome", {}, JSON.stringify({ 'name': name })); } </script> </body> </html>
subws.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8" /> <title>Spring Boot+WebSocket+廣播式</title> </head> <body onload="disconnect()"> <noscript><h2 style="color: #ff0000">貌似你的瀏覽器不支持websocket</h2></noscript> <div> <div> <button id="connect" onclick="connect();">連接</button> <button id="disconnect" disabled="disabled" onclick="disconnect();">斷開連接</button> </div> <div id="conversationDiv"> <label>輸入你的userId</label><input type="text" id="userId" /> <button id="subMsg" onclick="subMsg();">訂閱消息</button> <p id="response"></p> <p id="response1"></p> </div> </div> <!--<script th:src="@{sockjs.min.js}"></script> <script th:src="@{stomp.min.js}"></script> <script th:src="@{jquery.js}"></script>--> <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script> <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script th:inline="javascript"> var stompClient = null; //此值有服務(wù)端傳遞給前端,實(shí)現(xiàn)方式?jīng)]有要求 //var userId = [[${userId}]]; function setConnected(connected) { document.getElementById('connect').disabled = connected; document.getElementById('disconnect').disabled = !connected; document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden'; $('#response').html(); } function connect() { var socket = new SockJS('/endpointWisely'); //1連接SockJS的endpoint是“endpointWisely”,與后臺代碼中注冊的endpoint要一樣。 stompClient = Stomp.over(socket);//2創(chuàng)建STOMP協(xié)議的webSocket客戶端。 stompClient.connect({}, function(frame) {//3連接webSocket的服務(wù)端。 setConnected(true); console.log('開始進(jìn)行連接Connected: ' + frame); //4通過stompClient.subscribe()訂閱服務(wù)器的目標(biāo)是'/topic/getResponse'發(fā)送過來的地址,與@SendTo中的地址對應(yīng)。 /*stompClient.subscribe('/topic/getResponse', function(respnose){ showResponse(JSON.parse(respnose.body).responseMessage); });*/ }); } function subMsg() { var userId = $('#userId').val(); console.log(userId); $.ajax({ type: 'GET', url: '/user/insert?userId='+userId, //data: userId, success: function (data) { console.log(data); //4通過stompClient.subscribe()訂閱服務(wù)器的目標(biāo)是'/user/' + userId + '/msg'接收一對一的推送消息,其中userId由服務(wù)端傳遞過來,用于表示唯一的用戶,通過此值將消息精確推送給一個用戶 stompClient.subscribe('/user/' + userId + '/msg', function(respnose){ console.log(respnose); showResponse1(JSON.parse(respnose.body).responseMessage); }); } }); } function disconnect() { if (stompClient != null) { stompClient.disconnect(); } setConnected(false); console.log("Disconnected"); } function showResponse1(message) { var response = $("#response1"); response.html(message); } </script> </body> </html>
實(shí)戰(zhàn)應(yīng)用
①啟動springboot-dubbo-service的主啟動類“SpringbootDubboServiceApplication”
②啟動springboot-dubbo-web的主啟動類“SpringbootDubboWebApplication”
③訪問
http://localhost:9000/sendws 發(fā)送消息方
http://localhost:9000/subws 訂閱消息方
④分別進(jìn)行連接操作
訂閱方輸入訂閱方的連接賬號userid,后期就可以接收發(fā)送端發(fā)送的消息
連接后的結(jié)果展示
以上就是SpringBoot+websocket實(shí)現(xiàn)消息對話功能的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot websocket消息對話的資料請關(guān)注腳本之家其它相關(guān)文章!
- Springboot實(shí)現(xiàn)人臉識別與WebSocket長連接的實(shí)現(xiàn)代碼
- SpringBoot+WebSocket實(shí)現(xiàn)IM及時通訊的代碼示例
- SpringBoot 整合WebSocket 前端 uniapp 訪問的詳細(xì)方法
- Springboot+WebSocket+Netty實(shí)現(xiàn)在線聊天/群聊系統(tǒng)
- SpringBoot集成WebSocket的兩種方式(JDK內(nèi)置版和Spring封裝版)
- SpringBoot中使用WebSocket的教程分享
- SpringBoot實(shí)現(xiàn)WebSocket全雙工通信的項(xiàng)目實(shí)踐
- 使用WebSocket+SpringBoot+Vue搭建簡易網(wǎng)頁聊天室的實(shí)現(xiàn)代碼
- SpringBoot整合WebSocket實(shí)現(xiàn)后端向前端發(fā)送消息的實(shí)例代碼
- Springboot+WebSocket實(shí)現(xiàn)在線聊天功能
- springboot中websocket簡單實(shí)現(xiàn)
- Spring Boot中的WebSocketMessageBrokerConfigurer接口使用
相關(guān)文章
SpringMVC開發(fā)restful API之用戶查詢代碼詳解
這篇文章主要介紹了SpringMVC開發(fā)restful API之用戶查詢代碼詳解,小編覺得挺不錯的,這里分享給大家,需要的朋友可以參考。下面隨小編一起看看吧。2017-11-11Mybatis?List列表In查詢實(shí)現(xiàn)的注意事項(xiàng)說明
這篇文章主要介紹了Mybatis?List列表In查詢實(shí)現(xiàn)的注意事項(xiàng)說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02Stream distinct根據(jù)list某個字段去重的解決方案
這篇文章主要介紹了Stream distinct根據(jù)list某個字段去重,stream的distinct去重方法,是根據(jù) Object.equals,和 Object.hashCode這兩個方法來判斷是否重復(fù)的,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05解決sharding JDBC 不支持批量導(dǎo)入問題
這篇文章主要介紹了解決sharding JDBC 不支持批量導(dǎo)入問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10Java實(shí)現(xiàn)PDF文件的分割與加密功能
這篇文章主要為大家分享了如何利用Java語言實(shí)現(xiàn)PDF文件的分割與加密以及封面圖的生成,文中的示例代碼簡潔易懂,感興趣的可以了解一下2022-04-04使用chatgpt實(shí)現(xiàn)微信聊天小程序的代碼示例
這篇文章主要介紹了使用chatgpt實(shí)現(xiàn)微信聊天小程序(秒回復(fù)),文中有詳細(xì)的代碼示例,對大家了解chatgpt聊天有一定的幫助,感興趣的同學(xué)可以參考閱讀2023-05-05