springboot集成socketio實現一對一實時聊天

看到別人的系統或者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,如果有用戶在線,則是立即可以收到消息,不在線,下次連接時通過獲取歷史消息獲取消息即可。

 

在此接近尾聲,也希望這篇文章對你有所收穫,下次再見!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章