一、 1.1:用法,版本号:0.0.3

<dependency>
          <groupId>cn.zflzqy</groupId>
          <artifactId>web-socket</artifactId>
          <version>${websocket.version}</version>
 </dependency>

1.2、spring中的配置属性

# 请求头中的鉴权key,默认username
zfl.zqy.websocket.header-key=username

1.3:注意 destination 如果是广播,页面就填/app/send,如果是个人页面就填:/user/sendUser/info 注意广播只能以app开头,但是后端的发送以topic开头,ws会自己把app缓存topic 单对单只能以user开头,且除去user前缀后的地址必须有2个斜线(傻逼ws),且前端订阅地址必须是/user/topic开头 使用示范

package cn.zflzqy.myApp.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.handler.annotation.*;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;

import java.security.Principal;
import java.util.Map;

@Controller
public class MessageController {
 
    private static final Logger log = LoggerFactory.getLogger(MessageController.class);
 
    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;
    // 参考地址
    // https://docs.spring.io/spring-framework/docs/5.0.5.RELEASE/spring-framework-reference/web.html#websocket-stomp-handle-send
 
    @MessageMapping("/test/{id}")
    public void test(Message message,
                     MessageHeaders MessageHeaders,
                     @Header("destination") String destination,
                     @Headers Map<String, Object> headers,
                     @DestinationVariable long id,
                     @Payload String body) {
        log.info("[test] Message: {}", message);
        log.info("[test] MessageHeaders: {}", MessageHeaders);
        log.info("[test] Header: {}", destination);
        log.info("[test] Headers: {}", headers);
        log.info("[test] DestinationVariable: {}", id);
        log.info("[test] Payload: {}", body);
    }
 
    // ---------------------- 广播推送 ----------------------
    @MessageMapping("/send")
    public void hello(@Payload String body) {
        print(body);
        simpMessagingTemplate.convertAndSend("/topic/accept", "reply hello");
    }

    // ---------------------- 对点推送 ----------------------
    @MessageMapping("/sendUser/info")
    public void hello3(@Payload String body, Principal principal) {
        print(body);
        print(principal);
        simpMessagingTemplate.convertAndSendToUser(principal.getName(), "/topic/acceptUser", "reply hello3");
    }
    private void print(Object data) {
        log.error("receive message body: {}", data);
    }
}

js:

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Stomp Demo Test</title>
    <link rel="stylesheet" href="../static/css/main.css"/>
    <script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.js"></script>
    <script>
        var username = '54F05DAA-4BBD-496E-B8B0-288A8337F4B9';
        var sendMessage = null;
        var disConnect = null;

        function connect() {
            var client = Stomp.client('wss://test.zflzqy.cn:8080/ws/websocket');
            client.heartbeat.outgoing = 5000;
            client.heartbeat.incoming = 0;

            client.connect({
                username: username
            }, function (succ) {
                console.log('client connect success:', succ);
                updateState('连接成功');

                // 订阅广播
                client.subscribe("/topic/accept", onMessage);
                // 订阅消息
                client.subscribe("/user/topic/acceptUser", onMessage);
            }, function (error) {
                console.log('client connect error:', error);
                updateState('连接失败');
            });
            // destination 如果是广播,页面就填/app/send,如果是个人页面就填:/user/sendUser/info
            // 注意广播只能以app开头,但是后端的发送以topic开头,ws会自己把app缓存topic
            // 单对单只能以user开头,且除去user前缀后的地址必须有2个斜线(傻逼ws),且前端订阅地址必须是/user/topic开头
            sendMessage = function (destination, headers, body) {
                client.send(destination, headers, body)
            };
            disConnect = function () {
                client.disconnect();
                console.log('client connect break')
            }
        }

        function onMessage(message) {
            console.log(message);
            insertChat(false, message.headers.destination, message.body)
        }

        function send() {
            var destination = document.getElementById("destination").value;
            var body = document.getElementById("content").value;
            if (sendMessage == null) {
                alert('ws connect break');
                return;
            }
            console.log(destination)
            sendMessage(destination, {}, body);
            insertChat(true, destination, body)
        }

        function updateState(state) {
            document.getElementById("state").innerHTML = state;
        }

        function insertChat(isLeft, destination, body) {
            var p = document.createElement('p');
            if (isLeft) {
                p.setAttribute('class', 'p-left');
            } else {
                p.setAttribute('class', 'p-right');
            }
            console.log(destination)
            p.innerHTML = destination + '<br/>' + body;
            document.getElementById("chat").appendChild(p);
        }

    </script>
</head>
<body>
<div class="body-left">
    <div id="state">未连接</div>
    <button id="connect" onclick="connect()">连接</button>
    <button id="disConnect" onclick="disConnect()">断开</button>
    <div>
        <input id="destination" type="text" placeholder="destination"/>
        <textarea id="content" rows="10", placeholder="payload"></textarea>
        <button id="send" onclick="send()">发送</button>
    </div>
    <div>
    </div>
</div>
<div id="chat" class="body-right">
    <p class="p-left">client message ...</p>
    <p class="p-right">server message ...</p>
</div>
</body>
</html>

css:

* {
    margin: 0;
    padding: 0;
}

body {
    width: 100%;
    height: 100%;
}

.body-left, .body-right {
    width: 50%;
    height: 100%;
    box-sizing: border-box;
    text-align: center;
    padding: 20px;
    /*display: inline-block;*/
    float: left;
}

.body-left {
    border-right: 1px solid #ccc;
}

p + p{
    margin-top: 20px
}

.p-left {
    text-align: left;
}

.p-right {
    text-align: right;
}

#state {
    padding-bottom: 20px;
    border-bottom: 1px solid #eee;
}

button {
    width: 100px;
    height: 40px;
    background-color: #1b7ef9;
    display: block;
    border-radius: 5px;
    margin: 10px auto;
    line-height: 40px;
    color: #fff;
    font-size: 16px;
}

input, textarea {
    display: block;
    margin: 10px auto;
    padding: 10px;
    width: 90%;
    border-radius: 5px;
    -webkit-appearance: none;
    outline: none;
    border: 1px solid #ccc;
}