什么是WebSocket
WebSocket 为 浏览器 和 服务 端 提供 了 双工 异步 通信 的 功能, 即 浏览器 可以向 服务 端 发送 消息, 服务 端 也可以 向 浏览器 发送 消息。 WebSocket 需 浏览器 的 支持, 如 IE 10+、 Chrome 13+、 Firefox 6+, 这对 我们 现在 的 浏览器 来说 都不 是 问题。 WebSocket 是 通过 一个 socket 来 实现 双工 异步 通信 能力 的。 但是 直接 使用 WebSocket( 或者 SockJS: WebSocket 协议 的 模拟, 增 加了 当 浏览器 不支持 WebSocket 的 时候 的 兼容 支持) 协议 开发 程序 显得 特别 烦琐, 我们 会使 用 它的 子 协议 STOMP, 它是 一个 更高 级别 的 协议, STOMP 协议 使用 一个 基于 帧( frame) 的 格式 来 定义 消息, 与 HTTP 的 request 和 response 类似( 具有 类似于@ RequestMapping 的@ MessageMapping)。
实战源码()
新建spring Boot项目,添加Thymeleaf 和 Websocket 依赖。
新建WebSocekt配置类WebSocketConfig.java,需要@EnableWebSocketMessageBroker开启WebSocket支持,并且继承AbstractWebSocketMessageBrokerConfigurer。源码如下:
/**
*
*/
package com.sunshuo.springboot_websocket;
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;
/**
* @ClassName: WebSocketConfig
* @Description: TODO(这里用一句话描述这个类的作用)
* @author SunShuo
* @date 2019年3月28日
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
/*
* (non-Javadoc)
*
* @see org.springframework.web.socket.config.annotation.
* WebSocketMessageBrokerConfigurer#registerStompEndpoints(org.
* springframework.web.socket.config.annotation.StompEndpointRegistry)
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
/*
* 注册STOPM协议的节点(endpoint),并映射的指定的URL
*/
/*
* 注册一个STOPM节点(endpoint),并指定使用SockJS协议
*/
registry.addEndpoint("/endpointWisely").withSockJS();
}
/*
* (non-Javadoc)
*
* @see org.springframework.web.socket.config.annotation.
* AbstractWebSocketMessageBrokerConfigurer#configureMessageBroker(org.
* springframework.messaging.simp.config.MessageBrokerRegistry)
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
/*
* 配置消息代理
*/
/*
* 广播式应配置一个/topic消息代理
*/
registry.enableSimpleBroker("/topic");
}
}
代码解释
① 通过@ EnableWebSocketMessageBroker 注解 开启 使用 STOMP 协议 来 传输 基于 代理( message broker) 的 消息, 这时 控制器 支持 使用@ MessageMapping, 就 像 使用@ RequestMapping 一样。
② 注册 STOMP 协议 的 节点( endpoint), 并 映射 的 指定 的 URL。
③ 注册 一个 STOMP 的 endpoint, 并 指定 使用 SockJS 协议。
④ 配置 消息 代理( Message Broker)。
⑤ 广播 式 应 配置 一个/ topic 消息 代理。
新建WiselyMessage类。浏览器向服务端发送消息用该类接收封装。
源码如下:
/**
*
*/
package com.sunshuo.springboot_websocket.domain;
/**
* @ClassName: WiselyMessage
* @Description: 浏览器想服务端发送和的消息由此类接受
* @author SunShuo
* @date 2019年3月28日
*/
public class WiselyMessage {
private String name;
public String getName() {
return name;
}
}
新建WiselyResponse类。服务端向浏览器发送消息用该类接收。
源码如下:
/**
*
*/
package com.sunshuo.springboot_websocket.domain;
/**
* @ClassName: WiselyResponse
* @Description: 服务端向浏览器发送消息
* @author SunShuo
* @date 2019年3月28日
*/
public class WiselyResponse {
private String responseMessage;
public WiselyResponse(String responseMessage) {
this.responseMessage = responseMessage;
}
public String getResponseMessage() {
return responseMessage;
}
}
新建一个WsController类当控制器。
/**
*
*/
package com.sunshuo.springboot_websocket;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import com.sunshuo.springboot_websocket.domain.WiselyMessage;
import com.sunshuo.springboot_websocket.domain.WiselyResponse;
/**
* @ClassName: WsController
* @Description: TODO(这里用一句话描述这个类的作用)
* @author SunShuo
* @date 2019年3月28日
*/
@Controller
public class WsController {
@MessageMapping("/welcome")
@SendTo("/topic/getResponse")
public WiselyResponse say(WiselyMessage wiselyMessage) throws Exception {
Thread.sleep(3000);
return new WiselyResponse("Welcome " + wiselyMessage.getName() + "!");
}
}
代码 解释
① 当 浏览器 向 服务 端 发送 请求 时, 通过@ MessageMapping 映射/ welcome 这个 地址, 类似于@ RequestMapping。
② 当 服务 端 有 消息 时, 会对 订阅 了@ SendTo 中的 路径 的 浏览器 发送 消息。 .
新建一个html页面用于演示,需要引入stomp. min. js( STOMP 协议 的 客户 端 脚本)、 sockjs. min. js( SockJS 的 客户 端 脚本) 以及 jQuery脚本,将脚本放在src/ main/ resources/ static下。
在src/ main/ resources/ templates 下新建ws. html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"></meta>
<title>Insert title here</title>
</head>
<body "disconnect()">
<noscript><h2 style="color:#FF0000">浏览器不支持websocket</h2></noscript>
<div>
<div>
<button id="connect" "connect();">连接</button>
<button id="disconnect" disabled="disabled" "disconnect();">断开链接</button>
</div>
<div id="conversationDiv">
<label>输入你的名字</label><input type="text" id="name" />
<button id="sendName" "sendName();">发送</button>
<p id="response"></p>
</div>
</div>
<script th:src="@{stomp.min.js}"></script>
<script th:src="@{sockjs.min.js}"></script>
<script th:src="@{jquery.min.js}"></script>
<script type="text/javascript">
var stopmClient = 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('/endpointWisely');
stopmClient = Stomp.over(socket);
stopmClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stopmClient.subscribe('/topic/getResponse', function(response) {
showResponse(JSON.parse(response.body).responseMessage);
});
});
}
function disconnect() {
if(stopmClient != null) {
stopmClient.disconnect();
}
setConnected(false);
console.log('disconnected. ');
}
function sendName() {
var name = $('#name').val();
stopmClient.send("/welcome", {}, JSON.stringify({'name': name}));
}
function showResponse(message) {
var response = $('#response');
response.html(message);
}
</script>
</body>
</html>
代码 解释
① 连接 SockJS 的 endpoint 名称 为“/ endpointWisely”。
② 使用 STOMP 子 协议 的 WebSocket 客户 端。
③ 连接 WebSocket 服务 端。
④ 通过 stompClient. subscribe 订阅/ topic/ getResponse 目标( destination) 发送 的 消息, 这个 是在 控制器 的@ SendTo 中 定义 的。
⑤ 通过 stompClient. send 向/ welcome 目标( destination) 发送 消息, 这个 是在 控制器 的@ MessageMapping 中 定义 的。
配置 viewController, 为 ws. html 提供 便捷 的 路径 映射:
源码如下:
/**
*
*/
package com.sunshuo.springboot_websocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* @ClassName: WebMvcConfig
* @Description: TODO(这里用一句话描述这个类的作用)
* @author SunShuo
* @date 2019年3月28日
*/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
/*
* (non-Javadoc)
*
* @see
* org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* #addViewControllers(org.springframework.web.servlet.config.annotation.
* ViewControllerRegistry)
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/ws").setViewName("/ws");
}
}
运行项目:
在浏览器中输入:http://localhost:8080/ws,打开3个界面,分别链接。然后在一个浏览器中输入消息并且发送,其他的浏览器接收消息。
其消息发送的格式为: