webSocket学习笔记(一)HelloWorld - STOMP

一、介绍

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。


其他特点包括:


(1)建立在 TCP 协议之上,服务器端的实现比较容易。


(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。


(3)数据格式比较轻量,性能开销小,通信高效。


(4)可以发送文本,也可以发送二进制数据。


(5)没有同源限制,客户端可以与任意服务器通信。


(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

二、代码实现

一个集成在springboot中的小demo

maven依赖

<!-- webSocket -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

配置类和常量类

package com.huaguoguo.constant;

/**
  * @Author:huaguoguo
  * @Description: websocket常量类
  * @Date: 2018/5/21 16:40
  */
public class WebSocketConstant {

    /**
     * 链接地址
     */
    public static String WEBSOCKETPATHPERFIX = "/ws-push";
    public static String WEBSOCKETPATH = "/endpointWisely";
    /**
     * 消息代理路径
     */
    public static String WEBSOCKETBROADCASTPATH = "/topic";
    /**
     * 前端发送给服务端请求地址
     */
    public static final String FORETOSERVERPATH = "/welcome";
    /**
     * 服务端生产地址,客户端订阅此地址以接收服务端生产的消息
     */
    public static final String PRODUCERPATH = "/topic/getResponse";
    /**
     * 点对点消息推送地址前缀
     */
    public static final String P2PPUSHBASEPATH = "/user";
    /**
     * 点对点消息推送地址后缀,最后的地址为/user/用户识别码/msg
     */
    public static final String P2PPUSHPATH = "/msg";
}
package com.huaguoguo.config;

import com.huaguoguo.constant.WebSocketConstant;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Configuration
//注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{

    /**
     * 注册STOMP协议的节点(endpoint),并映射指定的url
     * @param stompEndpointRegistry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        //注册一个STOMP的endpoint,并指定使用SockJS协议
        stompEndpointRegistry.addEndpoint(WebSocketConstant.WEBSOCKETPATH).withSockJS();
    }

    /**
     * 配置消息代理(Message Broker)
     * @param registry
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //广播式应配置一个/topic消息代理
        registry.enableSimpleBroker(WebSocketConstant.WEBSOCKETBROADCASTPATH);
        //定义一对一推送的时候前缀
        registry.setUserDestinationPrefix(WebSocketConstant.P2PPUSHBASEPATH);
        //定义websoket前缀
        registry.setApplicationDestinationPrefixes(WebSocketConstant.WEBSOCKETPATHPERFIX);
    }
}

controller

package com.huaguoguo.controller;

import com.huaguoguo.constant.WebSocketConstant;
import com.huaguoguo.entity.websocket.WiselyMessage;
import com.huaguoguo.entity.websocket.WiselyResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

import java.util.ArrayList;
import java.util.List;

/**
 * webSocket控制器
 */
@Controller
public class WebSocketController {


    @MessageMapping(WebSocketConstant.FORETOSERVERPATH) //当浏览器向服务端发送请求时,通过@MessageMapping映射/welcome这个地址,类似于@ResponseMapping
    @SendTo(WebSocketConstant.PRODUCERPATH)//当服务器有消息时,会对订阅了@SendTo中的路径的浏览器发送消息
    public WiselyResponse say(WiselyMessage message) {
        return new WiselyResponse("Welcome, " + message.getName() + "!");
    }

}

html页面

springboot中,html引擎使用thymeleaf

需要加入thymeleaf的maven依赖

<!-- thymeleaf模板引擎 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

在application.properties中,加入thymeleaf的配置

spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.cache=false

将html页面放在resource/templates目录下

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>SpringBoot实现广播式WebSocket</title>
    <!--<script th:src="@{sockjs.min.js}"></script>
    <script th:src="@{stomp.min.js}"></script>
    <script th:src="@{jquery.js}"></script>-->
    <script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
    <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<noscript><h2 style="color:#ff0000">抱歉,您的浏览器不支持改功能!</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>
</body>
<script type="text/javascript">
    var stompClient = null;
    var userId = 'd892bf12bf7d11e793b69c5c8e6f60fb';

    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() {
        var socket = new SockJS('/endpointWisely'); //连接SockJS的endpoint名称为"endpointWisely"
        stompClient = Stomp.over(socket);//使用STMOP子协议的WebSocket客户端
        stompClient.connect({}, function (frame) {//连接WebSocket服务端
            setConnected(true);
            console.log('Connected:' + frame);
            //通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息,这个是在控制器的@SentTo中定义的
            stompClient.subscribe('/topic/getResponse', function (response) {
                showResponse(JSON.parse(response.body).responseMessage);
            });

            //通过stompClient.subscribe()订阅服务器的目标是'/user/' + userId + '/msg'接收一对一的推送消息,其中userId由服务端传递过来,用于表示唯一的用户,通过此值将消息精确推送给一个用户
            stompClient.subscribe('/user/' + userId + '/msg', function(respnose){
                console.log(respnose);
                showResponse1(JSON.parse(respnose.body).responseMessage);
            });
        });
    }

    function disconnect() {
        if (stompClient != null) {
            stompClient.disconnect();
        }
        setConnected(false);
        console.log("Disconnected");
    }

    function sendName() {
        var name = $("#name").val();
        alert(name);
        //通过stompClient.send向/welcome 目标(destination)发送消息,这个是在控制器的@MessageMapping中定义的
        stompClient.send("/ws-push/welcome", {}, JSON.stringify({'name': name}));
    }

    function showResponse(message) {
        alert(message);
        var response = $("#response");
        response.html(message);
    }
</script>
</html>

还需要一个controller来做页面跳转

package com.huaguoguo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
  * @Author:huaguoguo
  * @Description:页面跳转controller
  * @Date: 2018/5/21 17:14
  */
@Controller
public class PageController {

    @RequestMapping(value = "toWebSocket",method = RequestMethod.GET)
    public String toWebSocket(){
        return "webSocket";
    }
}

三、效果展示

启动springboot工程,跳转到页面


点击“连接”


SUBSCRIBE已经出现订阅日志了,这时服务器推送的消息就可以被浏览器接收了

在输入框输入一个字符串,发送


MESSAGE就是服务器推送的消息

这样整个demo就成功了。

想看完整的代码,可以访问我的GitHub地址是

https://github.com/huaguoguo555/hellohuaguoguo

猜你喜欢

转载自blog.csdn.net/qq_23603437/article/details/80397083