WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
直接使用WebSocket或者SockJS协议显得特别繁琐。使用它的子协议STOMP,它是一个更高级别的协议,STMOP协议使用一个基于帧格式来定义消息,与HTTP的Request和Response类似。
SpringBoot对使用WebSocket提供了支持,配置源码在org.springframework.boot.autoconfigure.websocket包下。
/**
* 配置WebSocket
*/
@Configuration
//注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {//注册STOMP协议的节点(endpoint),并映射指定的url
//注册一个STOMP的endpoint,并指定使用SockJS协议
registry.addEndpoint("/endpointAric").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {//配置消息代理(Message Broker)
//广播式应配置一个/topic消息代理
registry.enableSimpleBroker("/topic");
}
}
/**
* webSocket控制器
*/
@Controller
public class WebSocketController {
@MessageMapping("/welcome") //当浏览器向服务端发送请求时,通过@MessageMapping映射/welcome这个地址,类似于@ResponseMapping
@SendTo("/topic/getResponse")//当服务器有消息时,会对订阅了@SendTo中的路径的浏览器发送消息
public AricResponse say(AricMessage message) {
try {
//睡眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new AricResponse("welcome," + message.getName() + "!");
}
}
<!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-1.11.3.min.js}"></script>
</head>
<body>
<noscript><h2 style="color:#ff0000">抱歉,您的浏览器不支持改功能!</h2></noscript>
<div>
<div>
<button id="connect" οnclick="connect();">连接</button>
<button id="disconnect" disabled="disabled" οnclick="disconnect();">断开连接</button>
</div>
<div id="conversationDiv">
<label>请输入您的姓名</label><input type="text" id="name" />
<button id="sendName" οnclick="sendName();">发送</button>
<p id="response"></p>
</div>
</div>
</body>
<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(){
var socket = new SockJS('/endpointAric'); //连接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);
});
});
}
function disconnect(){
if(stompClient != null) {
stompClient.disconnect();
}
setConnected(false);
console.log("Disconnected");
}
function sendName(){
var name = $("#name").val();
//通过stompClient.send向/welcome 目标(destination)发送消息,这个是在控制器的@MessageMapping中定义的
stompClient.send("/welcome",{},JSON.stringify({'name':name}));
}
function showResponse(message){
var response = $("#response");
response.html(message);
}
</script>
</html>
/**
* 配置viewController,为页面提供路径映射
*/
@Controller
public class WebMvcConfig extends WebMvcConfigurerAdapter{
/**
* 配置viewController,提供映射路径
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/webSocket").setViewName("/webSocket");
}
}
打开多个浏览器窗口连接服务器,就能收到广播消息了,明天看点对点