springboot整合websocket对多客户端实时数据分发

 项目git地址:https://github.com/Ray8080/RealData.git

一.maven依赖(boot版本2.0.4)

    <dependencies>
        <!-- springboot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--单元测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.28</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <!-- log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
    </dependencies>

 

 二.websocket配置bean

package com.zhourui.common.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;


@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

三.抽象session管理类

package com.zhourui.business.websocket.holder;

import com.alibaba.fastjson.JSON;

import javax.websocket.Session;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public abstract class SocketSessionManager {

    private ConcurrentHashMap<String, Session> sessions;


    public SocketSessionManager(){
        this.sessions = new ConcurrentHashMap<>();
    }


    public Set<String> getUserKeys(){
        return this.sessions.keySet();
    }

    /**
     * 用户上线
     * @param session
     */
    public void online(Session session){
        this.sessions.put(session.getId(),session);

    }

    /**
     * 用户下线
     * @param sessionId
     */
    public void offline(String sessionId){
        this.sessions.remove(sessionId);

    }

    /**
     * 获取session数
     */
    public int getSessionNum(){
        return this.sessions.size();
    }

    /**
     * 发送数据
     * @param sessionId
     * @param msg
     */
    public void sendData(String sessionId,Object msg){
        try {
            this.sessions.get(sessionId).getBasicRemote().sendText(JSON.toJSONString(msg));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

四.真正的session管理类

package com.zhourui.business.websocket.holder;

import org.apache.log4j.Logger;

public class RealDataSocketSessionManager extends SocketSessionManager {

    private static Logger log = Logger.getLogger(RealDataSocketSessionManager.class);

    private static RealDataSocketSessionManager manager = new RealDataSocketSessionManager();

    private RealDataSocketSessionManager(){
        super();
    }


    //单例模式,全局只产生一个 RealDataSocketSessionManager 实例
    public static RealDataSocketSessionManager getAlarmSocketSessionManager(){
        return manager;
    }

}

五.连接建立

package com.zhourui.business.websocket;


import com.zhourui.business.websocket.holder.RealDataSocketSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;


@ServerEndpoint("/real")
@Component
public class RealDataSocket {

    private static Logger log = LoggerFactory.getLogger(RealDataSocket.class);

    @OnOpen
    public void onOpen(Session session){
        RealDataSocketSessionManager.getAlarmSocketSessionManager().online(session);
        log.info("1个用户上线,一共"+(RealDataSocketSessionManager.getAlarmSocketSessionManager().getSessionNum())+"个用户在线");
        try {
            session.getBasicRemote().sendText("connect success..");
            //推送第一屏数据
            //session.getBasicRemote().sendText(JSON.toJSONString(RealTimeWarnProcesser.FIRST_BEAN));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @OnClose
    public void onClose(Session session){
        RealDataSocketSessionManager.getAlarmSocketSessionManager().offline(session.getId());
        log.info("1个用户下线,一共"+(RealDataSocketSessionManager.getAlarmSocketSessionManager().getSessionNum())+"个用户在线");
    }

    @OnMessage
    public void onMessage(String msg, Session session) {
        log.info("接收到的消息: msg={} ",msg);
        //msg应包含配置信息,模板ID或者配置的内容,然后根据session去更新模板,协议自定义
        if(msg != null) {
            try {

            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }


    @OnError
    public void onError(Session session, Throwable error){
        log.error(session.getId()+" error: "+error.getMessage());
    }
}

六.对建立连接的客户端实时推送数据

package com.zhourui.business.websocket.process;

import com.zhourui.business.websocket.holder.RealDataSocketSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Set;


public class RealTimeData {
    private static final Logger logger = LoggerFactory.getLogger(RealTimeData.class);
    private Thread daemon;
    private long index;

    //public static RealTimeWarnInfoBean FIRST_BEAN = new RealTimeWarnInfoBean();

    public void start() {
        daemon = new Thread(new Runnable() {


            @Override
            public void run() {

                while (true) {
                    try {
                       //这里可以自己去实现数据获取,封装,然后分发出去
                        Set<String> keys = RealDataSocketSessionManager.getAlarmSocketSessionManager().getUserKeys();
                        keys.stream().forEach(e -> RealDataSocketSessionManager.getAlarmSocketSessionManager()
                                .sendData(e, "实时数据"));
                        logger.info("发送成功msg==={}",keys);
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } catch (Exception e) {
                        logger.error("实时数据返回参数出错========={}" ,e);
                        e.printStackTrace();
                    }
                    try {
                        Thread.sleep(200);
                        logger.info("WebSocket线程存活.........");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }, "RealTimeDataProcesser");
        daemon.setDaemon(true);
        daemon.start();
    }
}

七.启动类开启数据分发线程

package com.zhourui;

import com.zhourui.business.websocket.process.RealTimeData;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = {"com.zhourui"})
public class StarterServer {



    public static void main(String[] args) {

        SpringApplication.run(StarterServer.class,args);
        try {
            Thread.sleep(1000);
            new RealTimeData().start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



}

八.前端页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>websocket</title>
</head>
<body>
    <p>websocket.....</p>
    <input id="text" type="text"/><br/>
    <button onclick="send()">send</button><br/>
    <button onclick="close()">close socket</button><br/>
    <p id="msg"></p>
    <div id="rsvMsg" >收到的信息:</div>
</body>
<script type="text/javascript">
    var websocket = null;

    if('WebSocket' in window){
        websocket = new WebSocket("ws://localhost:8888/real");
    }else{
        alert("浏览器不支持ws");
    }

    function setMessage2Html(message){
        document.getElementById('msg').innerHTML = message;
    }

    function setRcvMessage2Html(message){
        document.getElementById('rsvMsg').innerHTML += message+'<br/>';
    }

    websocket.onerror = function () {
        setMessage2Html("socket error");
    };

    websocket.onclose = function () {
        setMessage2Html("socket close");
    };

    websocket.onopen = function () {
        setMessage2Html("socket open");
    };

    websocket.onmessage = function (event) {
        setRcvMessage2Html(event.data);
    };

    window.onbeforeunload = function () {
        websocket.close();
    };

    function send() {
        var message = document.getElementById('text').value;
        websocket.send(message);
    }

    function close() {
        websocket.close();
    }
</script>
</html>

九.启动服务,打开页面测试

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值