SpringBoot 集成 STOMP 实现一对一聊天的两种方法

前言

之前写过一篇SpringBoot 配置基于 wss 和 STOMP 的 WebSocket,而本文则将介绍两种实现单点聊天的方法,如果对配置基于 STOMPwssWebSocket 不太熟悉,建议先回看一下,本文的完整代码同样也已上传到GitHub

效果

在介绍最终的实现之前,先看一下效果,为了方便展示,使用了 iframe,以便可以同时展示四个窗口:

demo1

实现

为了实现能够将信息发给特定的用户,本文主要借用了 spring-messagingSimpMessagingTemplate 消息模板来实现,而下面的两种方法也是基于该消息模板的 convertAndSendconvertAndSendToUser 方法来实现。

基于 convertAndSendToUser 方法的实现

为了使用 convertAndSendToUser 方法能指定发送信息给特定用户,首先需要添加一个自定义的处理器,用于生成用户唯一的标识:

public class CustomHandshakeHandler extends DefaultHandshakeHandler {

    @Override
    protected Principal determineUser(
        ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
        // 获取例如 wss://localhost/websocket/1 订阅地址
        // 中的最后一个用户 id 参数作为用户的标识,
        // 为实现发送信息给指定用户做准备
        String uri = request.getURI().toString();
        String uid = uri.substring(uri.lastIndexOf("/") + 1);
        return () -> uid;
    }

}

以上自定义处理器用于设置用户唯一的标识为用户的 uid,用户只要在连接 websocket 时,在订阅地址 wss://localhost/websocket/ 后加上用户的 id,即可作为用户的唯一标识。

然后就是启用 websocket 消息代理的设置:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // 开启一个简单的基于内存的消息代理
        // 将消息返回到订阅了带 /chat 前缀的目的客户端
        config.enableSimpleBroker("/chat");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 注册一个 /websocket/{id} 的 WebSocket 终端
        // {id} 用于让用户连接终端时都可以有自己的路径
        // 作为 Principal 的标识,以便实现向指定用户发送信息
        registry.addEndpoint("/websocket/{id}")
                .setHandshakeHandler(new CustomHandshakeHandler());
    }

}

完成以上的配置后就已经有了一个 websocket终端,下面就介绍对消息的处理,为了便于处理消息,所有的消息都封装成了以下实体:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MessageEntity {

    private Long from;
    private Long to;
    private String message;
    private Date time;

}

其中 from 为发送者的 idto 为接收者的 idmessage 为具体的消息,time 为消息的发送时间。

然后再介绍发送消息的接口:

@RestController
public class ChatController {

    private final MessageService messageService;

    @Autowired
    public ChatController(MessageService messageService) {
        this.messageService = messageService;
    }

    // 这里的 @MessageMapping 可以当成 @RequestMapping,
    // 当有信息 (sendMsg 方法中的 messageEntity 参数即为客服端发送的信息实体)
    // 发送到 /sendMsg 时会在这里进行处理
    @MessageMapping("/sendMsg")
    public void sendMsg(MessageEntity messageEntity) {
        messageService.sendToUser(messageEntity);
    }

}

最后是消息模板发送信息方法:

@Service
public class MessageService {

    private final SimpMessagingTemplate simpMessagingTemplate;

    @Autowired
    public MessageService(SimpMessagingTemplate simpMessagingTemplate) {
        this.simpMessagingTemplate = simpMessagingTemplate;
    }

    public void sendToUser(MessageEntity messageEntity) {
        // convertAndSendToUser 方法可以发送信给给指定用户,
        // 底层会自动将第二个参数目的地址 /chat/contact 拼接为
        // /user/username/chat/contact,其中第二个参数 username 即为这里的第一个参数
        // username 也是前文中配置的 Principal 用户识别标志
        simpMessagingTemplate.convertAndSendToUser(
                String.valueOf(messageEntity.getTo()),
                "/chat/contact",
                messageEntity
        );
    }

}

进行以上后端的后端配置(省略了 wss 的配置,如果不清楚,可以参考前言里的文章),即完成了后端代码的编写,下面再来介绍前端界面的编写:

首先是单个聊天界面的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
    <script src="/webjars/stomp-websocket/stomp.min.js"></script>
</head>
<body>
    <label><input id="uid"/></label>
    <button onclick="login()" id="login">登录</button>
    <label><input id="msg" placeholder="信息后加 -id,发给指定人"/></label>
    <button onclick="sendMsg()">发送</button>
    <div id="user"></div>
    <div id="greet"></div>
    <script>
        let stompClient
        function login() {
            // 根据输入的 id 号模拟不同用户的订阅
            let socket = new WebSocket(`wss://localhost/websocket/${document.getElementById('uid').value}`)
            stompClient = Stomp.over(socket)
            stompClient.connect({}, function () {
                // 所有想要接收给指定用户发送的信息的订阅地址都必须加上/user前缀
                // 这里是为了配合后台的 convertAndSendToUser 方法,如果使用
                // convertAndSend,就不需要 /user 前缀了,下面会再介绍
                stompClient.subscribe(`/user/chat/contact`, function (frame) {
                    let entity = JSON.parse(frame.body)
                    showGreeting(`收到用户${entity.from}的信息: ${entity.message}`)
                })
            })

            document.getElementById('user').innerText = `当前用户为:${document.getElementById('uid').value}`

            function showGreeting(clientMessage) {
                document.getElementById("greet").innerText += `${clientMessage}\n`
            }
        }

        function sendMsg() {
            const msg = document.getElementById('msg').value
            stompClient.send("/sendMsg", {}, JSON.stringify({
                from: document.getElementById('uid').value,
                to: msg.substring(msg.lastIndexOf('-') + 1),
                message: msg.substring(0, msg.lastIndexOf('-')),
                time: new Date()
            }))
        }
    </script>
</body>
</html>

然后是为了有四个聊天界面的代码:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>聊天</title>
    <style>
        html, body, #app {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }

        iframe {
            width: 49%;
            height: 49%;
            border: aquamarine 1px solid;
        }

    </style>
</head>
<body>
    <div id="app">
        <iframe src="https://localhost/index"></iframe>
        <iframe src="https://localhost/index"></iframe>
        <iframe src="https://localhost/index"></iframe>
        <iframe src="https://localhost/index"></iframe>
    </div>
</body>
</html>

进行了以上的配置后,就可以模拟实现简单的单点聊天了,下面再介绍使用消息模板的 convertAndSend 方法来实现单点聊天。

基于convertAndSend 方法的实现

基于convertAndSend 方法的实现不同于基于 convertAndSendToUser 时主要是通过后端进行配置,如果使用 convertAndSend 就只需要在前端订阅时进行控制即可,这么说可能不太清晰,下面就具体展示:

基于convertAndSend 就不再需要自定义处理器了,终端也不再需要/{id} 了:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig2 implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/chat");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket");
    }

}

消息接口处理的代码还是一样:

@RestController
public class ChatController2 {

    private final MessageService2 messageService;

    @Autowired
    public ChatController2(MessageService2 messageService) {
        this.messageService = messageService;
    }

    @MessageMapping("/sendMsg2")
    public void sendMsg(MessageEntity messageEntity) {
        messageService.sendToUser(messageEntity);
    }

}

不过消息模板的方法实现就有所不同了:

@Service
public class MessageService2 {

    private final SimpMessagingTemplate simpMessagingTemplate;

    @Autowired
    public MessageService2(SimpMessagingTemplate simpMessagingTemplate) {
        this.simpMessagingTemplate = simpMessagingTemplate;
    }

    public void sendToUser(MessageEntity messageEntity) {
        simpMessagingTemplate.convertAndSend("/chat/contact/" + messageEntity.getTo(), messageEntity);
    }

}

这里通过在发送地址后拼接目的用户的 id,然后再配合前端订阅时的处理即可实现发送发送信息给特定用户,下面是前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
    <script src="/webjars/stomp-websocket/stomp.min.js"></script>
</head>
<body>
    <label><input id="uid"/></label>
    <button onclick="login()" id="login">登录</button>
    <label><input id="msg" placeholder="信息后加 -id,发给指定人"/></label>
    <button onclick="sendMsg()">发送</button>
    <div id="user"></div>
    <div id="greet"></div>
    <script>
        let stompClient
        function login() {
            let socket = new WebSocket(`wss://localhost/websocket`)
            stompClient = Stomp.over(socket)
            stompClient.connect({}, function () {
                // 由于使用了 convertAndSend, 这里就不再需要加 /user 前缀了
                // 只要在订阅地址后加上自己的 id 即可发送给自己的信息
                stompClient.subscribe(`/chat/contact/${document.getElementById('uid').value}`, function (frame) {
                    let entity = JSON.parse(frame.body)
                    showGreeting(`收到用户${entity.from}的信息: ${entity.message}`)
                })
            })

            document.getElementById('user').innerText = `当前用户为:${document.getElementById('uid').value}`

            function showGreeting(clientMessage) {
                document.getElementById("greet").innerText += `${clientMessage}\n`
            }
        }

        function sendMsg() {
            const msg = document.getElementById('msg').value
            stompClient.send("/sendMsg2", {}, JSON.stringify({
                from: document.getElementById('uid').value,
                to: msg.substring(msg.lastIndexOf('-') + 1),
                message: msg.substring(0, msg.lastIndexOf('-')),
                time: new Date()
            }))
        }
    </script>
</body>
</html>

以上便是基于 STOMP 实现单点聊天的两种方法,如果有不清楚的地方也可以留言反馈。

总结

本文通过一个简单的例子介绍了两种实现单点聊天的方法,在下一篇文章将会通过一个基于 SpringBoot + Vue 的比较完善的例子来展示单点聊天的实现,不过下一篇的例子并未使用本文的 STOMP,而只是用了基本的 WebSocket 通信,不过只要按照本文的例子,也很容易对其进行改造,希望本文能够对你有所帮助。

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
在这个互联网时代,客服可以说必不可少,每个电商网站都应该有一个强大的智能客服对话系统,以满足用户沟通的需求。智能客服对话系统,不仅需要人工的沟通,同时结合人工智能实现智能对话,减少人工客服的成本,势在必行。基于SpringBoot+Python的多语言前后端智能多人聊天系统课程,将以基础知识为根基,带大家完成一个强大的智能客服系统,该系统将包含以下功能:智能对话机器人、单聊、群聊、消息撤回、上线、下线通知、用户动态信息实时提示等。即时通讯和人工智能,在未来的发展趋势,必然需要大批人才,掌握这两个技术势在必行。项目是一个真实可用的项目,商业价值不言而喻。也可以基于课程的基础上进一步完善和优化,所以价值是很高的。本课程包含的技术: 开发工具为:IDEA、WebStorm、PyCharmTensorflowRNNLSTMAnacondaSpringBoot SpringCloudWebsocketSTOMPDjangoVue+Nodejs+jQuery等 课程亮点: 1.与企业接轨、真实工业界产品2.从基础到案例,逐层深入,学完即用3.市场主流的前后端分离架构和人工智能应用结合开发4.多语言结合开发,满足多元化的需求5.涵盖TensorFlow1.x+TensorFlow2.x版本6.智能机器人实战7.即时通讯实战8.多Python环境切换9.微服务SpringBoot10.集成SpringCloud实现统一整合方案 11.全程代码实操,提供全部代码和资料 12.提供答疑和提供企业技术方案咨询 课程目录:第一章、Anaconda以及TensorFlow环境和使用0、智能多人聊天系统课程说明1、智能多人聊天系统之Anaconda讲解2、智能多人聊天系统之Anaconda安装和使用3、智能多人聊天系统之Anaconda之conda命令使用4、智能多人聊天系统之TensorFlow讲解5、智能多人聊天系统之TensorFlow安装和使用6、TensorFlow常量、变量和占位符实战讲解17、TensorFlow常量、变量和占位符实战讲解28、TensorFlow原理补充讲解9、TensorFlow四则运算实战讲10、TensorFlow矩阵操作以及运算实战讲解111、TensorFlow矩阵操作以及运算实战讲解212、TensorFlow均匀分布和正态分布数据实战讲解13、智能多人聊天系统之Numpy实战讲解14、智能多人聊天系统之matplotlib实战讲解15、TensorFlow深度学习DNN讲解16、TensorFlow常用Python扩展包讲解17、TensorFlow常用回归算法以及正则化讲解18、TensorFlow损失函数定义和使用实战讲解19、TensorFlow优化器讲解以及综合案例实战讲解20、智能多人聊天系统之RNN讲解21、智能多人聊天系统之RNN种类讲解22、智能多人聊天系统之RNN代码实战23、智能多人聊天系统之LSTM讲解24、智能多人聊天系统之attention机制讲解25、智能多人聊天系统之Django环境构建及初体验26、智能多人聊天系统之Django开发27、Python章节环境侯建和项目搭建28、Python TensorFlow读取训练数据代码编写29、Python TensorFlow形成语料编码30、Python TensorFlow保存字典文件31、Python TensorFlow构建词向量32、Python TensorFlow构建lstm模型以及attention wrapper33、Python TensorFlow训练代码编写34、Python整体代码讲解35、Python运用模型代码讲解36、SpringBoot讲解以及构建web应用37、Spring Cloud注册中心构建38、智能多人聊天系统之前端Vue项目构建39、SpringBoot+Websocket群聊40、SpringBoot+Websocket昵称群聊41、SpringBoot+Websocket群聊+单聊实战42、SpringBoot+Stomp单聊143、SpringBoot+Stomp单聊244、SpringBoot+Stomp单聊+群聊45、Django Web整合TF代码讲解及Postman调试46、智能客服系统单聊群聊等项目功能代码讲解147、智能客服系统单聊群聊等项目功能代码讲解248、智能客服系统集成机器人对话代码开发讲解49、智能机器人TensorFlow2版本升级实战之训练模型代码讲解50、智能机器人TensorFlow2版本升级实战之预测代码讲解 51、智能机器人TensorFlow2版本升级实战补充讲解
### 回答1: Spring Boot WebSocket Stomp是一种基于Spring Boot框架的WebSocket协议的实现方式,它可以实现实时通信和消息推送功能。Stomp是一种简单的消息传输协议,它可以在WebSocket之上提供一个可靠的消息传输机制。使用Spring Boot WebSocket Stomp可以轻松地实现WebSocket通信,同时也可以使用Stomp协议来传输消息。这种方式非常适合实现实时通信和消息推送功能,例如在线聊天、实时监控等场景。 ### 回答2: springboot websocket stomp是一种基于Java的开源框架,它可以帮助我们实现实时通信功能。它采用了WebSocket协议作为底层通信协议,并结合了STOMP(Simple Text Oriented Messaging Protocol)协议来进行消息的传输和解析。 使用springboot websocket stomp可以很方便地实现客户端和服务器之间的实时通信,比如聊天室、实时数据展示等功能。它的好处是能够降低开发成本,提高开发效率,同时还可以提供较好的用户体验。 在使用springboot websocket stomp时,首先需要进行相关的配置和依赖,然后在代码中定义好相关的消息处理器,用于处理客户端发送过来的消息和服务器推送的消息。接下来,我们可以使用JS等前端技术来调用WebSocket对象,连接到指定的WebSocket服务端,并发送和接收消息。 在WebSocket连接建立之后,我们可以使用STOMP协议进行消息的发送和订阅。我们可以使用STOMP协议中的几个关键命令,比如SEND、SUBSCRIBE、UNSUBSCRIBE等来进行消息的发送和订阅操作。 springboot websocket stomp还提供了一些注解,用于标识和定义消息的处理器、消息的目的地等属性。通过这些注解,我们可以很方便地控制消息的发送和接收。 总的来说,springboot websocket stomp提供了一种简单且效率高的方式来实现实时通信功能。它的易用性、扩展性和可靠性使得它在实际应用中得到广泛的应用。 ### 回答3: Spring Boot是一种用于简化Spring应用程序开发的框架,它提供了许多便利的功能和自动配置的特性。WebSocket是一种在客户端和服务器之间建立持久连接的协议,它为实时双向通信提供了一个解决方案。Stomp是一种在WebSocket之上建立消息传递协议的简单文本协议。 Spring Boot提供了对WebSocketStomp的支持,使开发人员能够轻松实现实时通信功能。通过使用Spring BootWebSocketStomp支持,可以快速构建具有实时功能的应用程序。 在Spring Boot中使用WebSocketStomp,首先需要在pom.xml文件中添加相关依赖。然后,在应用程序的配置类中使用@EnableWebSocketMessageBroker注解启用WebSocketStomp的消息代理功能。接下来,使用@MessageMapping注解来定义处理WebSocket消息的方法。 在处理WebSocket消息的方法中,可以使用@SendTo注解将消息发送到指定的目的地,也可以使用SimpMessagingTemplate来主动推送消息给客户端。 另外,还可以使用@SubscribeMapping注解来定义处理订阅请求的方法。通过在订阅请求方法中返回需要订阅的数据,可以在客户端成功订阅后立即将数据发送给客户端。 通过使用Spring BootWebSocketStomp支持,我们可以轻松地实现实时通信功能,使应用程序能够实时传递消息和数据。这对于需要实时更新的应用程序非常有用,如聊天室、股票交易系统等。 总而言之,Spring Boot提供了对WebSocketStomp的支持,使开发人员能够方便地构建具有实时通信功能的应用程序。通过使用WebSocketStomp,我们可以实现实时传递消息和数据的需求。
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值