spring整合socketio一對一實時聊天
阿新 • • 發佈:2019-10-10
第一步:pom.xml新增socketio依賴
<dependency> <groupId>com.corundumstudio.socketio</groupId> <artifactId>netty-socketio</artifactId> <version>1.7.11</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
值得提醒的是,當專案啟動netty類錯誤時,有可能是引入的版本問題,最好是最新版本
第二步:新增host和埠配置檔案(application.properties)
socketio.host=10.101.67.26 socketio.port=5380
值得說明的是,host也可以是localhost或者127.0.0.1,但是當在伺服器部署時,host不能是公網ip,必須是該部署的伺服器內網ip,否則socketio服務會繫結失敗
第三步:專案啟動類新增socketio服務啟動
package com.web; import com.corundumstudio.socketio.SocketIOServer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application implements CommandLineRunner { @Autowired private SocketIOServer socketIOServer; public static void main(String[] args) { System.out.println("進入了Application方法"); SpringApplication.run(Application.class, args); } @Override public void run(String... args) throws Exception { socketIOServer.start();//啟動 } }
第四步:新建連線、埠、傳送訊息處理類
package com.web.service.socket; import com.corundumstudio.socketio.SocketIOClient; import com.corundumstudio.socketio.annotation.OnConnect; import com.corundumstudio.socketio.annotation.OnDisconnect; import com.web.entity.cus.CusMessageDetail; import com.web.service.cus.CusMessageDetailService; import com.web.utils.ApplicationContextProvider; import com.web.utils.DateUtils; import com.web.utils.MyUtils; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @Component public class LoginHandler { private static Map<String, SocketIOClient> clientMap = new ConcurrentHashMap<>(); //客戶端連上socket伺服器時執行此事件 @OnConnect public void onConnect(SocketIOClient client) { String messagerelateid = client.getHandshakeData().getSingleUrlParam("messagerelateid"); String fromuserid = client.getHandshakeData().getSingleUrlParam("fromuserid"); String touserid = client.getHandshakeData().getSingleUrlParam("touserid"); if (messagerelateid != null) { clientMap.put(messagerelateid+"&"+fromuserid, client);//這裡使用messagerelateid和fromuserid進行拼湊 } //TODO 根據messagerelateid、fromuserid、touserid查出聊天記錄(可能需要弄成介面形式) } //客戶端斷開socket伺服器時執行此事件 @OnDisconnect public void onDisconnect(SocketIOClient client) { String messagerelateid = client.getHandshakeData().getSingleUrlParam("messagerelateid"); String fromuserid = client.getHandshakeData().getSingleUrlParam("fromuserid"); String touserid = client.getHandshakeData().getSingleUrlParam("touserid"); if (messagerelateid != null) { clientMap.remove(messagerelateid+"&"+fromuserid, client); client.disconnect(); } } //伺服器向客戶端傳送事件 public CusMessageDetail pushMessage(String messagerelateid,String fromuserid,String touserid,String content) { CusMessageDetailService cusMessageDetailService = (CusMessageDetailService) ApplicationContextProvider.getBean("cusMessageDetailService"); if (!StringUtils.isEmpty(messagerelateid)) { SocketIOClient client = clientMap.get(messagerelateid+"&"+touserid);//因為是發給對方,所以這裡使用messagerelateid和touserid進行拼湊,拿到對方的socket CusMessageDetail cusMessageDetail = new CusMessageDetail(); cusMessageDetail.setContent(content); cusMessageDetail.setCreateby(fromuserid); cusMessageDetail.setCreatetime(DateUtils.strDate2()); cusMessageDetail.setFromuserid(fromuserid); cusMessageDetail.setId(MyUtils.subUUID(UUID.randomUUID().toString())); cusMessageDetail.setIsdelete(0); cusMessageDetail.setMessagerelateid(messagerelateid); cusMessageDetail.setTouserid(touserid); cusMessageDetail.setUpdateby(fromuserid); cusMessageDetail.setUpdatetime(DateUtils.strDate2()); cusMessageDetailService.insert(cusMessageDetail);//插入 if (client != null) { //如果線上,則直接傳送 client.sendEvent("pushMsg", cusMessageDetail.getContent());//傳送訊息 return cusMessageDetail; }else{ //對方離線,那麼也進行返回 return cusMessageDetail; } } return null; } }
值得說明的是,伺服器向客戶端傳送事件方法有我本人自己的一些邏輯處理,大家可以自行處理即可。
第五步:建立前端頁面進行測試
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>NETTY SOCKET.IO DEMO</title> <base> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/socket.io/2.1.1/socket.io.js"></script> <style> body { padding: 20px; } #console { height: 450px; overflow: auto; } .username-msg { color: orange; } .connect-msg { color: green; } .disconnect-msg { color: red; } </style> </head> <body> <div id="console" class="well"></div> </body> <script type="text/javascript"> var socket; connect(); function connect() { var opts = { query: 'messagerelateid=a387b209c37948fbb47f58a9dcd53881&fromuserid=d138b75e81e74c4082295175ad605744&touserid=a138b75e81e74c4082295175ad605744' }; socket = io.connect('http://10.101.67.26:5380', opts); socket.on('connect', function () { console.log("連線成功"); serverOutput('<span class="connect-msg">連線成功</span>'); }); socket.on('pushMsg', function (data) { console.info(data); output('<span class="username-msg">' + data + ' </span>'); }); socket.on('disconnect', function () { serverOutput('<span class="disconnect-msg">' + '已下線! </span>'); }); } function output(message) { var element = $("<div>" + " " + message + "</div>"); $('#console').prepend(element); } function serverOutput(message) { var element = $("<div>" + message + "</div>"); $('#console').prepend(element); } </script> </html>
說明:socket = io.connect('http://10.101.67.26:5380', opts); 這裡的ip即為伺服器配置檔案的host,但是如果伺服器繫結的是內網的ip,那麼頁面這裡必須是公網的ip方可連線上
一對一發送訊息時,傳送的是對方的client中,自己這邊是收不到的,所以傳送成功後需要把傳送的訊息內容追加的訊息列表後面即可。
擴充套件:socketio如何實現群聊?
提示:可以建立一個群組,群組繫結多個人該群的一位client值,當群發時,迴圈發給該群所掛載的所有使用者client,如果有使用者線上,則是立即可以收到訊息,不線上,下次連線時通過獲取歷史訊息