IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 简单实现-微服务项目Gateway转发websocket实现讨论组即时通讯 -> 正文阅读

[网络协议]简单实现-微服务项目Gateway转发websocket实现讨论组即时通讯

一、websocket实现讨论组即时聊天的功能

1、引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.0.4.RELEASE</version>
        </dependency>

2、写websocket配置类


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

/**
 * WebSocket 配置类
 * @Author Niki_Ya
 * @Date 2022/3/28 14:24
 */
@Configuration
public class WebSocketConfig {

    /**
     * 用于扫描和注册所有携带ServerEndPoint注解的实例 若部署到外部容器 则无需提供此类。
     *
     * @return org.springframework.web.socket.server.standard.ServerEndpointExporter
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

    /**
     * 在websocketServer服务注入讨论组服务接口,即时通讯的逻辑层
     *
     * @param dmtDiscussionService dmt讨论服务
     */
    @Autowired
    public void setMessageService(DmtDiscussionService dmtDiscussionService){
        WebSocketServer.dmtDiscussionService = dmtDiscussionService;
    }
}

3、websocket服务类实现


import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description
 * @Author Niki_Ya
 * @Date 2022/3/29 10:55
 */
@Slf4j
@ServerEndpoint(value = "/dmt/discussion/websocket")
@Component
@SuppressWarnings("all")
public class WebSocketServer {

    /**
     * 全部在线会话 PS: 基于场景考虑 这里使用线程安全的Map存储会话对象。
     */
    private static final Map<String, List<Client>> ONLINE_SESSIONS = new ConcurrentHashMap<>();

    //聊天逻辑层service
    public static DmtDiscussionService dmtDiscussionService;

    // 讨论组id
    private String discussionId;

    // 用户信息和session保存
    private Client client;

    /**
     * 连接建立成功调用的方法,初始化
     * 当客户端打开连接:1.添加会话对象
     */
    @OnOpen
    public void onOpen(Session session) {
        //初始化数据
        String[] split = session.getQueryString().split("&");
        HashMap<String, String> map = new HashMap<>();
        for (String s : split) {
            String[] strings = s.split("=");
            map.put(strings[0], strings[1]);
        }
        this.discussionId = map.get("discussionId");
        log.info("用户 {} 打开了{} 讨论组的WebSocket连接", map.get("staffNo"), discussionId);
        this.client = Client.builder()
                .staffId(map.get("staffId"))
                .staffNo(map.get("staffNo"))
                .staffName(map.get("staffName"))
                .session(session)
                .build();
        if (ONLINE_SESSIONS.containsKey(discussionId)) {
            List<Client> clients = ONLINE_SESSIONS.get(discussionId);
            clients.add(client);
            ONLINE_SESSIONS.put(discussionId, clients);
        } else {
            List<Client> clients = new ArrayList<>();
            clients.add(client);
            ONLINE_SESSIONS.put(discussionId, clients);
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        log.info("用户 {} 关闭了 {} 的WebSocket连接", client.getStaffNo(), discussionId);
        // 更新最后阅读时间
        DmtDiscussionDTO.UpdateLastReadTimeDTO dto = new DmtDiscussionDTO.UpdateLastReadTimeDTO();
        dto.setDiscussionId(discussionId);
        dto.setTime(new Date());
        dto.setStaffNo(client.getStaffNo());
        dmtDiscussionService.updateLastReadTime(dto);
        //将当前的session删除
        List<Client> clients = ONLINE_SESSIONS.get(discussionId);
        clients.remove(client);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message) {
        Long createTime = System.currentTimeMillis();
        //联调:从客户端传过来的数据是json数据,所以这里使用jackson进行转换为chatMsg对象 todo
//        DmtDiscussionDTO.Message message = JSON.parseObject(message, DmtDiscussionDTO.Message.class);
        //对chatMsg进行装箱
        DmtDiscussionDTO.MessageBaseDTO chatMsg = DmtDiscussionDTO.MessageBaseDTO.builder()
                .sendFromStaffId(client.getStaffId())
                .sendFromStaffNo(client.getStaffNo())
                .sendFromStaffName(client.getStaffName())
                .sendFromTime(createTime)
                .discussionId(discussionId)
                .content(message) // todo json数据
                .type(MessageType.TEXT.getCode()) // todo 先默认为0
                .build();
        //声明一个map,封装直接发送信息数据返回前端
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("staffName", chatMsg.getSendFromStaffName());
        resultMap.put("content", chatMsg.getContent());
        resultMap.put("sendTime", chatMsg.getSendFromTime());
        resultMap.put("type", chatMsg.getType());
        JSONObject json = new JSONObject(resultMap);
      //发送给接收者
        List<Client> clients = ONLINE_SESSIONS.get(discussionId);
        clients.forEach(e -> {
            //异步发送消息.
            e.getSession().getAsyncRemote().sendText(json.toString());
        });
        //保存聊天记录信息
        dmtDiscussionService.saveMessage(chatMsg);
    }

    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
        log.error("用户 {} 在{} 讨论组的通信发生异常 {}", client.getStaffNo(),discussionId, error.getMessage());
        throw new BaseException(error.getMessage());
    }
}

4、测试(测试网址:websocket在线测试

测试地址示例:ws://本地IP地址:端口号/dmt/discussion/websocket?discussionId=1507261309312798722&staffId=1&staffNo=ceshi001&staffName=ceshi001

?

?二、通过网关转发webSocket

1、引入依赖(不确定需不需要)

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

2、配置网关路由

spring.cloud.gateway.routes[0].id = notice-websocket
spring.cloud.gateway.routes[0].uri = lb:ws://notice-service
spring.cloud.gateway.routes[0].predicates[0] = Path=/notice/websocket/dmt/**
spring.cloud.gateway.routes[0].filters[0] = StripPrefix=2

3、测试?(测试网址:websocket在线测试

由于我的网关一定需要传token和timestamp才可以进入,大家可以按实际要求改地址

测试地址示例:ws://本地IP地址:端口号/notice/websocket/dmt/discussion/websocket?discussionId=1507261309312798722&staffId=1481884657660043266&staffNo=cshi019&staffName=cshi019&token=token内容&timeStamp=时间戳毫秒

?

?

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-04-04 12:47:24  更:2022-04-04 12:49:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:53:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码