Springboot 整合 Socket 实战案例 ,实现 单点发送、广播群发,1对1,1对多_springboot socket

import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.socket.mysocket.util.SocketUtil;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**

  • @Author: JCccc
  • @Description:
  • @Date: 2022/6/23 21:21
    */
    @Component
    public class MySocketHandler {
    private final Logger log = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private SocketIOServer socketIoServer;
    @PostConstruct
    private void start(){
    try {
    socketIoServer.start();
    }catch (Exception e){
    e.printStackTrace();
    }
    }
    @PreDestroy
    private void destroy(){
    try {
    socketIoServer.stop();
    }catch (Exception e){
    e.printStackTrace();
    }
    }
    @OnConnect
    public void connect(SocketIOClient client) {
    String userFlag = client.getHandshakeData().getSingleUrlParam(“userFlag”);
    SocketUtil.connectMap.put(userFlag, client);
    log.info("客户端userFlag: "+ userFlag+ “已连接”);
    }
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
    String userFlag = client.getHandshakeData().getSingleUrlParam(“userFlag”);
    log.info(“客户端userFlag:” + userFlag + “断开连接”);
    SocketUtil.connectMap.remove(userFlag, client);
    }
    }

 


代码简析:  
![](https://img-blog.csdnimg.cn/aa0e9f47075644c9ac07fbe6ebdf4768.png)


 


####  ⑥ 封装的socket 小函数


SocketUtil.java



import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.annotation.OnEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**

  • @Author: JCccc

  • @Description:

  • @Date: 2022/6/23 21:28
    */
    @Component
    public class SocketUtil {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    //暂且把用户&客户端信息存在缓存
    public static ConcurrentMap<String, SocketIOClient> connectMap = new ConcurrentHashMap<>();

    @OnEvent(value = “CHANNEL_SYSTEM”)
    public void systemDataListener(String receiveMsg) {
    if (!StringUtils.hasLength(receiveMsg)){
    return;
    }
    JSONObject msgObject = (JSONObject) JSON.parse(receiveMsg);
    String userFlag = String.valueOf(msgObject.get(“from”));
    String content = String.valueOf(msgObject.get(“content”));
    log.info(“收到用户 : {} 推送到系统频道的一条消息 :{}”,userFlag,content );
    }

    public void sendToAll(Map<String, Object> msg,String sendChannel) {
    if (connectMap.isEmpty()){
    return;
    }
    //给在这个频道的每个客户端发消息
    for (Map.Entry<String, SocketIOClient> entry : connectMap.entrySet()) {
    entry.getValue().sendEvent(sendChannel, msg);
    }
    }

    public void sendToOne(String userFlag, Map<String, Object> msg,String sendChannel) {
    //拿出某个客户端信息
    SocketIOClient socketClient = getSocketClient(userFlag);
    if (Objects.nonNull(socketClient) ){
    //单独给他发消息
    socketClient.sendEvent(sendChannel,msg);
    }
    }

    /**

    • 识别出客户端
    • @param userFlag
    • @return
      */
      public SocketIOClient getSocketClient(String userFlag){
      SocketIOClient client = null;
      if (StringUtils.hasLength(userFlag) && !connectMap.isEmpty()){
      for (String key : connectMap.keySet()) {
      if (userFlag.equals(key)){
      client = connectMap.get(key);
      }
      }
      }
      return client;
      }

}


代码简析:  
![](https://img-blog.csdnimg.cn/bd5a673046a24052a1f7dd6214a5d992.jpeg)


 


#### ⑦写1个接口,模拟场景,前端页面调用后端接口,做消息推送


TestController.java



import com.socket.mysocket.dto.MyMessage;
import com.socket.mysocket.util.SocketUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

/**

  • @Author: JCccc

  • @Description:

  • @Date: 2022/06/13 21:50
    */
    @RestController
    public class TestController {
    public final static String SEND_TYPE_ALL = “ALL”;
    public final static String SEND_TYPE_ALONE = “ALONE”;
    @Autowired
    SocketUtil socketUtil;

    @PostMapping(“/testSendMsg”)
    public String testSendMsg(@RequestBody MyMessage myMessage){
    Map<String, Object> map = new HashMap<>();
    map.put(“msg”,myMessage.getContent());

     //群发
     if (SEND_TYPE_ALL.equals(myMessage.getType())){
         socketUtil.sendToAll( map,myMessage.getChannel());
         return "success";
     }
     //指定单人
     if (SEND_TYPE_ALONE.equals(myMessage.getType())){
         socketUtil.sendToOne(myMessage.getTo(), map, myMessage.getChannel());
         return "success";
     }
    
     return "fail";
    

    }
    }


代码简析:  
![](https://img-blog.csdnimg.cn/bd942945e0b349b9bf5a026e2a429aef.jpeg)


 



好了,7步了。一切已经就绪了。


###  前端简单页面



接下来搞点前端HTML页面, 玩一玩看看效果:


  
![](https://img-blog.csdnimg.cn/12dca7a95df140b483889dca8884767a.png)


 


第一个页面:  
 TestClientStudentJC.html



我要连SOCKET
给系统推消息 发送
```

代码简析:

第二个页面,跟第一个基本一样,改一下用户唯一标识:

TestClientStudentPU.html

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>我要连SOCKET</title>
    <base>
    <script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
    <style>
        body {
            padding: 20px;
        }
        #console {
            height: 450px;
            overflow: auto;
        }
        .msg-color {
            color: green;
        }
    </style>
</head>

<body>
<div id="console" class="well"></div>


<div id="conversationDiv">
    <labal>给系统推消息</labal>
    <input type="text" id="content"/>
    <button id="btnSendToSystem" onclick="sendSys();">发送</button>
</div>


</body>
<script type="text/javascript">
    var socket;
    connect();

    function connect() {
        var userFlag = 'user_PU';
        var opts = {
            query: 'userFlag=' + userFlag
        };
        socket = io.connect('http://localhost:8503', opts);
        socket.on('connect', function () {
            console.log("连接成功");
            output('当前用户是:' + userFlag );
            output('<span class="msg-color">连接成功了。</span>');
        });
        socket.on('disconnect', function () {
            output('<span class="msg-color">下线了。 </span>');
        });

        socket.on('CHANNEL_STUDENT', function (data) {
            let msg= JSON.stringify(data)
            output('收到学生频道消息了:' + msg );
            console.log(data);

        });
        socket.on('CHANNEL_SYSTEM', function (data) {
            let msg= JSON.stringify(data)
            output('收到系统全局消息了:' + msg );
            console.log(data);

        });

    }

    function sendSys() {
        console.log('发送消息给服务端');
        var content = document.getElementById('content').value;

        socket.emit('CHANNEL_SYSTEM',JSON.stringify({
            'content': content,
            'from': 'user_PU'
        }));

    }
    function output(message) {
        var element = $("<div>" + message + "</div>");
        $('#console').prepend(element);
    }

</script>
</html>

OK,把项目跑起来,开始玩。

直接访问客户端页面 模拟学生 JC连接socket:
http://127.0.0.1:8089/TestClientStudentJC.html

可以看到服务端有监测到:

这里监测的:

先试试客户端给系统推消息先:

可以看到服务端成功收到消息:

这种方式,其实是因为服务监听了相关的频道:

前端使用JS推到这个系统频道:

ps: 其实前端给服务端推消息,其实调用接口就可以。

OK,进入核心应用场景1:

群发,所有人都能收到    系统给连上的客户端都推送消息

{

“type”: “ALL”,

“content”:“你们好,这是一条广播消息,全部人都能收到”,

“channel”:“CHANNEL_SYSTEM”

}

看看效果:

一线互联网大厂Java核心面试题库

image

正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!

.cn/eec7593b232e41c5805e63d5ac5a338b.png)

{

“type”: “ALL”,

“content”:“你们好,这是一条广播消息,全部人都能收到”,

“channel”:“CHANNEL_SYSTEM”

}

看看效果:

一线互联网大厂Java核心面试题库

[外链图片转存中…(img-XblIeQ7j-1714459741673)]

正逢面试跳槽季,给大家整理了大厂问到的一些面试真题,由于文章长度限制,只给大家展示了部分题目,更多Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等已整理上传,感兴趣的朋友可以看看支持一波!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 13
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值