中文文档 (Chinese Docs)
netty-websocket-spring-boot-starter will help you develop WebSocket server by using Netty in spring-boot,it is easy to develop by using annotation like spring-websocket
- jdk version 17
- add Dependencies:
<dependency>
<groupId>org.yeauty</groupId>
<artifactId>netty-websocket-spring-boot-starter</artifactId>
<version>0.13.0</version>
</dependency>- annotate
@ServerEndpointon endpoint class,and annotate@BeforeHandshake,@OnOpen,@OnClose,@OnError,@OnMessage,@OnBinary,@OnEventon the method. e.g.
@ServerEndpoint(path = "/ws/{arg}")
public class MyWebSocket {
@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();
}
}
@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);
}
@OnClose
public void onClose(Session session) throws IOException {
System.out.println("one connection closed");
}
@OnError
public void onError(Session session, Throwable throwable) {
throwable.printStackTrace();
}
@OnMessage
public void onMessage(Session session, String message) {
System.out.println(message);
session.sendText("Hello Netty!");
}
@OnBinary
public void onBinary(Session session, byte[] bytes) {
for (byte b : bytes) {
System.out.println(b);
}
session.sendBinary(bytes);
}
@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;
}
}
}
}- use Websocket client to connect
ws://127.0.0.1:80/ws/xxx
declaring
ServerEndpointExporterin Spring configuration,it will scan for WebSocket endpoints that be annotated withServerEndpoint. beans that be annotated withServerEndpointwill be registered as a WebSocket endpoint. all configurations are inside this annotation ( e.g.@ServerEndpoint("/ws"))
when there is a connection accepted,the method annotated with
@BeforeHandshakewill be called
classes which be injected to the method are:Session,HttpHeaders...
when there is a WebSocket connection completed,the method annotated with
@OnOpenwill be called
classes which be injected to the method are:Session,HttpHeaders...
when a WebSocket connection closed,the method annotated with
@OnClosewill be called classes which be injected to the method are:Session
when a WebSocket connection throw Throwable, the method annotated with
@OnErrorwill be called classes which be injected to the method are:Session,Throwable
when a WebSocket connection received a message,the method annotated with
@OnMessagewill be called classes which be injected to the method are:Session,String
when a WebSocket connection received the binary,the method annotated with
@OnBinarywill be called classes which be injected to the method are:Session,byte[]
when a WebSocket connection received the event of Netty,the method annotated with
@OnEventwill be called classes which be injected to the method are:Session,Object
all configurations are configured in
@ServerEndpoint's property
| property | default | description |
|---|---|---|
| path | "/" | path of WebSocket can be aliased for value |
| host | "0.0.0.0" | host of WebSocket."0.0.0.0" means all of local addresses |
| port | 80 | port of WebSocket。if the port equals to 0,it will use a random and available port(to get the port Multi-Endpoint) |
| bossLoopGroupThreads | 0 | num of threads in bossEventLoopGroup |
| workerLoopGroupThreads | 0 | num of threads in workerEventLoopGroup |
| useCompressionHandler | false | whether add WebSocketServerCompressionHandler to pipeline |
| optionConnectTimeoutMillis | 30000 | the same as ChannelOption.CONNECT_TIMEOUT_MILLIS in Netty |
| optionSoBacklog | 128 | the same as ChannelOption.SO_BACKLOG in Netty |
| childOptionWriteSpinCount | 16 | the same as ChannelOption.WRITE_SPIN_COUNT in Netty |
| childOptionWriteBufferHighWaterMark | 64*1024 | the same as ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK in Netty,but use ChannelOption.WRITE_BUFFER_WATER_MARK in fact. |
| childOptionWriteBufferLowWaterMark | 32*1024 | the same as ChannelOption.WRITE_BUFFER_LOW_WATER_MARK in Netty,but use ChannelOption.WRITE_BUFFER_WATER_MARK in fact. |
| childOptionSoRcvbuf | -1(mean not set) | the same as ChannelOption.SO_RCVBUF in Netty |
| childOptionSoSndbuf | -1(mean not set) | the same as ChannelOption.SO_SNDBUF in Netty |
| childOptionTcpNodelay | true | the same as ChannelOption.TCP_NODELAY in Netty |
| childOptionSoKeepalive | false | the same as ChannelOption.SO_KEEPALIVE in Netty |
| childOptionSoLinger | -1 | the same as ChannelOption.SO_LINGER in Netty |
| childOptionAllowHalfClosure | false | the same as ChannelOption.ALLOW_HALF_CLOSURE in Netty |
| readerIdleTimeSeconds | 0 | the same as readerIdleTimeSeconds in IdleStateHandler and add IdleStateHandler to pipeline when it is not 0 |
| writerIdleTimeSeconds | 0 | the same as writerIdleTimeSeconds in IdleStateHandler and add IdleStateHandler to pipeline when it is not 0 |
| allIdleTimeSeconds | 0 | the same as allIdleTimeSeconds in IdleStateHandler and add IdleStateHandler to pipeline when it is not 0 |
| maxFramePayloadLength | 65536 | Maximum allowable frame payload length. |
| useEventExecutorGroup | true | Whether to use another thread pool to perform time-consuming synchronous business logic |
| eventExecutorGroupThreads | 16 | num of threads in bossEventLoopGroup |
| sslKeyPassword | ""(mean not set) | the same as server.ssl.key-password in spring-boot |
| sslKeyStore | ""(mean not set) | the same as server.ssl.key-store in spring-boot |
| sslKeyStorePassword | ""(mean not set) | the same as server.ssl.key-store-password in spring-boot |
| sslKeyStoreType | ""(mean not set) | the same as server.ssl.key-store-type in spring-boot |
| sslTrustStore | ""(mean not set) | the same as server.ssl.trust-store in spring-boot |
| sslTrustStorePassword | ""(mean not set) | the same as server.ssl.trust-store-password in spring-boot |
| sslTrustStoreType | ""(mean not set) | the same as server.ssl.trust-store-type in spring-boot |
| corsOrigins | {}(mean not set) | the same as @CrossOrigin#origins in spring-boot |
| corsAllowCredentials | ""(mean not set) | the same as @CrossOrigin#allowCredentials in spring-boot |
You can get the configurate of
application.propertiesby using${...}placeholders. for example:
- first,use
${...}in@ServerEndpoint
@ServerEndpoint(host = "${ws.host}",port = "${ws.port}")
public class MyWebSocket {
...
}- then configurate in
application.properties
ws.host=0.0.0.0
ws.port=80
The way of configure favicon is the same as spring-boot.If favicon.ico is presented in the root of the classpath,it will be automatically used as the favicon of the application.the example is following:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- favicon.ico
The way of configure favicon is the same as spring-boot.you can add a file to an /public/error
folder.The name of the error page should be the exact status code or a series mask.the example is following:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
| +- 5xx.html
+- <other public assets>
- base on Quick-Start,use annotation
@ServerEndpointand@Componentin classes which hope to become a endpoint. - you can get all socket addresses in
ServerEndpointExporter.getInetSocketAddressSet(). - when there are different addresses(different host or different port) in WebSocket,they will use different
ServerBootstrapinstance. - when the addresses are the same,but path is different,they will use the same
ServerBootstrapinstance. - when multiple port of endpoint is 0 ,they will use the same random port
- when multiple port of endpoint is the same as the path,host can't be set as "0.0.0.0",because it means it binds all of the addresses
- Auto-Configuration
- Support RESTful by
@PathVariable - Get param by
@RequestParamfrom query - Remove
ParameterMap,instead of@RequestParam MultiValueMap - Add
@BeforeHandshakeannotation,you can close the connect before handshake - Set sub-protocol in
@BeforeHandshakeevent - Remove the
@Componenton endpoint class - Update
Nettyversion to4.1.44.Final
- Bug fixed : it was null when using
@RequestParam MultiValueMapto get value - Update
Nettyversion to4.1.45.Final
- There are compatibility version under 0.8.0 that can configure the
ServerEndpointExportermanully
- Bug fixed :when there is no
@BeforeHandshake, NullPointerException will appear
- Bug fixed :when there is no
@BeforeHandshake,SessioninOnOpenis null
- Bug fixed :
ThrowableinOnErrorevent is null
- Modified the default value of
bossLoopGroupThreadsto 1 - Supports configuring
useEventExecutorGroupto run synchronous and time-consuming business logic in EventExecutorGroup, so that the I/O thread is not blocked by a time-consuming task - SSL supported
- CORS supported
- Update
Nettyversion to4.1.49.Final
- When the
ServerEndpointclass is proxied by CGLIB (as with AOP enhancement), it still works
@enableWebSocketadds thescanBasePackagesattribute@serverEndpointno longer depends on@Component- Update
Nettyversion to4.1.67.Final
- Fixed the issue where WebSocket compression was not working.
- Upgraded support for Spring Boot 3.
- Included the client's
Sec-WebSocket-Protocolin the response header. - When closing the connection, sends a
byecommand first instead of directly closing. - Updated
Nettyversion to4.1.118.Final.