{"id":18879305,"url":"https://github.com/jdk-plus/spring-boot-starter-websocket","last_synced_at":"2026-01-31T11:31:29.706Z","repository":{"id":45799807,"uuid":"513962944","full_name":"JDK-Plus/spring-boot-starter-websocket","owner":"JDK-Plus","description":"A springboot websocket clustered message push component written by netty. 🏝✨","archived":false,"fork":false,"pushed_at":"2024-12-10T02:43:49.000Z","size":77,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-31T02:43:53.106Z","etag":null,"topics":["java","netty","springboot","websocket","websocket-server"],"latest_commit_sha":null,"homepage":"https://jdk.plus/spring-boot-starter-websocket/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JDK-Plus.png","metadata":{"files":{"readme":"README-CN.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-07-14T15:57:31.000Z","updated_at":"2024-12-10T02:43:53.000Z","dependencies_parsed_at":"2023-01-21T21:15:31.638Z","dependency_job_id":null,"html_url":"https://github.com/JDK-Plus/spring-boot-starter-websocket","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JDK-Plus%2Fspring-boot-starter-websocket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JDK-Plus%2Fspring-boot-starter-websocket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JDK-Plus%2Fspring-boot-starter-websocket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JDK-Plus%2Fspring-boot-starter-websocket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JDK-Plus","download_url":"https://codeload.github.com/JDK-Plus/spring-boot-starter-websocket/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239841743,"owners_count":19705981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","netty","springboot","websocket","websocket-server"],"created_at":"2024-11-08T06:35:11.306Z","updated_at":"2026-01-31T11:31:29.666Z","avatar_url":"https://github.com/JDK-Plus.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg align=\"center\" src=\"https://jdk.plus/img/jdk-plus.png\" alt=\"drawing\" style=\"width:100%;\"/\u003e\n\u003ch3 align=\"center\"\u003e这是一款使用netty编写的springboot websocket 集群化消息推送的组件。\u003c/h3\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/JDK-Plus/spring-boot-starter-websocket/blob/master/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/JDK-Plus/spring-boot-starter-websocket.svg\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/JDK-Plus/spring-boot-starter-websocket/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/release/JDK-Plus/spring-boot-starter-websocket.svg\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/JDK-Plus/spring-boot-starter-websocket/stargazers\"\u003e\u003cimg src=\"https://img.shields.io/github/stars/JDK-Plus/spring-boot-starter-websocket.svg\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/JDK-Plus/spring-boot-starter-websocket/network/members\"\u003e\u003cimg src=\"https://img.shields.io/github/forks/JDK-Plus/spring-boot-starter-websocket.svg\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e这是一款支持集群广播的使用netty编写的websocket组件,完美解决websocket和用户单机建立连接无法和整个业务集群通信的问题\u003c/p\u003e\n\n\n- [English](README-CN.md)\n\n\n## 如何引入\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eplus.jdk\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-starter-websocket\u003c/artifactId\u003e\n    \u003cversion\u003e1.1.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n## 配置\n\n```\nplus.jdk.websocket.enabled=true\n\n# 指定host\nplus.jdk.websocket.host=0.0.0.0\n\n# 指定websocket端口\nplus.jdk.websocket.port=10001\n\n\n# 指定自定义实现的验证器\nplus.jdk.websocket.session-authenticator=plus.jdk.broadcast.test.session.WSSessionAuthenticator\n\n# boss线程池线程数，默认为1\nplus.jdk.websocket.boss-loop-group-threads=1\n\n# worker线程池线程数,若不指定则默认为CPU核心数 * 2\nplus.jdk.websocket.worker-loop-group-threads=5\n\n# 是否需允许跨域\nplus.jdk.websocket.cors-allow-credentials=true\n\n# 跨域的header头\nplus.jdk.websocket.cors-origins[0]=\"\"\n\n# 是否使用 NioEventLoopGroup 来处理请求\nplus.jdk.websocket.use-event-executor-group=true\n\n# 指定 NioEventLoopGroup 线程池数量\nplus.jdk.websocket.event-executor-group-threads=0\n\n# 连接超时时间\n#plus.jdk.websocket.connect-timeout-millis=\n\n# 指定了内核为此套接口排队的最大连接个数\n#plus.jdk.websocket.SO_BACKLOG=\n\n# 旋转计数用于控制每次Netty写入操作调用基础socket.write(...)的次数\n#plus.jdk.websocket.write-spin-count=\n\n# 日志等级\nplus.jdk.websocket.log-level=debug\n\n# udp广播监听端口\nplus.jdk.websocket.broadcast-monitor-port=10300\n\n# udp广播监听端口，若小于等于0，则不监听消息\nplus.jdk.websocket.broadcast-monitor-port=10300\n\n# 是否将接收到的UDP广播信息打印到日志中\nplus.jdk.websocket.print-broadcast-message=true\n```\n\n\n## 使用示例\n\n\n### 根据自己的业务实现session认证相关逻辑\n\n#### 定义业务关于session的实现\n\n业务上session的定义必须实现`IWsSession` 接口。\n\n该接口封装了一个`userId`,该参数用户可以自定义其类型。还有一个channel，是当前机器与用户建立的连接\n\n```java\npackage plus.jdk.broadcast.test.session;\n\nimport io.netty.channel.Channel;\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport plus.jdk.websocket.model.IWsSession;\n\n@Data\n@AllArgsConstructor\npublic class MyWsSession implements IWsSession\u003cString\u003e {\n\n    private String userId;\n\n    private Channel channel;\n}\n```\n\n#### 自定义`Session`验证器\n\n验证器必须实现`IWSSessionAuthenticator`接口，使用示例如下：\n\n```java\nimport io.netty.channel.Channel;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport org.springframework.stereotype.Component;\nimport plus.jdk.broadcast.model.Monitor;\nimport plus.jdk.websocket.common.HttpWsRequest;\nimport plus.jdk.websocket.global.IWSSessionAuthenticatorManager;\nimport plus.jdk.websocket.model.IWsSession;\nimport plus.jdk.websocket.properties.WebsocketProperties;\n\n@Component\npublic class WSSessionAuthenticator implements IWSSessionAuthenticatorManager\u003cString, MyWsSession\u003e {\n\n    /**\n     * 握手阶段验证session信息，若验证不通过，直接抛出异常终止握手流程。\n     * 若验证成功，则返回自定义的session，并使用redis之类的公用存储服务记录当前用户和哪台机器建立了连接\n     */\n    @Override\n    public MyWsSession authenticate(Channel channel, FullHttpRequest req, String path, WebsocketProperties properties) {\n        HttpWsRequest httpWsRequest = new HttpWsRequest(req);\n        String uid = httpWsRequest.getQueryValue(\"uid\");\n        return new MyWsSession(uid, channel);\n    }\n\n    /**\n     * 当连接断开时，销毁session的回调\n     */\n    @Override\n    public void onSessionDestroy(IWsSession\u003c?\u003e session, String path, WebsocketProperties properties) {\n\n    }\n\n    /**\n     * 返回当前用户和哪些机器建立了连接，需要向这些机器发送广播推送消息\n     */\n    @Override\n    public Monitor[] getUserConnectedMachine(String userId, String path, WebsocketProperties properties) {\n        return new Monitor[]{new Monitor(\"127.0.0.1\", properties.getBroadcastMonitorPort())};\n    }\n}\n```\n\n**通过配置指定验证器组件**\n\n```\nplus.jdk.websocket.session-authenticator=plus.jdk.broadcast.test.session.WSSessionAuthenticator\n```\n\n\n### 编写相关业务逻辑\n\n如上文，当实现Session认证后，即可继续编写websocket的业务逻辑了。\n\n```java\npackage plus.jdk.broadcast.test.websocket;\n\nimport io.netty.channel.Channel;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpHeaders;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport plus.jdk.broadcast.test.session.MyWsSession;\nimport plus.jdk.websocket.annotations.*;\n\n@WebsocketHandler(values = {\"/ws/message\"})\npublic class DemoHandler {\n\n    @OnWsHandshake\n    public void doHandshake(FullHttpRequest req, MyWsSession session) {\n    }\n\n    @OnWsOpen\n    public void onOpen(Channel channel, FullHttpRequest req, MyWsSession session, HttpHeaders headers, @RequestParam String uid) {\n        session.sendText(\"onOpen\" + System.currentTimeMillis());\n    }\n\n    @OnWsMessage\n    public void onWsMessage(MyWsSession session, String data) {\n        session.sendText(\"onWsMessage\" + System.currentTimeMillis());\n        session.sendText(\"receive data\" + data);\n        session.sendText(\"onWsMessage, id:\" + session.getChannel().id().asShortText());\n    }\n\n    @OnWsEvent\n    public void onWsEvent(Object data, MyWsSession session) {\n        session.sendText(\"onWsEvent\" + System.currentTimeMillis());\n    }\n\n    @OnWsBinary\n    public void OnWsBinary(MyWsSession session, byte[] data) {\n        session.sendText(\"OnWsBinary\" + System.currentTimeMillis());\n    }\n\n    @OnWsError\n    public void onWsError(MyWsSession session, Throwable throwable) {\n        session.sendText(\"onWsError\" + throwable.getMessage());\n    }\n\n    @OnWsClose\n    public void onWsClose(MyWsSession session){\n        session.sendText(\"onWsClose\" + System.currentTimeMillis());\n    }\n}\n```\n\n### 使用websocket连接主动向用户客户端推送消息\n\n```java\npackage plus.jdk.broadcast.test.controller;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\nimport plus.jdk.websocket.global.SessionGroupManager;\nimport plus.jdk.websocket.model.IWsSession;\n\nimport javax.annotation.Resource;\nimport java.util.concurrent.ConcurrentLinkedDeque;\n\n\n@RestController\npublic class MessageController {\n\n    /**\n     * 该bean实例已经在底层封装好\n     */\n    @Resource\n    private SessionGroupManager sessionGroupManager;\n\n    @RequestMapping(value = \"/message/send\", method = {RequestMethod.GET})\n    public Object sendMessage(@RequestParam String uid, @RequestParam String content){\n        // 调用sessionGroupManager.getSession()函数获取当前用户在该实例中的所有连接\n        // 你可以在 IWSSessionAuthenticator 的实现中自行实现自己的session定义，将消息分发给不同的设备\n        // 或向远端上报当前用户的连接到底在哪些机器上\n        ConcurrentLinkedDeque\u003cIWsSession\u003c?\u003e\u003e sessions = sessionGroupManager.getSession(uid, \"/ws/message\");\n\n        // 发送文本消息\n        // 如果你按要求实现了IWSSessionAuthenticatorManager接口中的getUserConnectedMachine方法，那么将会向已经和用户建立连接的机器发送广播，推送消息\n\n        sessionGroupManager.sendText(uid, \"/ws/message\", content);\n\n        // 发送二进制消息\n        sessionGroupManager.sendBinary(uid, \"/ws/message\", content.getBytes(StandardCharsets.UTF_8));\n        return \"success\";\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdk-plus%2Fspring-boot-starter-websocket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjdk-plus%2Fspring-boot-starter-websocket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjdk-plus%2Fspring-boot-starter-websocket/lists"}