一、 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;
}