websocket(二)–基于sockjs和stomp实现广播通信

websocket(二)–基于sockjs和stomp实现广播通信

文章目录

  • websocket(二)--基于sockjs和stomp实现广播通信
      • 一、简介
      • 二、知识点
        • 2.1 sockjs
        • 2.2、stomp
      • 三、后端知识点
        • 3.1 注解@EnableWebSocketMessageBroker
        • 3.2 WebSocketMessageBrokerConfigurer类
        • 3.3 @MessageMapping
        • 3.4 @SendTo
      • 四、前端知识点
      • 五、使用示例
        • 5.1 添加maven依赖
        • 5.2 配置spring mvc类
        • 5.3 配置websocket类
        • 5.4 定义消息载体类
        • 5.5 定义转发页面和消息处理的controller
        • 5.6 spring boot配置文件application.yaml
        • 5.7 spring boot启动类
        • 5.8 添加前端静态文件
        • 5.9 定义前端页面

一、简介

原生websocket实现方式需要新版浏览器的支持。为兼容不支持websocket的浏览器,可以使用sockjs和stomp,当浏览器不支持时,会自动改用轮询等方式来模拟websocket实现。这里介绍基于sockjs和stomp实现websocket的广播通信。

二、知识点

2.1 sockjs

sockjs是javascript库,提供了服务器和浏览器间的双向通信,优先使用websocket通信,当浏览器不支持时,则自动改为轮询与服务器通信。

2.2、stomp

stomp(streaming text orientated messaging protocal),即面向流文本的消息协议,定义了服务端与客户端进行消息传递的文本格式,其使用基于帧(frame)的格式定义消息。

三、后端知识点

3.1 注解@EnableWebSocketMessageBroker

开启stomp协议,使用基于消息代理(message broker)来传输,消息的接收支持注解@MessageMapping;

3.2 WebSocketMessageBrokerConfigurer类

定义来自客户端用于配置消息处理如stomp协议的方法,关键方法有:

  • default void registerStompEndpoints(StompEndpointRegistry registry)
    注册endpoint, 即是客户端连接址。如:registry.addEndpoint("/endpoint").setAllowedOrigins("*").withSockJS();
  • default void configureMessageBroker(MessageBrokerRegistry registry)
    配置消息代理选项,如接收消息的地址前缀,如:registry.enableSimpleBroker("/topicTalkClient");
  • default void configureClientInboundChannel(ChannelRegistration registration)
    配置来自客户端的用于接收消息的org.springframework.messaging.MessageChanne。
  • default void configureClientOutboundChannel(ChannelRegistration registration)
    配置发给客户端的用于发送消息的org.springframework.messaging.MessageChanne。

3.3 @MessageMapping

服务端接收消息的地址(即是客户端发送消息的地址)

3.4 @SendTo

服务端广播的地址(即是客户端监听接收消息的地址);

四、前端知识点

  1. 需要下载sockjs.js和stomp.min.js

  2. 连接服务端,如:

    var socket = new SockJS("/endpoint");
    
  3. 获取stomp对象,如:

    client = Stomp.over(socket);
    
  4. 连接并订阅消息, 如:

    client.connect(headers, function (frame) {
            client.subscribe("/topicTalkClient", function (response) {..})
    });
    
  5. 发送消息,如:

    client.send("/topicTalkServer", headers, JSON.stringify({'uid': 1, 'msg': msg}));
    

五、使用示例

5.1 添加maven依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-websocketartifactId>
dependency>
<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
    <optional>trueoptional>
dependency>
<dependency>

5.2 配置spring mvc类

package com.dragon.public_talk.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /
     * 添加静态文件
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/").addResourceLocations("classpath:/static/");
    }
}

5.3 配置websocket类

package com.dragon.public_talk.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    /
     * 注册stomp的endpoint端点
     * @param registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        //addEndpoint客户端连接地址,setAllowedOrigins允许连接的域名,withSockJS支持以SockJS连接服务器
        registry.addEndpoint("/endpoint").setAllowedOrigins("*").withSockJS();
    }

    /
     * 设置消息代理,默认会配置一个简单的内存消息代理
     * @param registry
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //配置发送给客户端消息的地址前缀,这是"/topicTalkClient",可配置多个,对就@SendTo中的地址
        registry.enableSimpleBroker("/topicTalkClient");
    }
}

5.4 定义消息载体类

package com.dragon.public_talk.bean;
import lombok.Data;
/
 * 消息载体
 */
@Data
public class MsgBean {
    private String uid;
    private String msg;
}

5.5 定义转发页面和消息处理的controller

package com.dragon.public_talk.controller;

import com.dragon.public_talk.bean.MsgBean;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.*;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Map;

@Controller
public class TopicWebSocketController {
    /
     * 对话页面
     *
     * @param model
     * @param uid
     * @return
     */
    @RequestMapping("/topicTalk/{uid}")
    public String topicTalk(Model model, @PathVariable String uid) {
        model.addAttribute("uid", uid);
        return "topicTalk";

    }

    /
     * 接收和广播消息
     *
     * @param msg
     * @return
     */
    @MessageMapping("/topicTalkServer")  //客户端发到服务端
    @SendTo("/topicTalkClient")  //服务端发到客户端,客户端订阅
    public MsgBean topicTalk(MsgBean msg,  //消息
                             StompHeaderAccessor accessor, //所有消息头信息
                             @Headers Map<String, Object> headers, //所有头部值
                             @Header(name = "simpSessionId") String sessionId, //指定头部的值 ,这里指sessionId
                             Message message,   //完整消息,包含消息头和消息体(即header和body)
                             @Payload String body) { //消息体内容
        //消息直接返回
        return msg;
    }
}

5.6 spring boot配置文件application.yaml

server:
  port: 8010

5.7 spring boot启动类

package com.dragon.public_talk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class PublicTalkApplication {

    public static void main(String[] args) {
        SpringApplication.run(PublicTalkApplication.class, args);
    }

}

5.8 添加前端静态文件

添加前端静态文件jquery-3.1.1.min.js、sockjs.js、stomp.min.js

5.9 定义前端页面


<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>

    <style>
        #historyId {
            border: 1px black solid;
            height: 370px;
            width: 500px;
            overflow-y: scroll;
            word-break: break-all;
        }

        #msgId {
            width: 500px;
            height: 130px;
        }

        #talkId {
            /*text-align: center;*/
        }
    style>

head>
<body>
<section id="talkId">
    <header>
        tip:<span id="tipId" th:text="${uid}">span>
    header>

    <article id="historyId">

    article>
    <article>
        <textarea id="msgId">textarea>
    article>
    <footer>
        <button id="sendId">sendbutton>
        <button id="closeId">closebutton>
        <button id="clearId">clearbutton>
        <button id="connectId">connectbutton>
    footer>
section>

<script src="../static/js/jquery-3.1.1.min.js">script>
<script src="../static/js/sockjs.js">script>
<script src="../static/js/stomp.min.js">script>
<script type="text/javascript" th:inline="javascript">
    $(function () {
        //stomp协议客户端对象
        var client;
        //连接
        var headers = {'uid': [[${uid}]]};
        var connect = function () {
            //连接endpoint地址,这里完整地址为: http://localhost:8010/endpoint
            var socket = new SockJS("/endpoint");
            //获取stomp协议的客户端对象
            client = Stomp.over(socket);
            client.connect(headers, function (frame) {
                //订阅消息,对应后端@SendTo中地址
                client.subscribe("/topicTalkClient", function (response) {
                    var obj = JSON.parse(response.body)
                    $("#historyId").append("

" + obj.uid + ":" + obj.msg + "

"
); $("#historyId").scrollTop($("#historyId")[0].scrollHeight); }) }); $("#tipId").html("connect success"); }; var sendMsg = function () { var msg = $("#msgId").val(); if (/^\s*$/.test(msg)) { $("#msgId").val(""); return; } //发送消息,对应@MessageMapping中地址 client.send("/topicTalkServer", headers, JSON.stringify({'uid': [[${uid}]], 'msg': msg})); $("#msgId").val(""); }; //点按钮发送消息 $("#sendId").click(function () { sendMsg(); }); //回车发消息 $(document).keyup(function (e) { if (e.keyCode == 13) { sendMsg(); } }); //清空记录 $("#clearId").click(function () { $("#historyId").empty(); }); //连接 $("#connectId").click(function () { connect(); }); //关闭连接 $("#closeId").click(function () { client.disconnect(); $("#tipId").html("connect close"); }); })
script> body> html>

至此,示例websocket广播结束。
访问地址:
http://localhost:8010/topicTalk/1
http://localhost:8010/topicTalk/2
所在页面均会收到消息

你可能感兴趣的:(java通信)