WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
最近做的系统中,也涉及到websocket的使用,打算在这里记录一下相关知识,本篇博客主要包括:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
package com.learn.websocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint("/websocketlearn/{id}") // websocket连接url
@Component
public class WebSocketServer {
private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
//存储当前server对象到map集合中
private static final Map<String, WebSocketServer> clientMap = new ConcurrentHashMap<String, WebSocketServer>();
// 当前会话
private Session session;
/**
* websocket建立连接成功时调用
*
* @param id
*/
@OnOpen
public void onOpen(@PathParam("id") String id, Session session) {
log.info("连接成功!");
this.session = session;
clientMap.put(id, this);
}
/**
* 关闭连接时调用
*/
@OnClose
public void onClose(Session session) {
log.info("关闭连接");
}
/**
* 接收到客户端消息以后调用
*
* @param message
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("接收到消息:" + message);
}
/**
* 发生异常时调用
*
* @param throwable
*/
@OnError
public void onError(Session session, Throwable throwable) {
log.info("连接异常!" + throwable);
}
/**
* 向指定id的客户端发送消息
*
* @param id
* @param message
*/
public void sendMessageToId(String id, String message) {
WebSocketServer webSocketServer = clientMap.get(id);
if (webSocketServer != null) {
webSocketServer.session.getAsyncRemote().sendText(message);
}
}
/**
* 给所有用户进行推送信息
*
* @param message 推送的信息
*/
public void sendMessageAll(String message) {
for (WebSocketServer item : clientMap.values()) {
item.session.getAsyncRemote().sendText(message);
}
}
}
@Configuration
public class WebSocketConfig {
/**
* 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
@RestController
@RequestMapping("/wsServer")
public class WebSocketController {
@Autowired
public WebSocketServer webSocketServer;
/**
* 给指定的用户推送信息
*
* @param id
* @param message
*/
@GetMapping("/sendToClient")
public void sendTo(String id, String message) {
webSocketServer.sendMessageToId(id, message);
}
/**
* 给所有用户推送信息
*
* @param msg 想要推送给用户的信息
*/
@GetMapping("/sendAllClient")
public void sendAll(String msg) {
webSocketServer.sendMessageAll(msg);
}
}
org.springframework.boot</groupId>
spring-boot-starter-web</artifactId>
</dependency>
org.java-websocket</groupId>
Java-WebSocket</artifactId>
1.5.1</version>
</dependency>
org.springframework.boot</groupId>
spring-boot-starter-test</artifactId>
test</scope>
</dependency>
server.port=8081
package com.learn.websocket;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
public class MyWebSocketClient extends WebSocketClient {
private static final Logger log = LoggerFactory.getLogger(WebSocketClient.class);
public MyWebSocketClient(URI serverUri) {
super(serverUri);
}
@Override
public void onOpen(ServerHandshake serverHandshake) {
log.info("连接成功!");
}
@Override
public void onMessage(String s) {
log.info("接收到服务端数据:" + s);
}
@Override
public void onClose(int i, String s, boolean b) {
log.info("关闭连接" + s);
}
@Override
public void onError(Exception e) {
log.info("发生异常" + e);
}
}
public class WebSocketUtils {
private static final Logger log = LoggerFactory.getLogger(WebSocketUtils.class);
public static WebSocketClient webSocketClient(String id) {
try {
MyWebSocketClient webSocketClient = new MyWebSocketClient(new URI("ws://localhost:8080/websocketlearn/" + id));
webSocketClient.connect();
return webSocketClient;
} catch (URISyntaxException e) {
e.printStackTrace();
log.error("创建websocket连接出现异常!", e);
}
return null;
}
}
@RequestMapping("/wsclient")
@RestController
public class WebSocketController {
private static final String CURRENT_ID = "1";
WebSocketClient webSocketClient = WebSocketUtils.webSocketClient(CURRENT_ID);
@RequestMapping("sendhllo")
public void sendfirst(String message) {
if(webSocketClient != null){
webSocketClient.send("hello," + message + "!");
}
}
}
客户端启动时输出了日志:
查看服务端控制台日志:
已经实现了服务端和客户端正常通信。
编写websocket.html页面:
<html>
<head>
<meta charset="UTF-8">
<title>webSocketTesttitle>
head>
<body>
<input id="id" type="text" />
<button onclick="oppen()">连接服务器button>
<hr>
<input id="msg" type="text" />
<button onclick="sendMessage()">发送消息button>
<hr>
<button onclick="closeWebSocket()">关闭连接button>
<hr>
<div id="message">div>
body>
<script type="text/javascript">
var websocket = null;
//创建连接
function oppen(){
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window){
var id = document.getElementById('id').value;
if(id) {
//连接WebSocket节点
websockewt = new WebSocket("ws://localhost:8080/websocketlearn/" + id);
}else {
alert('请输入连接服务器的id')
}
}
else{
alert('Not support websocket')
}
//连接发生错误的回调方法
websockewt.onerror = function(){
setMessageInnerHTML("error");
};
//连接成功建立的回调方法
websockewt.onopen = function(event){
setMessageInnerHTML("open");
}
//接收到消息的回调方法
websockewt.onmessage = function(event){
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websockewt.onclose = function(){
setMessageInnerHTML("close");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function(){
websockewt.close();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML){
document.getElementById('message').innerHTML += innerHTML + '
';
}
}
//关闭连接
function closeWebSocket(){
websockewt.close();
}
//发送消息
function sendMessage(){
var message = document.getElementById('msg').value;
websockewt.send(message);
}
script>
html>
测试流程跟上面差不多,不做过多赘述,测试结果如下:
客户端:
访问链接:http://localhost:8080/wsServer/sendToClient?id=10&message=我很好啊,你呢。