目录:
css
一,Spring Boot集成WebSockethtml
二,声明WebSocket服务,发送接收消息前端
三,JavaScript建立WebSocket客户端java
四,增长SocketController,返回前端页面jquery
五,Spring Boot集成TioWebSocketgit
六,常见问题和解决方法github
WebSocket是创建在TCP协议上的全双工通讯链接。不一样于HTTP只能有客户端发送请求消息,WebSocket在客户端和后台服务创建链接后,双方均可以主动发送实时消息。web
在不少业务场景下,后台服务须要实时将数据推送到客户端,好比代驾定位系统,司机客户端定时发送位置信息到服务器,后台管理系统页面实时更新显示,这时就要使用WebSocket数据推送方式,并且不增长服务器负载压力。spring
项目下载:https://github.com/jextop/StarterApi浏览器
示例代码:https://github.com/rickding/HelloJava/tree/master/HelloSocket
代码文件 |
功能要点 |
|
Spring Boot集成WebSocket |
pom.xml |
引入WebSocket依赖:spring-boot-starter-websocket |
SocketConfig.java |
配置Bean,启动WebSocketServer |
|
SocketServer.java |
声明WebSocket服务,接收和发送消息 |
|
JavaScript建立WebSocket客户端 |
socket.html |
在前端页面中接收和发送消息 |
前端页面 |
SocketController.java |
返回前端页面 |
一,Spring Boot集成WebSocket
1. 新建Spring Boot项目时,选中WebSocket,将自动添加依赖。
2. 已有Spring Boot项目,能够在pom.xml中直接引用WebSocket Starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
3. 增长SocketConfig.java,启动WebSocketServer
@Configuration
public class SocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
二,声明WebSocket服务,接收和发送消息
1,增长SocketServer.java,声明服务地址
2,声明@OnMessage,接收消息
3,声明@OnOpen,客户端链接成功时,将session保存起来
4,声明@OnClose,客户端断开链接时,将session信息删除
5,封装sendMessage()函数,经过session推送消息到客户端
@ServerEndpoint("/ws/{uid}")
@Component
public class SocketServer {
private static ConcurrentHashMap<String, SocketServer> webSocketMap = new ConcurrentHashMap<>();
private Session session;
private String uid;
public static void sendMessage(String uid, String msg) {
System.out.printf("Send message: %s, %s\n", uid, msg);
if (StringUtils.isNotBlank(uid) && webSocketMap.containsKey(uid)) {
webSocketMap.get(uid).sendMessage(msg);
} else {
System.err.printf("Offline: %s\n", uid);
}
}
public void sendMessage(String msg) {
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
@OnMessage
public void onMessage(String msg, Session session) {
System.out.printf("Receive message: %s, %s, %s\n", uid, session.getId(), msg);
for (String uid : webSocketMap.keySet()) {
sendMessage(uid, String.format("%s消息: %s", uid.equals(this.uid) ? "本身" : "转发", msg));
}
}
@OnOpen
public void onOpen(Session session, @PathParam("uid") String uid) {
this.session = session;
this.uid = uid;
webSocketMap.put(uid, this);
System.out.printf("Online: %d, %s\n", webSocketMap.size(), uid);
sendMessage("链接成功");
}
@OnClose
public void onClose() {
webSocketMap.remove(uid);
System.out.printf("Offline 1, %s, online: %d\n", uid, webSocketMap.size());
}
}
三,JavaScript建立WebSocket客户端
1,判断浏览器是否支持WebSocket
2,建立客户端,链接服务器
3,增长消息接收函数
4,增长发送消息功能
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HelloSocket</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var socket;
function openSocket() {
if (typeof(WebSocket) === "undefined") {
$("#status").html("浏览器不支持WebSocket");
} else {
if (socket !== undefined) {
socket.close();
socket = undefined;
}
// 创建链接
var socketUrl = "ws://localhost:8080/ws/" + $("#uid").val();
socket = new WebSocket(socketUrl);
socket.onmessage = function (msg) {
$("#status").html(msg.data);
};
}
}
function sendMessage() {
if (socket === undefined) {
$("#status").html("请先链接Socket");
} else {
socket.send($("#msg").val() + ", " + new Date().getTime());
}
}
</script>
<body>
${msg}
<br/>uid: <div><input id="uid" name="uid" value="user_id"></div>
<br/>msg: <div><input id="msg" name="msg" value="Hello WebSocket"></div>
<br/>
<div>
<button onclick="openSocket()">链接Socket</button>
</div>
<br/>
<div>
<button onclick="sendMessage()">发送消息</button>
</div>
<br/>
<div><label id="status">Status</label></div>
</body>
</html>
四,增长SocketController,返回前端页面
@Controller
public class SocketController {
@RequestMapping("/ws")
public String ws(Model model){
model.addAttribute("msg","Web Socket!");
return "socket";
}
}
启动项目,浏览器打开页面,链接WebSocket服务,接收和发送消息。
五,Spring Boot集成TioWebSocket
tio-websocket是基于T-io 网络通信框架实现的开源websocket服务器,易于使用,没必要关心链接的维护问题,只要作好业务处理便可。
代码文件 |
功能要点 |
|
Spring Boot集成TioWebSocket |
pom.xml |
引入TioWebSocket依赖:tio-websocket-spring-boot-starter |
application.xml |
配置端口、超时等属性 |
|
TioMsgHandler.java |
实现IWsMsgHandler,接收和发送消息 |
|
JavaScript建立WebSocket客户端 |
tio.html |
在前端页面中接收和发送消息 |
前端页面 |
SocketController.java |
返回前端页面 |
1,在pom.xml中引入依赖
<dependency>
<groupId>org.t-io</groupId>
<artifactId>tio-websocket-spring-boot-starter</artifactId>
<version>3.6.0.v20200315-RELEASE</version>
</dependency>
2,在application.xml中配置端口、超时等属性
tio:
websocket:
server:
port: 8200
heartbeat-timeout: 3600000
3,增长TioMsgHandler.java,实现接收和发送消息功能
@Component
public class TioMsgHandler implements IWsMsgHandler {
@Autowired
private TioWebSocketServerBootstrap tioServer;
public void sendMessage(String msg) {
Tio.sendToAll(tioServer.getServerTioConfig(), WsResponse.fromText(msg, "utf-8"));
}
@Override
public Object onText(WsRequest wsRequest, String msg, ChannelContext channelContext) throws Exception {
System.out.printf("收到文本消息:%s\n", msg);
sendMessage(String.format("转发消息: %s", msg));
return String.format("收到消息: %s", msg);
}
@Override
public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) throws Exception {
System.out.printf("收到二进制数据:%d\n", bytes.length);
return null;
}
}
4,开发前端页面,JavaScript建立WebSocket客户端
5,SocketController.java返回前端页面
6,启动项目,看到WebSocket服务信息
六,常见问题和解决方法
l 运行单元测试时错误,不能建立Bean 'serverEndpointExporter'
IllegalStateException: javax.websocket.server.ServerContainer not available
解决:声明@SpringBootTest时指定webEnvironment参数。
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
缘由:WebSocket运行在servlet容器中,因此须要加载servlet容器。
webEnvironment为Spring Boot指定启动时的ApplicationContext, SpringBootTest.WebEnvironment.DEFINED_PORT表示内嵌的服务器将会在定义的端口启动。
l 运行单元测试时不能启动,Failed to load ApplicationContext
Web server failed to start. Port 8011 was already in use.
解决:服务端口被占用,若是项目已经启动,先停掉再运行测试。