当前位置:   article > 正文

[简单入门+应用]WebSocket双工通信(收发客户端数据+向指定客户端发送数据+主动断开连接)的实现(SpringBoot版本)_springboot+somp+websocke连接断开

springboot+somp+websocke连接断开

WebSocket简单来讲就是在客户端与服务端之间建立一个长连接,实现端对端的直接通信,连接保持期间可以双发互相发送数据(双工通信)
WebSocket测试网站:http://www.websocket-test.com/

一、基本使用

下面三步照着做就可以了,主要需要自己根据要求定制的再第三步
第一步:引入WebSocket依赖

<!--websocket-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

第二步:配置WebSocketConfig

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

第三步:创建WebSocketServer
主要需要自己根据项目修改的内容,其他基本不需要修改:
①websocket接口@ServerEndpoint(value = “/ws/{userId}”)和对应的路径参数的使用
②onMessage中的接收客户端请求信息的内容

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.len.bmbhome.client.*;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.bmbhome.service.UserDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
//自行设置连接接口的url,下方接收的参数userId也可以自行修改
@ServerEndpoint(value = "/ws/{userId}")
@Component
public class WebSocketServer {

    private Long userId;

    private Session session;

    //记录所有的WebSocketServer
    private static CopyOnWriteArrayList<WebSocketServer> webSocketSet = new CopyOnWriteArrayList<>();


    public Session getSession() {
        return this.session;
    }

    public Long getUserId(){
        return this.userId;
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") Long userId) {
        log.info("有连接加入:" + userId);
        this.userId = userId;
        this.session = session;
        webSocketSet.add(this);
    }

    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            log.info("来自客户端的消息:{}", message);
            //添加一些自己接收到客户端发送的数据的一些处理
        } catch (Exception e) {
            log.error("接收用户消息出错了:", e);
        }
    }

     /**
     *  连接关闭时调用的方法
     */
    @OnClose
    public void OnClose() {
        log.info("退出用户userId" + this.userId);
        webSocketSet.remove(this);
    }

    /**
     *  向指定的session发送数据
     */
    private void sendMessage(Session session, String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("消息发送失败", e);
        }
    }
    
    /**
     * 群发消息,即对每一个session都进行发送
     */
    private void sendMessageToAll(String message) throws IOException {
        for (WebSocketServer webSocketServer : webSocketSet) {
            webSocketServer.getSession().getBasicRemote().sendText(message);
        }
    }
    
    /**
     * 向指定userId用户发送信息
     * 利用遍历的方法,判断userId是否匹配
     */
    private void sendMessgaeByUserId(Long userId,String message) throws IOException {
        for (WebSocketServer webSocketServer : webSocketSet) {
            if(webSocketServer.getUserId() == userId){
                webSocketServer.getSession().getBasicRemote().sendText(message);
            }
        }
    }
    
    /**
     * 主动断开连接
     */
    public void close() throws IOException {
        //主动断开连接
        this.session.close();
        this.onClose();
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119

补充:
①客户端也要通过实现websocket才能进行通信,而不是使用原始的http协议
②sendMessage可以发送map、collection等等数据,但是要通过先转json,再转string。
客户端接收到string后,转换为json
以发送Map数据为例
在这里插入图片描述

					Map<String,Object> map = new HashMap<>();
                    map.put("userName","lnz");
                    map.put("userId","199");
                    map.put("gsr","10");
                    sendMessage(this.session,JSONObject.toJSON(map).toString());
  • 1
  • 2
  • 3
  • 4
  • 5

二、实战案例

实例测试:
①服务端从客户端接收用户的各种健康数据(步数、皮肤电等等),并保存到数据库中
②服务端向客户端发送数据
传递JSON格式数据{”type":“xx”,xxx},利用onMessage中switch来判断type进行接收还是发送数据
type = 2、3时,进行保存数据到服务器
type=100时,进行服务器向客户端发送数据

package org.bmbhome.config;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.len.bmbhome.client.*;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.bmbhome.service.UserDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

@Slf4j
@ServerEndpoint(value = "/ws/{userId}")
@Component
public class WebSocketServer {

    private Long userId;

    private Session session;

    //记录所有的WebSocketServer
    // 因为同一个userId可能有多个接入所以不可以使用Map<userId,WebSocketServer>或Map<userId,Session>这样的容器
    //这边可以自行设计存储的容器,但注意要为static
    private static CopyOnWriteArrayList<WebSocketServer> webSocketSet = new CopyOnWriteArrayList<>();

    private static UserDataService userDataService;



    @Autowired
    public void setUserDataService(UserDataService userDataService) {
        WebSocketServer.userDataService = userDataService;
    }

    public Session getSession() {
        return this.session;
    }

    public Long getUserId(){
        return this.userId;
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") Long userId) {
        log.info("有连接加入:" + userId);
        this.userId = userId;
        this.session = session;
        webSocketSet.add(this);
    }

    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            log.info("来自客户端的消息:{}", message);
            int type = JSON.parseObject(message).getInteger("type");
            System.out.println(type);
            JSONObject jsonObject = JSONObject.parseObject(message);
            switch (type) {   
                /**
                 * 步数统计
                 * json格式: {"type":"2",data:"xxx"}
                 */
                case 2:
                    MessageDTO<StepDTO> stepDTOMessageDTO = new MessageDTO<>();
                    stepDTOMessageDTO.setType(jsonObject.getInteger("type"));
                    StepDTO stepDTO = new StepDTO();
                    stepDTO.setCount(jsonObject.getLong("data"));
                    stepDTOMessageDTO.setData(stepDTO);

                    System.out.println(stepDTOMessageDTO.getType());
                    System.out.println(stepDTOMessageDTO.getData());
                    userDataService.saveUserStep(userId, stepDTOMessageDTO);
                    break;
                /**
                 * 皮肤电数据信息
                 * json格式: {"type":"3","data":"xxx"}
                 */
                case 3:
                    GsrDTO gsrDTO = new GsrDTO();
                    gsrDTO.setSensorValue(jsonObject.getInteger("data"));
                    userDataService.saveUserGsr(userId, gsrDTO);
                    System.out.println(gsrDTO);
                    break;

                /**
                 * 用户请求数据
                 * 测试服务器向客户端发送数据
                 * json格式: {"type":"100"}
                 */
                case 100:
                    sendMessage(this.session,"恭喜你以及获得到数据");
                    sendMessgaeByUserId(3L,"3号你很容易被选中");
                    Map<String,Object> map = new HashMap<>();
                    map.put("userName","lnz");
                    map.put("userId","199");
                    map.put("gsr","10");
                    sendMessage(this.session,JSONObject.toJSON(map).toString());
                    break;
                default:
                    log.error("未知消息类型");
            }
        } catch (Exception e) {
            log.error("接收用户消息出错了:", e);
        }
    }


    @OnClose
    public void OnClose() {
        log.info("退出用户userId" + this.userId);
        webSocketSet.remove(this);
    }

    /**
     *  向指定的session发送数据
     */
    private void sendMessage(Session session, String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("消息发送失败", e);
        }
    }
    /**
     * 群发消息,即对每一个session都进行发送
     */
    private void sendMessageToAll(String message) throws IOException {
        for (WebSocketServer webSocketServer : webSocketSet) {
            webSocketServer.getSession().getBasicRemote().sendText(message);
        }
    }
    /**
     * 向指定userId用户发送信息
     * 利用遍历的方法
     */
    private void sendMessgaeByUserId(Long userId,String message) throws IOException {
        for (WebSocketServer webSocketServer : webSocketSet) {
            if(webSocketServer.getUserId() == userId){
                webSocketServer.getSession().getBasicRemote().sendText(message);
            }
        }
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164

请求服务器发送数据测试:
在这里插入图片描述
在这里插入图片描述
向服务器发送数据测试:
在这里插入图片描述
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/喵喵爱编程/article/detail/745507
推荐阅读
相关标签
  

闽ICP备14008679号