简单实现-微服务项目Gateway转发websocket实现讨论组即时通讯

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

1、引入依赖

        
            org.springframework.boot
            spring-boot-starter-websocket
            2.0.4.RELEASE
        

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.JSON;
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> ONLINE_SESSIONS = new ConcurrentHashMap<>();

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

    // 讨论组id
    private String discussionId;

    private Client client;

    /**
     * 连接建立成功调用的方法,初始化
     * 当客户端打开连接:1.添加会话对象
     */
    @OnOpen
    public void onOpen(Session session) {
        //初始化数据
        String[] split = session.getQueryString().split("&");
        HashMap 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)
                .image(Optional.ofNullable(map.get("image")).orElse(""))
                .build();
        if (ONLINE_SESSIONS.containsKey(discussionId)) {
            List clients = ONLINE_SESSIONS.get(discussionId);
            clients.add(client);
            ONLINE_SESSIONS.put(discussionId, clients);
        } else {
            List 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 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 mes = 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(mes.getContent())
                .type(mes.getType())
                .fileType(mes.getFileType())
                .image(client.getImage())
                .build();
        //保存聊天记录信息
        DmtDiscussionMessage po = dmtDiscussionService.saveMessage(chatMsg);
        //声明一个map,封装直接发送信息数据返回前端
        Map resultMap = new HashMap<>();
        resultMap.put("id", po.getId());
        resultMap.put("staffNo", po.getSendFromStaffNo());
        resultMap.put("staffName", po.getSendFromStaffName());
        resultMap.put("content", po.getContent());
        resultMap.put("sendTime", po.getSendFromTime());
        resultMap.put("type", po.getType());
        resultMap.put("fileType", po.getFileType());
        resultMap.put("image", Optional.ofNullable(po.getImage()).orElse(""));
        JSONObject json = new JSONObject(resultMap);
        //发送给接收者
        List clients = ONLINE_SESSIONS.get(discussionId);
        clients.forEach(e -> {
            //异步发送消息.
            e.getSession().getAsyncRemote().sendText(json.toString());
        });
        // 发送有信息给其他在线人员
        ONLINE_SESSIONS.entrySet().stream().filter(key -> !key.getKey().equals(discussionId)).forEach(e -> {
            e.getValue().forEach(f -> {
                //异步发送消息.
                f.getSession().getAsyncRemote().sendText(discussionId);
            });
        });
    }

    /**
     * 发生错误时调用
     */
    @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

简单实现-微服务项目Gateway转发websocket实现讨论组即时通讯_第1张图片

 简单实现-微服务项目Gateway转发websocket实现讨论组即时通讯_第2张图片

 二、通过网关转发webSocket

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

        
            org.springframework.boot
            spring-boot-starter-websocket
            
                
                    org.springframework.boot
                    spring-boot-starter-web
                
            
        

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=时间戳毫秒

简单实现-微服务项目Gateway转发websocket实现讨论组即时通讯_第3张图片

 简单实现-微服务项目Gateway转发websocket实现讨论组即时通讯_第4张图片

你可能感兴趣的:(java,websocket,gateway)