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

本文介绍了如何使用Spring Boot的WebSocket实现讨论组即时聊天功能,包括配置、服务类实现以及连接的建立、关闭、消息处理等。此外,还展示了如何通过网关进行WebSocket请求的转发,确保消息的正确传递。测试部分提供了在线测试的URL示例。
摘要由CSDN通过智能技术生成

一、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.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<String, List<Client>> 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<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)
                .image(Optional.ofNullable(map.get("image")).orElse(""))
                .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 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<String, Object> 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<Client> 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

 

 二、通过网关转发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=时间戳毫秒

 

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当使用Spring Cloud Gateway转发WebSocket请求时,需要进行一些特殊配置。下面是一个简单的教程,演示了如何配置Spring Cloud Gateway转发WebSocket请求。 1. 首先,确保你已经有一个基本的Spring Cloud Gateway项目,并且已经添加了必要的依赖。 2. 在你的Gateway配置类中,添加一个`@Bean`方法来创建一个`WebSocketHandlerMapping`的实例。这个实例将用于将WebSocket请求转发到相应的目标服务。 ```java @Configuration public class GatewayConfig { @Bean public WebSocketHandlerMapping webSocketHandlerMapping() { Map<String, WebSocketHandler> handlerMap = new HashMap<>(); // 添加需要转发WebSocket处理器 handlerMap.put("/ws-endpoint", new MyWebSocketHandler()); // 创建WebSocketHandlerMapping实例,并设置handlerMap SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setOrder(Ordered.HIGHEST_PRECEDENCE); mapping.setUrlMap(handlerMap); return mapping; } } ``` 请替换`MyWebSocketHandler`为你自己实现WebSocket处理器。 3. 在Gateway配置文件中,添加以下配置来启用WebSocket支持和设置路由规则。 ```yaml spring: cloud: gateway: routes: - id: websocket_route uri: lb://websocket-service predicates: - Path=/ws-endpoint/** filters: - WebSocket=ws-endpoint ``` 这里的`websocket_route`是路由的ID,`lb://websocket-service`是目标WebSocket服务的地址,`/ws-endpoint/**`是需要转发WebSocket请求路径。请根据你的实际情况进行修改。 4. 在你的WebSocket服务项目中,实现一个WebSocket处理器作为目标处理器。例如: ```java @Component public class MyWebSocketHandler extends TextWebSocketHandler { @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { // 处理WebSocket消息 session.sendMessage(new TextMessage("Hello, WebSocket!")); } } ``` 这里的`handleTextMessage`方法用于处理收到的WebSocket消息。 5. 最后,启动你的Gateway服务和WebSocket服务,并尝试发送一个WebSocket消息到`/ws-endpoint`路径。如果一切配置正确,Gateway应该会将该消息转发WebSocket服务,并返回处理结果。 希望这个简单的教程能帮助到你实现Spring Cloud GatewayWebSocket转发功能。如有任何疑问,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值