{"id":15294793,"url":"https://github.com/wanghongfei/springboot-starter-nettyweb","last_synced_at":"2025-07-08T19:07:56.534Z","repository":{"id":37134577,"uuid":"232283092","full_name":"wanghongfei/springboot-starter-nettyweb","owner":"wanghongfei","description":"一款基于SpringBoot、Netty开发的轻量级Web API框架","archived":false,"fork":false,"pushed_at":"2023-06-15T02:17:22.000Z","size":143,"stargazers_count":7,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-07T05:12:08.245Z","etag":null,"topics":["netty","springboot"],"latest_commit_sha":null,"homepage":"","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/wanghongfei.png","metadata":{"files":{"readme":"README.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-01-07T08:51:43.000Z","updated_at":"2023-03-05T05:44:32.000Z","dependencies_parsed_at":"2024-10-23T14:01:43.454Z","dependency_job_id":null,"html_url":"https://github.com/wanghongfei/springboot-starter-nettyweb","commit_stats":{"total_commits":45,"total_committers":2,"mean_commits":22.5,"dds":0.06666666666666665,"last_synced_commit":"b232cc42b1581684865f9d2c51bd2d01901ce267"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wanghongfei%2Fspringboot-starter-nettyweb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wanghongfei%2Fspringboot-starter-nettyweb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wanghongfei%2Fspringboot-starter-nettyweb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wanghongfei%2Fspringboot-starter-nettyweb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wanghongfei","download_url":"https://codeload.github.com/wanghongfei/springboot-starter-nettyweb/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252817653,"owners_count":21808707,"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":["netty","springboot"],"created_at":"2024-09-30T17:07:00.578Z","updated_at":"2025-05-07T05:12:16.842Z","avatar_url":"https://github.com/wanghongfei.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spring Boot Starter Netty Web\n\nNettyWeb是我**个人自用**的一款基于SpringBoot、Netty开发的轻量级Web API框架，最大的特点就是代码量少、实现简单，以稍微妥协易用性为代价**尽量少的使用反射**。\n\n\u003e 个人自用指的是，所有的私人项目和当公司不强制绑定技术栈时我都会使用。\n\n\n\nNettyWeb实现了一个Web框架所应该具有的最基本功能：\n\n- 请求路由\n- 参数绑定、验证\n- 为每一个请求自动生成唯一id, 方便日志统计\n\n同时，作为一个API框架，NettyWeb仅支持返回**JSON格式**的数据，不具备页面渲染功能。\n\n请求路由这块并没有使用Trie-Tree, 而是直接HashMap精确匹配，简单粗暴高性能。承认吧，其实绝大多数时候你并不需要`/item/{Id}`，也不需要`/item/*`，就算需要了，也有办法替换。\n\n\n\n## 快速开始\n\n在常规的SpringBoot2.x项目中加入以下依赖便可随Spring启动:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.wanghongfei\u003c/groupId\u003e\n    \u003cartifactId\u003espring-boot-starter-nettyweb\u003c/artifactId\u003e\n    \u003cversion\u003e1.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\u003e 已发布到中央仓库,可直接引用\n\n\n\nGet请求Demo: test目录下的DemoGetApi.java\n\nPost请求Demo: test目录下的DemoPostApi.java\n\n无参数请求Demo: test目录下的DemoEmptyApi.java\n\n带过滤器的请求Demo: test目录下的DemoAroundApi.java\n\n\n\n\n### 定义请求处理器\n\n为了避免使用反射，NettyWeb没有像SpringMVC那样支持将任意方法指定为请求处理器，而是必须定义一个类实现`RequestHandler`接口，同时加上`@HttpApi`注解，如：\n\n```java\n@HttpApi(path = \"/\", paramType = DemoRequest.class, method = \"POST\")\npublic class DemoApi implements RequestHandler\u003cDemoRequest, String\u003e {\n    @Override\n    public String serveRequest(DemoRequest request) {\n        return request.toString();\n    }\n}\n\n```\n\n在注解`@HttpApi`中：\n\n- path: 请求路径。这里是精确匹配，不支持通配符;\n- paramType: 参数对象类型。NettyWeb会自动将参数值绑定到对象的字段中; 如果此接口不需要参数，可以不赋值或者赋值为`Void.class`；\n- method: 请求方法，只支持`GET`, `POST`两个取值；\n\n`serveRequest()`是请求处理的入口方法，`DemoRequest`是用户自定义的参数对象，框架会自动将请求参数转换成此对象。\n\n当请求方法为`GET`时， NettyWeb会从URL里的`Query String`中解析参数并**忽略请求体**；如果是`POST`请求则会将请求体视为JSON并将其反序列化为参数对象。\n\n响应的JSON格式默认如下：\n\n```json\n{\n    \"code\": 0,\n    \"data\": \"this is data\",\n    \"message\": \"ok\"\n}\n```\n\n请求处理方法返回的业务数据对象会在`data`中体现，如果返回String, 则`data`的值是string类型，如果返回复杂对象，则`data`的值是object类型。\n\n\n\n### 实现Pre、Post过滤器\n\n让自己的请求处理器实现`AroundRequestHandler`可以实现类似于SpringMVC中过滤器的功能：\n\n```java\n@HttpApi(path = \"/around\", paramType = DemoRequest.class)\npublic class DemoAroundApi implements AroundRequestHandler\u003cDemoRequest, String\u003e {\n    @Override\n    public String serveRequest(DemoRequest request) {\n        System.out.println(\"middle\");\n        return \"ok\";\n    }\n\n    @Override\n    public boolean before(DemoRequest demoRequest, ChannelHandlerContext context) {\n        System.out.println(\"before\");\n\n        // 可直接写入响应数据\n        // context.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.copiedBuffer(\"break\", StandardCharsets.UTF_8)));\n\n        // false表示中断处理流程; 如果返回false, 务必保证已经通过context返回了适当的数据\n        // return false\n        return true;\n    }\n\n    @Override\n    public void after(DemoRequest demoRequest, String retObject) {\n        System.out.println(\"after\");\n\n    }\n}\n\n```\n\n其中，`before()`方法会在`serveRequest()`之前调用，如果返回`false`则表示终止后续处理。注意此时一定要用参数里传入的`context`引用给客户端返回适当的数据，否则此HTTP请求会无响应。\n\n`after()`方法会在`serveRequest()`之后调用，前提是`serveRequest()`正常返回没有跑出异常。\n\n\n\n### 修改响应Header\n\n如果需要修改响应头，则需要实现`RequestHander`的`default`方法`modifyHeader`：\n\n```java\n@HttpApi(path = \"/\", paramType = DemoRequest.class, method = \"POST\")\npublic class DemoApi implements RequestHandler\u003cDemoRequest, String\u003e {\n    @Override\n    public String serveRequest(DemoRequest request) {\n        return request.toString();\n    }\n    \n    @Override\n    public void modifyHeader(HttpHeaders headers, String data) {\n        headers.add(\"My-Header\", data);\n    }\n}\n```\n\n\n\n\n\n### 特定参数注入\n\n为了避免使用反射，NettyWeb通过探测参数对象是否实现了指定接口来\"注入\"一些特定参数，如完整的请求头和请求唯一id。\n\n如果需要获取框架给当前请求自动生成的唯一id, 可以让参数对象实现`InjectRequestId`接口：\n\n```java\npublic class DemoRequest implements InjectRequestId {\n    @JSONField(serialize = false, deserialize = false)\n    private Long requestId;\n    \n    @Override\n    public Long getRequestId() {\n        return requestId;\n    }\n\n    @Override\n    public void setRequestId(Long reqId) {\n        this.requestId = reqId;\n    }\n}\n```\n\n框架会调用`setRequestId(Long)`将id设置到参数对象中。如果嫌麻烦，可以直接继承`RequestIdVO`：\n\n```java\npublic class DemoRequest extends RequestIdVO {\n}\n```\n\n就不需要写前面一堆getXXX, setXXX了。\n\n如果想获取请求头，可以实现`InjectHeaders`接口:\n\n```java\npublic class DemoRequest implements InjectHeaders {\n    @JSONField(serialize = false, deserialize = false)\n    private Map\u003cString, String\u003e headerMap;\n\n    @Override\n    public Map\u003cString, String\u003e headerMap() {\n        return headerMap;\n    }\n\n    @Override\n    public void setHeaderMap(Map\u003cString, String\u003e map) {\n        this.headerMap = map;\n    }\n}\n\n```\n\n同样，如果嫌麻烦，可以直接继承`RequestHeaderVO`类：\n\n```java\npublic class DemoRequest extends RequestHeaderVO {\n}\n```\n\n\n\n### 参数验证\n\n这块如果不用反射会大大降低易用性，所以该反射还得反射。NettyWeb支持注解声明式的参数验证，如：\n\n```java\n@Validation // 启用注解验证\n@Data\npublic class DemoRequest {\n    @StringLen(min = 1,  max = 2, message = \"name长度1~2\")\n    private String name;\n\n    @StringCandidate(candidates = {\"boy\", \"girl\"}, message = \"boy/girl\")\n    private String gender;\n}\n```\n\n其中`@StringLen`表示`name`字段：\n\n- 不为null\n- 长度\u003e=1, 且\u003c=2\n- 当不满足要求时将message作为响应的一部分返回\n\n`@StringCandidate`表示`gender`字段：\n\n- 不为null\n- 值只能在`boy`或`girl`中二选一\n- 当不满足要求时将message作为响应的一部分返回\n\n\n\nNettyWeb支持的全部验证注解有：\n\n- @NutNull\n- @NumberSize(Short, Integer, Long的取值范围限制)\n- @CollectionNotEmpty\n- @StringCandidate\n- @StringLen\n- @StringReg(匹配正则表达式)\n\n如果参数对象的字段中还嵌套了一个复杂类型，NettyWeb同样支持递归验证，只需要在这个复杂字段上再次添加`@Validation`注解即可：\n\n```java\n@Validation // 启用注解验证\n@Data\npublic class DemoRequest {    \n    @NotNull\n    @Validation\n    private UserInfo userInfo;\n}\n```\n\n\n\n### 自定义响应数据格式\n\n如果默认的响应json格式不满足要求，可以继承框架的`NettyResponseBuilder`重新实现`buildResponseObject()`方法，然后注册为Spring Bean，如：\n\n```java\n@Component\npublic class MyResponseBuilder extends NettyResponseBuilder {\n    @Override\n    protected Object buildResponseObject(Object data, String message, int code) {\n        MyResponse response = new MyResponse();\n        response.setData(data);\n\n        return response;\n    }\n\n    @Data\n    public static class MyResponse {\n        private Object data;\n    }\n}\n```\n\n\n\n\n\n## 配置项\n\n```java\npublic class NettyWebProp {\n    private Integer port = 8080;\n  \n    /**\n     * netty boss线程数量\n     */\n    private Integer bossGroupThreadCount = 2;\n    /**\n     * netty worker线程数量\n     */\n    private Integer workGroupThreadCount = 0;\n\n    /**\n     * http请求最大字节数\n     */\n    private Integer httpObjectMaxSize = 1024 * 1024 * 5;\n    /**\n     * 用于标识登录状态的header名\n     */\n    private String loginTokenHeaderName = \"Login-Token\";\n\n    /**\n     * 业务线程池CoreSize\n     */\n    private Integer servicePoolCoreSize = 5;\n    /**\n     * 业务线程池MaxSize\n     */\n    private Integer servicePoolMaxSize = 10;\n    /**\n     * 业务线程池任务队列最大长度\n     */\n    private Integer servicePoolQueueSize = 50;\n\n    /**\n     * 是否启动Server\n     */\n    private Boolean startWebServer = true;\n}\n\n```\n\n\n\n## 单元测试\n\n如果在跑测试的时候不希望启动HTTP Server, 可以在配置文件中把`nettyweb.startwebServer`设为false:\n\n```yaml\nnettyweb:\n  start-web-server: false\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwanghongfei%2Fspringboot-starter-nettyweb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwanghongfei%2Fspringboot-starter-nettyweb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwanghongfei%2Fspringboot-starter-nettyweb/lists"}