springboot-集成WebSockets广播消息

简介: springboot-集成WebSockets广播消息

一 WebScoketS 简介

RFC 6455 即 webSockets 协议提供了一种标准化的方式去建立全双工,双方面交流的通道在客户端和服务端甚至单一的TCP连接中进行通信; webSockets 协议其跟HTTP的tcp协议不同,但是其设计目的是通过HTTP协议进行工作,可以使用40或者443端口和重新使用现有的防火墙规则;

GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080

webSockets 的交互是以HTTP协议开始的,使用Upgrade header 转向使用Upgrade连接;如果非200状态成功响应就类似于下面的信息;如果WebSocket server 是运行在nginx是需要配置WebSocket upgrade requests ;如果是运行在云上,需要查阅相关的云是否支持WebSocket ;

HTTP/1.1 101 Switching Protocols 
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp

二 HTTP 和 WebSocket 对比

  1. 在HTTP和REST中一个应用需要很多的URLs;应用和客户端是通过 请求和响应的风格使用这些URLs进行交互;服务端会路由这些请求给基于HTTP 的URL或者方法或者头进行处理;
  2. WebSockets 通常在初始化的时候就只有一个链接,所有应用的消息都是通过相同的TCP连接进行流动;这指向一个完全不同的异步、事件驱动的消息传递体系结构。
  3. WebSocket 是一种低端的协议,不像HTTP,其不规定消息中内容中任何的语义信息;这意味着其没有任何方式去路由或者处理这些信息,除非客户端和服务端在语义上达成一致;
  4. WebSocket 客户端和服务端其交流是通过使用更加高级的消息协议(比如STOMP)和基于HTTP握手请求的Sec-WebSocket-Protocol header ;

三 注意事项

WebSockets可以使web页面具有动态性和交互性。然而,在许多情况下,Ajax和HTTP流或 long polling(轮询)可以提供一个简单有效的解决方案。HTTP流和polling适用于消息不频繁的交互,WebSockets适用于消息较频繁的交互;在 因特网上由于没有Upgrade header 或者 关闭了空闲的长链接,受限于在你有限的代理可能会将WebSockets的交互排除;

四 websocket配置和依赖

4.1 依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.1.RELEASE</version>
        <relativePath/>
    </parent>
    
    <dependencies>
        <!--  websocket依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <!-- 模板引擎-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

4.2 配置

/**
 * @Author lsc
 * @Description <p>websocket配置类 </p>
 * @Date 2019/11/12 22:27
 */
//使用STOMP协议来传输基于消息代理的消息,控制器支持在@Controller类中使用@MessageMapping
@EnableWebSocketMessageBroker
@Configurable
@EnableWebSocket
@Component
public class WebConfig implements WebSocketMessageBrokerConfigurer {
 
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 注册 Stomp的端点(Endpoint),并且映射指定的url
        registry.addEndpoint("/websocket")
                .setAllowedOrigins("*") // 添加允许跨域访问
                .withSockJS();// 指定SockJS协议
    }
 
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 启动广播模式代理,只有符合的的路径才发送消息
        registry.enableSimpleBroker("/topic");
    }
}

五 实体类

5.1 接受消息实体

/**
 * @Author lsc
 * @Description <p> 接受客户端消息</p>
 * @Date 2019/11/12 22:42
 */
public class AcceptMessages {
 
    private String name;
 
    public String getName() {
        return name;
    }
}

5.2 发送消息实体

/**
 * @Author lsc
 * @Description <p>发送消息给客户端 </p>
 * @Date 2019/11/12 22:42
 */
public class SendMessages {
 
    private String responseMessage;
 
    public String getResponseMessage() {
        return responseMessage;
    }
 
    public void setResponseMessage(String responseMessage) {
        this.responseMessage = responseMessage;
    }
}

六控制器

/**
 * @Author lsc
 * @Description <p>websockets 之 广播式</p>
 * @Date 2019/11/12 22:49
 */
@Controller
public class WebSocketsController {
 
    @MessageMapping("/welcome")//类似@RequestMapping,进行客户端请求地址映射
    @SendTo("/topic/getResponse")//订阅了@SendTo中的路径进行发送消息
    public SendMessages broadcast(AcceptMessages acceptMessages){
        System.out.println(acceptMessages.getName());
        SendMessages sendMessages = new SendMessages();
        sendMessages.setResponseMessage("知识追寻者:"+acceptMessages.getName());
        return sendMessages;
    }
 
}

七 前端页面

在 resource目录下新建templates目录存放WebSockets.html;在resource目录下新建static目录,继续在其子目录下新建js目录存放sockjs.min.js,stomp.min.js,jquery-3.3.1.min.js;

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>springboot广播式WebSocket</title>
</head>
<body onload="disconnect()">
<noscript><h2 style="color: #ffff0000;">Sorry,not support the WebSocket</h2></noscript>
<div>
    <div>
        <button id="connect" onclick="connect();">连接</button>
        <button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接</button>
    </div>
    <div id="conversationDiv">
        <label>输入你的名字</label>
        <input type="text" id="name"/>
        <button id="sendName" onclick="sendName();">发送</button>
        <p id="response"></p>
    </div>
</div>
<script th:src="@{js/sockjs.min.js}"></script>
<script th:src="@{js/stomp.min.js}"></script>
<script th:src="@{js/jquery-3.3.1.min.js}"></script>
<script type="text/javascript">
    var stompClient = null;
    // 设置连接
    function setConnected(connected) {
        document.getElementById("connect").disabled = connected;
        document.getElementById("disconnect").disabled = !connected;
        document.getElementById("conversationDiv").style.visibility = connected ? 'visible' : 'hidden';
        $("#response").html();
    }
    // 连接
    function connect() {
        // 转向 endpoint 名为websocket
        var socket = new SockJS('/websocket');
        // 使用ssocket的协议
        stompClient = Stomp.over(socket);
        // 连接
        stompClient.connect({}, function (frame) {
            setConnected(true);
            console.log('Connected:' + frame);
            // @Sendto 中定义路径 向目标订阅消息
            stompClient.subscribe('/topic/getResponse', function (response) {
                showResponse(JSON.parse(response.body).responseMessage);
            })
        });
    }
    function disconnect() {
        if (stompClient != null) {
            stompClient.disconnect();
        }
        setConnected(false);
        console.log('Disconnected');
    }
    function sendName() {
        var name = $('#name').val();
        // 控制器@MessageMapping中定义向目标发送消息
        stompClient.send("/welcome", {}, JSON.stringify({'name': name}));
    }
    function showResponse(message) {
        $("#response").html(message);
    }
</script>
</body>
</html>

八 视图转发

当客户端请求地址是localhost:8080/ws,经过springmvc视图转发器至WebSockets.html;

/**
 * @Author lsc
 * @Description <p> spingmvc视图映射转发</p>
 * @Date 2019/11/12 23:35
 */
@Configurable
@Component
public class WebMvcConfig implements WebMvcConfigurer {
 
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 配置视图转发
        registry.addViewController("/ws").setViewName("/WebSockets");
    }
}

九 效果图

即一个浏览器发送消息,其它连接的浏览器也能收到消息,即广播形式;

十参考文献

参考1:《JavaEE开发的颠覆者》

参考2: spring-web

源码: youku1327

相关文章
|
3天前
|
消息中间件 Java Kafka
springboot集成kafka
springboot集成kafka
11 2
|
10天前
|
消息中间件 Java Kafka
集成Kafka到Spring Boot项目中的步骤和配置
集成Kafka到Spring Boot项目中的步骤和配置
43 7
|
10天前
|
druid Java 关系型数据库
在Spring Boot中集成Druid实现多数据源有两种常用的方式:使用Spring Boot的自动配置和手动配置。
在Spring Boot中集成Druid实现多数据源有两种常用的方式:使用Spring Boot的自动配置和手动配置。
76 5
|
10天前
|
Java 数据库连接 mybatis
在Spring Boot应用中集成MyBatis与MyBatis-Plus
在Spring Boot应用中集成MyBatis与MyBatis-Plus
46 5
|
10天前
|
前端开发 JavaScript 安全
集成WebSocket在Spring Boot中可以用于实现实时的双向通信
集成WebSocket在Spring Boot中可以用于实现实时的双向通信
28 4
|
10天前
|
安全 Java Maven
在 Spring Boot 中实现邮件发送功能可以通过集成 Spring Boot 提供的邮件发送支持来完成
在 Spring Boot 中实现邮件发送功能可以通过集成 Spring Boot 提供的邮件发送支持来完成
19 2
|
10天前
|
XML 搜索推荐 Java
Elasticsearch集成到Spring Boot项目
将Elasticsearch集成到Spring Boot项目中,可以方便地实现数据的搜索、分析等功能。
35 2
|
10天前
|
监控 前端开发 Java
五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链
五分钟后,你将学会在SpringBoot项目中如何集成CAT调用链
|
10天前
|
Java API Spring
集成EasyPoi(一个基于POI的Excel导入导出工具)到Spring Boot项目中
集成EasyPoi(一个基于POI的Excel导入导出工具)到Spring Boot项目中
47 1
|
11天前
|
easyexcel Java API
SpringBoot集成EasyExcel 3.x:高效实现Excel数据的优雅导入与导出
SpringBoot集成EasyExcel 3.x:高效实现Excel数据的优雅导入与导出
35 1