看到別人的系統或者app都有聊天功能,大家有沒有想過自己的系統也集成進去呢?現在來揭曉!
第一步: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,如果有用戶在線,則是立即可以收到消息,不在線,下次連接時通過獲取歷史消息獲取消息即可。
在此接近尾聲,也希望這篇文章對你有所收穫,下次再見!