目录
一. 写本文的初衷
学习如何使用 WebSocket 技术,了解Java全双端通信。通过实践下面这个实例,以便于更好的理解。(最后附上了本demo的gitee地址,有需要可以随时下载)
二. 实例概述
使用单例模式+WebSocket向前端用户提示需要处理的消息数量。这里的单例模式用来存储消息的数量,将初始数量设置为10。这里的"+"号和"-"是一个抽象的概念,泛指用户在某数据上做的操作使得该数据增加或减少。
三. 开始实践
1. 引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
<relativePath/>
</parent>
<dependencies>
<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>
<dependencies>
2. Websocket 相关配置
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3. 创建消息数量单例
由于此单例需要频繁使用,所以创建为饿汉式单例。
public class CountSingle {
private Integer count = 10;
private final static CountSingle countSingle = new CountSingle();
public static Integer getCount() {
return getInstance().count;
}
public static synchronized void setCount(OperEnum operEnum) {
if (operEnum == OperEnum.ADD) {
getInstance().count++;
}
if (operEnum == OperEnum.SUB) {
getInstance().count--;
}
}
public static CountSingle getInstance() {
return countSingle;
}
}
4. 创建操作枚举
此枚举分别对应用户做的加或减操作
public enum OperEnum {
ADD(1), SUB(2);
private final Integer code;
OperEnum(int code) {
this.code = code;
}
public Integer getCode() {
return code;
}
}
5. 主要服务类
这里主要说两个重要的方法:
<1> sendMessage
向当前会话主体对象发送信息
<2> broadcast
向所有会话主体对象广播信息
@Component
@ServerEndpoint("/websocket")
public class WebSocketServer {
private static final CopyOnWriteArraySet<WebSocketServer> connections = new CopyOnWriteArraySet<>();
private Session session;
@OnOpen
public void onOpen(Session session) {
this.session = session;
connections.add(this);
this.sendMessage(String.valueOf(CountSingle.getCount()));
System.out.println("新建连接: " + session.getId());
}
@OnClose
public void onClose() {
connections.remove(this);
System.out.println("连接关闭: " + session.getId());
}
@OnError
public void onError(Throwable error) {
error.printStackTrace();
}
private void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void broadcast(String message) {
for (WebSocketServer client : connections) {
client.sendMessage(message);
}
}
}
6. 消息数量单例控制器
@RestController
public class CountController {
@GetMapping("add")
public void add() {
CountSingle.setCount(OperEnum.ADD);
WebSocketServer.broadcast(String.valueOf(CountSingle.getCount()));
}
@GetMapping("sub")
public void sub() {
CountSingle.setCount(OperEnum.SUB);
WebSocketServer.broadcast(String.valueOf(CountSingle.getCount()));
}
}
7. 前端页面
<1>页面结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="/lib/jquery-3.4.1.min.js"></script>
<script src="/lib/layui-v2.5.5/layui.js"></script>
<link rel="stylesheet" href="/lib/layui-v2.5.5/css/layui.css">
<style>
div {
text-align: center;
}
</style>
</head>
<body>
<div>
<button class="layui-btn layui-btn-sm layui-btn-normal" onclick="add()">+</button>
<button class="layui-btn layui-btn-sm layui-btn-warm" onclick="sub()">-</button>
<button class="layui-btn">查看消息<span class="layui-badge layui-bg-gray" id="count"></span></button>
</div>
<2>js部分
let socket = new WebSocket("ws://localhost:8080/websocket");
socket.onmessage = function (event) {
$("#count").text(event.data);
};
function add() {
$.ajax({
url: '/add', // 请求的 URL
type: 'GET', // 请求方法:GET、POST 等
dataType: 'json', // 预期服务器返回的数据类型
});
}
function sub() {
$.ajax({
url: '/sub', // 请求的 URL
type: 'GET', // 请求方法:GET、POST 等
dataType: 'json', // 预期服务器返回的数据类型
});
}
8. 效果展示
这里需要使用两个浏览器才能看到效果。
websocket测试
项目gitee地址:WebsocketTest: 本系统做一个简单的应用,使用单例模式+WebSocket向前端提示需要处理的消息数量。