# netty-websocket-spring-boot-starter **Repository Path**: toocruel/netty-websocket-spring-boot-starter ## Basic Information - **Project Name**: netty-websocket-spring-boot-starter - **Description**: 轻量级、高性能的WebSocket框架 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 372 - **Created**: 2022-01-17 - **Last Updated**: 2022-01-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README netty-websocket-spring-boot-starter [![License](http://img.shields.io/:license-apache-brightgreen.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) =================================== [中文文档](https://github.com/YeautyYE/netty-websocket-spring-boot-starter/blob/master/README_zh.md) (Chinese Docs) ### About 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 ### Requirement - jdk version 1.8 or 1.8+ ### Quick Start - add Dependencies: ```xml org.yeauty netty-websocket-spring-boot-starter 0.12.0 ``` - annotate `@ServerEndpoint` on endpoint class,and annotate `@BeforeHandshake`,`@OnOpen`,`@OnClose`,`@OnError`,`@OnMessage`,`@OnBinary`,`@OnEvent` on the method. e.g. ```java @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` ### Annotation ###### @ServerEndpoint > declaring `ServerEndpointExporter` in Spring configuration,it will scan for WebSocket endpoints that be annotated with `ServerEndpoint` . > beans that be annotated with `ServerEndpoint` will be registered as a WebSocket endpoint. > all [configurations](#configuration) are inside this annotation ( e.g. `@ServerEndpoint("/ws")` ) ###### @BeforeHandshake > when there is a connection accepted,the method annotated with `@BeforeHandshake` will be called > classes which be injected to the method are:Session,HttpHeaders... ###### @OnOpen > when there is a WebSocket connection completed,the method annotated with `@OnOpen` will be called > classes which be injected to the method are:Session,HttpHeaders... ###### @OnClose > when a WebSocket connection closed,the method annotated with `@OnClose` will be called > classes which be injected to the method are:Session ###### @OnError > when a WebSocket connection throw Throwable, the method annotated with `@OnError` will be called > classes which be injected to the method are:Session,Throwable ###### @OnMessage > when a WebSocket connection received a message,the method annotated with `@OnMessage` will be called > classes which be injected to the method are:Session,String ###### @OnBinary > when a WebSocket connection received the binary,the method annotated with `@OnBinary` will be called > classes which be injected to the method are:Session,byte[] ###### @OnEvent > when a WebSocket connection received the event of Netty,the method annotated with `@OnEvent` will be called > classes which be injected to the method are:Session,Object ### Configuration > 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](#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 ### Configuration by application.properties > You can get the configurate of `application.properties` by using `${...}` placeholders. for example: - first,use `${...}` in `@ServerEndpoint` ```java @ServerEndpoint(host = "${ws.host}",port = "${ws.port}") public class MyWebSocket { ... } ``` - then configurate in `application.properties` ``` ws.host=0.0.0.0 ws.port=80 ``` ### Custom Favicon 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/ | + +- resources/ +- favicon.ico ``` ### Custom Error Pages 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/ | + +- resources/ +- public/ +- error/ | +- 404.html | +- 5xx.html +- ``` ### Multi Endpoint - base on [Quick-Start](#quick-start),use annotation `@ServerEndpoint` and `@Component` in 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 `ServerBootstrap` instance. - when the addresses are the same,but path is different,they will use the same `ServerBootstrap` instance. - 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 --- ### Change Log #### 0.8.0 - Auto-Configuration #### 0.9.0 - Support RESTful by `@PathVariable` - Get param by`@RequestParam` from query - Remove `ParameterMap` ,instead of `@RequestParam MultiValueMap` - Add `@BeforeHandshake` annotation,you can close the connect before handshake - Set sub-protocol in `@BeforeHandshake` event - Remove the `@Component` on endpoint class - Update `Netty` version to `4.1.44.Final` #### 0.9.1 - Bug fixed : it was null when using `@RequestParam MultiValueMap` to get value - Update `Netty` version to `4.1.45.Final` #### 0.9.2 - There are compatibility version under 0.8.0 that can configure the `ServerEndpointExporter` manully #### 0.9.3 - Bug fixed :when there is no `@BeforeHandshake` , NullPointerException will appear #### 0.9.4 - Bug fixed :when there is no `@BeforeHandshake` , `Session` in `OnOpen` is null #### 0.9.5 - Bug fixed :`Throwable` in `OnError` event is null #### 0.10.0 - Modified the default value of `bossLoopGroupThreads` to 1 - Supports configuring `useEventExecutorGroup` to 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 `Netty` version to `4.1.49.Final` #### 0.11.0 - When the `ServerEndpoint` class is proxied by CGLIB (as with AOP enhancement), it still works #### 0.12.0 - `@enableWebSocket` adds the `scanBasePackages` attribute - `@serverEndpoint` no longer depends on `@Component` - Update `Netty` version to `4.1.67.Final`