本文讲述 基于springboot + netty 实现websocket服务端搭建。
使用springboot 集成 netty-websocket-spring-boot-starter 来实现websocket
也有直接通过netty 代码方式实现的方式但是不推荐,传统方式暂时我还无法找到通过url的方式来进行路由区分的,需要每个业务场景定义一个端口。
netty代码方式实现地址:https://blog.csdn.net/qq825478739/article/details/126263050
需要了解netty的 请点击网址查看我总结的一些netty的介绍
netty介绍地址:还没完善后边不上
netty-websocket-spring-boot-starter gitee地址:https://gitee.com/Yeauty/netty-websocket-spring-boot-starter
<dependency>
<groupId>org.yeauty</groupId>
<artifactId>netty-websocket-spring-boot-starter</artifactId>
<version>0.9.5</version>
</dependency>
/**
* 当springboot 项目启动会通过自动装配 找到netty-websocket-spring-boot-starter 中META-INF 加载 NettyWebSocketAutoConfigure
* 通过@EnableWebSocket -> @Import({NettyWebSocketSelector.class})
* 在 NettyWebSocketSelector 中会创建 Bean ServerEndpointExporter 被Spring声明并使用
*
* ServerEndpointExporter 类通过Spring配置声明并被使用,
* ServerEndpointExporter 将会去扫描带有@ServerEndpoint 注解的类注册成为一个WebSocket断电。
* 所有的配置项都在这个@ServerEndpoint注解属性中 ( 如:@ServerEndpoint("/ws") )
*
*/
//TODO 不需要加Spring的注解加载, 多例的,每次请求过来都会创建一个新的可以通过。无参构造查看
// port 默认80 host默认 0.0.0.0
@ServerEndpoint(path = "/ws/{arg}",port = "80",host = "0.0.0.0")
public class MyWebSocket {
public MyWebSocket() {
System.out.println("通过这里可以看到 每次请求过来都会创建");
}
/**
* 当有新的连接进入时,对该方法进行回调 注入参数的类型 一般用不是 可以去掉
*
* @param session
* @param headers
* @param req
* @param reqMap
* @param arg
* @param pathMap
*/
@BeforeHandshake
public void handshake(Session session, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap){
session.setSubprotocols("stomp");
if (!"ok".equals(req)){
System.out.println("Authentication failed!");
session.close();
}
}
/**
* 当有新的WebSocket连接完成时,会调用这个方法
*
* @param session
* @param headers
* @param req
* @param reqMap
* @param arg
* @param pathMap
*/
@OnOpen
public void onOpen(Session session, HttpHeaders headers, @RequestParam String req, @RequestParam MultiValueMap reqMap, @PathVariable String arg, @PathVariable Map pathMap){
System.out.println("new connection");
System.out.println(req);
}
/**
* 当有WebSocket 关闭连接时 调用
*
* @param session
* @throws IOException
*/
@OnClose
public void onClose(Session session) throws IOException {
System.out.println("one connection closed");
}
/**
* 当有WebSocket 抛出异常 调用
*
* @param session
* @param throwable
*/
@OnError
public void onError(Session session, Throwable throwable) {
throwable.printStackTrace();
}
/**
* 当接收到字符串消息时,调用
* message 请求参数 只能用字符串接收否则会报错 类型转换异常
*
* @param session
* @param message
*/
@OnMessage
public void onMessage(Session session, String message) {
System.out.println(message);
//TODO 发送消息
session.sendText("Hello Netty!");
}
/**
* 当接收到二进制消息时 调用
*
* @param session
* @param bytes
*/
@OnBinary
public void onBinary(Session session, byte[] bytes) {
for (byte b : bytes) {
System.out.println(b);
}
session.sendBinary(bytes);
}
/**
* 当接收到Netty的事件时 调用
*
* @param session
* @param evt
*/
@OnEvent
public void onEvent(Session session, Object evt) {
if (evt instanceof IdleStateEvent) {
IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
switch (idleStateEvent.state()) {
case READER_IDLE:
System.out.println("read idle");
break;
case WRITER_IDLE:
System.out.println("write idle");
break;
case ALL_IDLE:
System.out.println("all idle");
break;
default:
break;
}
}
}
}
在使用过程中遇到一个问题 ,当 onMessage 方法 接收参数用对象接收的话会报错。
我以为@RequestParam