1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 手放开 李圣杰
  4. 4 迷人的危险3(翻自 dance flow) FAFA
  5. 5 山楂树之恋 程佳佳
  6. 6 summertime cinnamons / evening cinema
  7. 7 不谓侠(Cover 萧忆情Alex) CRITTY
  8. 8 神武醉相思(翻自 优我女团) 双笙
  9. 9 空山新雨后 音阙诗听 / 锦零
  10. 10 Wonderful U (Demo Version) AGA
  11. 11 广寒宫 丸子呦
  12. 12 陪我看日出 回音哥
  13. 13 春夏秋冬的你 王宇良
  14. 14 世界が终わるまでは… WANDS
  15. 15 多想在平庸的生活拥抱你 隔壁老樊
  16. 16 千禧 徐秉龙
  17. 17 我的一个道姑朋友 双笙
  18. 18 大鱼  (Cover 周深) 双笙
  19. 19 霜雪千年(Cover 洛天依 / 乐正绫) 双笙 / 封茗囧菌
  20. 20 云烟成雨(翻自 房东的猫) 周玥
  21. 21 情深深雨濛濛 杨胖雨
  22. 22 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  23. 23 斑马斑马 房东的猫
  24. 24 See You Again Wiz Khalifa / Charlie Puth
  25. 25 Faded Alan Walker / Iselin Solheim
  26. 26 Natural J.Fla
  27. 27 New Soul Vox Angeli
  28. 28 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  29. 29 像鱼 王贰浪
  30. 30 Bye Bye Bye Lovestoned
  31. 31 Blame You 眠 / Lopu$
  32. 32 Believer J.Fla
  33. 33 书信 戴羽彤
  34. 34 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  35. 35 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  36. 36 慢慢喜欢你 LIve版(翻自 莫文蔚) 戴羽彤
  37. 37 病变(翻自 cubi) 戴羽彤
  38. 38 那女孩对我说 (完整版) Uu
  39. 39 绿色 陈雪凝
  40. 40 月牙湾 LIve版(翻自 F.I.R.) 戴羽彤
夜空中最亮的星(翻自 逃跑计划) - 戴羽彤
00:00 / 04:10

夜空中最亮的星 能否听清

那仰望的人 心底的孤独和叹息

夜空中最亮的星 能否记起

那曾与我同行 消失在风里的身影

我祈祷拥有一颗透明的心灵

和会流泪的眼睛

给我再去相信的勇气

越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请指引我靠近你

夜空中最亮的星 是否知道

那曾与我同行的身影 如今在哪里

夜空中最亮的星 是否在意

是等太阳先升起 还是意外先来临

我宁愿所有痛苦都留在心底

也不愿忘记你的眼睛

哦 给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行 哒~

我祈祷拥有一颗透明的心灵

和会流泪的眼睛 哦

给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行

spring-boot之websocket · 下

前言

昨天我们提到,并不是所有的浏览器都支持websokcet协议,对于不支持的浏览器,我们要通过STOMP 协议来进行兼容,今天我们就来看下如何通过STOMP 来兼容websocket

websocket兼容

STOMP的全称是Simple (or Streaming) Text Orientated Messaging Protocol,中文的意思是简单(流)文本定向消息协议,也就是说,我们其实使用了消息组件来兼容的。

配置类

对于不支持websocket的浏览器我们需要通过STOMP来兼容,兼容的解决方案涉及两方面知识,一个是SockJs,一个就是WebSocketMessageBrokerSockJs一种让前端可以支持socket通信的技术解决方案,WebSocketMessageBroker是基于消息组件实现的一种通信协议。

下面是我们的STOMP解决方案的配置类,注释已经够详细了,所以这里就不在赘述。

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    /**
     * 注册服务器端点
     * @param registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 增加一个聊天服务端点
        registry.addEndpoint("/socket").withSockJS();
        // 增加一个用户服务端点
        registry.addEndpoint("/wsuser").withSockJS();
    }

    /**
     * 定义服务器端点请求和订阅前缀
     * @param registry
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 客户端订阅路径前缀
        registry.enableSimpleBroker("/sub", "/queue");
        // 服务端点请求前缀
        registry.setApplicationDestinationPrefixes("/request");
    }
}

消息接收接口

这里定义两个接口,一个是接收通用消息的(/send),一个是发给指定用户的(/sendToUser)。这里需要补充说明的是,@SendTo注解的作用是将接收到的消息发送到指定的路由目的地,所有订阅该消息的用户都能收到,属于广播。

@RestController
public class WebsocketController {
    private final Logger logger = LoggerFactory.getLogger(WebsocketController.class);

    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;

    @Autowired
    private WebSocketService webSocketService;

    @MessageMapping("/send")
    @SendTo("/sub/chat")
    public String sendMessage(String value) {
        logger.info("发送消息内容:{}", value);
        return value;
    }

    @MessageMapping("/sendToUser")
    public void sendToUser(Principal principal, String body) {
        String srcUser = principal.getName();
        String[] args = body.split(": ");
        String desUser = args[0];
        String message = String.format("【%s】给你发来消息:%s", webSocketService.getNameMap().get(srcUser), args[1]);
        // 发送到用户和监听地址
        simpMessagingTemplate.convertAndSendToUser(desUser, "/queue/customer", message);

    }

}

前端页面

普通消息发送

首先要引入jquery.jsstomp.jssockjs.js,这个三个js就可以确保前端页面也支持STOMP协议。

然后我们定义了三个方法:connect()disconnect()sendMessage()方法。

connect方法内部,我们通过SockJS初始化了stompClient实例,SockJS的节点地址就是我们配置类中定义的聊天服务节点,然后建立stomp连接。

发送消息的时候,我们直接调用stomp客户端的send方法即可,这里需要指定发送消息的地址,要和消息接收方的地址一致。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>websocket STOMP</title>
</head>
<body>
websocket兼容STOMP测试<br>
<div>
    <div>
        <button id = "connect" onclick="connect()">连接</button>
        <button id = "disconnect" disabled="disabled" onclick="disconnect()">断开连接</button>
</div>
    <div id = "conversationDiv">
        <p>
            <label>发送消息内容</label>
        </p>
        <p>
            <textarea id="message" rows = "5"></textarea>
        </p>
        <p>
            <button id = "sendMsg" onclick="sendMessage()">发送</button>
        </p>
        <p id = "response">

        </p>
    </div>

    <a href="#" target="/websocket-receive">跳转到消息接收页</a>
</div>

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/stomp.js/2.3.3/stomp.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script type="text/javascript">
    var stompClient = null;
    // 设置连接
    function setConnected(connected) {
        $("#connect").attr({"disabled": connected});
        $("#disconnect").attr({"disabled": !connected});
        if (connected) {
            $("#conversationDiv").show();
        } else {
            $("#conversationDiv").hide();
        }
        $("#response").html("")
    }

    function connect() {
        // 定义请求服务器的端点
        var socket = new SockJS('/socket');
        // stomp客户端
        stompClient = Stomp.over(socket);
        // 连接服务器端点
        stompClient.connect({}, function (frame) {
            // 建立连接后的回调
            setConnected(true);
        })
    }
    // 断开socket连接
    function disconnect() {
        if (stompClient != null) {
            stompClient.disconnect();
        }
        setConnected(false);
        console.log("Disconnected");
    }
    // 向/request/send服务端发送消息
    function sendMessage() {
        var message = $("#message").val();
        // 发送消息到"/request/send",其中/request是服务器定义的前缀
        // 而/send则是@MessageMapping所配置的路径
        stompClient.send("/request/send", {}, message);
    }
    connect();
</script>

</body>
</html>
普通文本消息接收

接收页面和发送页面对应,sockJS的地址必须一样,因为是接收消息,所以这里执行的是stompClientsubscribe(订阅消息),这里的地址也必须和发送页面一致,否则无法收到消息

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>websocket-stomp-receive</title>
</head>
<body>

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/stomp.js/2.3.3/stomp.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script type="text/javascript">
    var noticeSocket = function () {
        // 连接服务器端点
        var s = new SockJS('/socket');
        //客户端
        var stompClient = Stomp.over(s);
        stompClient.connect({}, function () {
            console.log("notice socket connected !");
            // 订阅消息地址
            stompClient.subscribe('/sub/chat', function (data) {
                $('#receive').html(data.body);
            });
        });
    };
    noticeSocket();
</script>
<h1><span id="receive">等待接收消息</span></h1>

</body>
</html>
普通文本测试

我登陆了两个账号,用其中一个账号发送消息,他自己以及另一个账号都收到了发送的消息,说明我们的实例是ok的。

下面,我们看下如何给指定用户发送消息。

给指定用户发送消息

发送页面没有区别,只是js不一样,所以这里只贴出js

首先第一个不一样的地方是服务端点不一样了,我们这里的SockJS监听的是/wsuser,也就是给指定用户发送消息的地址。

然后再就是发送消息的地址也变了,指定的是/request/sendToUser,对应的是指定用户的发送消息的接口,剩下其他的都一模一样。

<script type="text/javascript">


    var stompClient = null;
    // 设置连接
    function setConnected(connected) {
        $("#connect").attr({"disabled": connected});
        $("#disconnect").attr({"disabled": !connected});
        if (connected) {
            $("#conversationDiv").show();
        } else {
            $("#conversationDiv").hide();
        }
        $("#response").html("")
    }

    function connect() {
        // 定义请求服务器的端点
        var socket = new SockJS('/wsuser');
        // stomp客户端
        stompClient = Stomp.over(socket);
        // 连接服务器端点
        stompClient.connect({}, function (frame) {
            // 建立连接后的回调
            setConnected(true);
        })
    }
    // 断开socket连接
    function disconnect() {
        if (stompClient != null) {
            stompClient.disconnect();
        }
        setConnected(false);
        console.log("Disconnected");
    }
    // 向/request/send服务端发送消息
    function sendMessage() {
        var message = $("#message").val();
        var user = $("#user").val();
        // 发送消息到"/request/send",其中/request是服务器定义的前缀
        // 而/send则是@MessageMapping所配置的路径
        var messageSend = user + ": " + message
        stompClient.send("/request/sendToUser", {}, messageSend);
    }
    connect();
</script>
给指定用户接收页面

这里也只是js发生变化,节点名称和发生页面一致,订阅地址和配置类中的一致。

<script type="text/javascript">
    var noticeSocket = function () {
        // 连接服务器端点
        var s = new SockJS('/wsuser');
        //客户端
        var stompClient = Stomp.over(s);
        stompClient.connect({}, function () {
            console.log("notice socket connected !");
            // 订阅消息地址
            stompClient.subscribe('/user/queue/customer', function (data) {
                $('#receive').html(data.body);
            });
        });
    };
    noticeSocket();
</script>
给指定用户发送消息测试

这次我们用哪吒的账号给女娲发了一条消息,最终的结果是只有女娲收到了消息,也和我们预期一致。

总结

相比于昨天我们直接通过websocket通信,通过STOMP通信,前端要稍过复杂一些,但总体来说,也不是特别复杂。

通篇来看,其实STOMP就是后端启动一个消息池,然后将消息发送接口暴露给前端,前端调用发送消息接口发消息,消息由后端转发到消息池中指定的队列(类似消息中继站),然后消费者(订阅该队列的消息接收方)接收并消费其中的消息。

如果知道了这点,那我们完全可以自己根据mq的相关文档开发一套,而且现在好多mq都提供了对ajax的支持,比如activemq

posted @ 2021-07-26 14:25  云中志  阅读(40)  评论(0编辑  收藏  举报