其实这个文章写得没啥技术含量,而且网上教程很多。
但是还是觉得用自己的语言表述出来,以后再用也不用一行代码一行代码的写了,直接cv就行了。
1.导包
<!-- netty socketio -->
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.13</version>
</dependency>
2.代码配置
这里需要两个配置类(我把socketio的配置信息都写在了类里而不是配置文件中)
- 启动类
@Component
@Order(value=1)
public class MyCommandLineRunner implements CommandLineRunner {
private final SocketIOServer server;
@Autowired
public MyCommandLineRunner(SocketIOServer server) {
this.server = server;
}
@Override
public void run(String... args) throws Exception {
server.start();
}
}
- 事件处理类
对于socket服务端来讲,其实事件就几个:- 客户端连接
- 客户端断开
- 客户端发来消息
- 给客户端发消息
然后首先说连接断开发来消息,都是可以知道是哪个客户端的。我这里是设置socket连接的参数 params来分辨是谁的。这里可以用来存具体的用户信息,token啥的都可以。
最后给客户端发消息大体上分两种:一种给某一个客户端发消息,还有一种是给所有用户或者某一类用户发消息。其实处理是一样的,只不过如果是所有用户则遍历全部客户端。
然后我直接贴代码:
@Component
public class MessageEventHandler {
@Autowired
public static SocketIOServer socketIoServer;
public static ConcurrentMap<String, SocketIOClient> socketIOClientMap = new ConcurrentHashMap<>();
@OnConnect
public void onConnect(SocketIOClient client) {
String params = client.getHandshakeData().getSingleUrlParam("params");
System.err.println(params + "已连接上");
System.err.println(client.getRemoteAddress());
System.err.println("客户端sessionid" + client.getSessionId());
// 存储SocketIOClient,用于发送消息
socketIOClientMap.put(params, client);
}
/**
* 客户端断开连接
*
* @param client
*/
@OnDisconnect
public void onDisconnect(SocketIOClient client) {
String params = client.getHandshakeData().getSingleUrlParam("params");
System.err.println(params + "已断开");
socketIOClientMap.remove(params);
}
/**
* 客户端事件
*
* @param client
* @param request
* @param data
*/
@OnEvent(value = "messageevent")
public void onEvent(SocketIOClient client, AckRequest request, String data) {
}
// 广播消息
public static boolean sendMsg(String event, String message) {
for (SocketIOClient client : socketIOClientMap.values()) {
if (client.isChannelOpen()) {
client.sendEvent(event, message);
}
}
return true;
}
}
如上,socket基本准备工作完成了,剩下的就是在启动类做一些具体的配置(这个配置可以用配置文件然后在代码中引用,但是我嫌麻烦,是直接在类中写的字面量,推荐配置文件吧)
socketio配置文件的基本配置:
# SocketIO配置
socketio:
# SocketIO端口
port: 9090
# 连接数大小
workCount: 100
# 允许客户请求
allowCustomRequests: true
# 协议升级超时时间(毫秒),默认10秒,HTTP握手升级为ws协议超时时间
upgradeTimeout: 10000
# Ping消息超时时间(毫秒),默认60秒,这个时间间隔内没有接收到心跳消息就会发送超时事件
pingTimeout: 60000
# Ping消息间隔(毫秒),默认25秒。客户端向服务器发送一条心跳消息间隔
pingInterval: 25000
# 设置HTTP交互最大内容长度
maxHttpContentLength: 1048576
# 设置最大每帧处理数据的长度,防止他人利用大数据来攻击服务器
maxFramePayloadLength: 1048576
我说了我是类中直接写的,然后在boot项目的启动类中加入启动代码:
@Bean
public SocketIOServer socketIOServer() {
com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
//这里注意,这不能写localhost。
config.setHostname("192.168.0.11");
config.setPort(9090);
config.setAuthorizationListener(new AuthorizationListener() {// 类似过滤器
@Override
public boolean isAuthorized(HandshakeData data) {
//可以有逻辑,我这里没写
return true;
}
});
final SocketIOServer server = new SocketIOServer(config);
return server;
}
@Bean
public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
return new SpringAnnotationScanner(socketServer);
}
最后附上一个前端测试页面(我也是在网上嫖的,都忘了是哪个帖子找到的了,在此感谢大佬):
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">
<title>websocket-java-socketio</title>
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.js"></script>
</head>
<body>
<h1>Socket.io Test</h1>
<div><p id="status">Waiting for input</p></div>
<div><p id="message">hello world!</p></div>
<button id="connect" onClick='connect()'/>Connect</button>
<button id="disconnect" onClick='disconnect()'>Disconnect</button>
<button id="send" onClick='send()'/>Send Message</button>
</body>
<script type="text/javascript">
/**
* 前端js的 socket.emit("事件名","参数数据")方法,是触发后端自定义消息事件的时候使用的,
* 前端js的 socket.on("事件名",匿名函数(服务器向客户端发送的数据))为监听服务器端的事件
**/
var socket = io.connect("http://192.168.0.11:9090?params=123");
var firstconnect = true;
function connect() {
if(firstconnect) {
//socket.on('reconnect', function(){ status_update("Reconnected to Server"); });
//socket.on('reconnecting', function( nextRetry ){ status_update("Reconnecting in "
//+ nextRetry + " seconds"); });
//socket.on('reconnect_failed', function(){ message("Reconnect Failed"); });
//firstconnect = false;
} else {
socket.socket.reconnect();
}
}
//监听服务器连接事件
socket.on('connect', function(){ status_update("Connected to Server"); });
//监听服务器关闭服务事件
socket.on('disconnect', function(){ status_update("Disconnected from Server"); });
//监听服务器端发送消息事件
socket.on('update', function(data) {
message(data)
//console.log("服务器发送的消息是:"+data);
});
//断开连接
function disconnect() {
socket.disconnect();
}
function message(data) {
document.getElementById('message').innerHTML = "Server says: " + data;
}
function status_update(txt){
document.getElementById('status').innerHTML = txt;
}
function esc(msg){
return msg.replace(/</g, '<').replace(/>/g, '>');
}
//点击发送消息触发
function send() {
console.log("点击了发送消息,开始向服务器发送消息")
var msg = "我很好的,是的.";
socket.emit('messageevent', {msgContent: msg});
};
</script>
</html>
这篇笔记就到这里,如果稍微帮到你了记得点个喜欢点个关注,也祝大家工作顺顺利利,生活健健康康!
网友评论