# nio-simple-web **Repository Path**: da9527/nio-simple-web ## Basic Information - **Project Name**: nio-simple-web - **Description**: 用nio做个简单的web服务器 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-07-10 - **Last Updated**: 2026-04-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # NIO Simple Web Server 基于 Java NIO 实现的轻量级 Web 服务器,支持 HTTP 和 WebSocket 协议。 ## 特性 - ✅ 基于 NIO 的非阻塞 IO 模型 - ✅ 支持 HTTP 请求处理(GET/POST) - ✅ 支持静态资源服务 - ✅ 支持注解驱动的路由注册(@Path) - ✅ 支持依赖注入(@Component, @Inject) - ✅ 完整的 WebSocket 支持(连接管理、消息发送、广播) - ✅ 配置文件支持(app.properties) - ✅ Bean 容器管理 ## 快速开始 ### Maven 依赖 ```xml nio-simple-web https://raw.githubusercontent.com/daHaoShuai/nio-simple-web/main/repo ``` ```xml com.da nio-simple-web 1.0.1 ``` ### 基础示例 ```java public class App { public static void main(String[] args) { DApp app = new DApp(); app.use("/", ctx -> ctx.sendHtml("

hello world

")); app.listen(); } } ``` ### 注解方式注册路由 ```java public class App { public static void main(String[] args) { // 自动扫描加了@Path 注解并且实现了 Handler 接口的类,注册到路由表 DApp app = new DApp(App.class); app.listen(); // 获取配置文件中的信息 System.out.println(app.getCfgInfo("port")); } } @Path("/hello") public class IndexController implements Handler { @Override public void callback(Context ctx) { ctx.send("hello"); } } ``` ### 配置文件 在 `resources/app.properties` 中配置: ```properties #指定端口号 (默认从 8080 开始找可用的端口) port=8083 #指定 static 目录 (默认为 resources/static),用/分开文件夹,static 目录下的 index.html 访问路径为/ static=aaa/aaa ``` ### 依赖注入示例 ```java public class App { public static void main(String[] args) { DApp app = new DApp(App.class); app.use("/", ctx -> ctx.sendHtml("

hello world

")); // @Component 注册的 bean Dog dog = app.getBean("dog", Dog.class); System.out.println(dog); // @path 注解用路径表示 beanName IndexController bean = (IndexController) app.getBean("/hello"); System.out.println(bean); app.listen(); } } @Component("dog") public class Dog { @Inject("小黄") private String name; @Override public String toString() { return "Dog{" + "name='" + name + '\'' + '}'; } // getters and setters... } @Component("user") public class User { @Inject("杰哥") private String name; @Inject("dog") private Dog dog; // getters and setters... } @Path("/hello") public class IndexController implements Handler { @Inject("user") private User user; @Inject("20") private int age; // 如果没有@Inject 注解会尝试从请求参数中注入值 private String name; private int sex; @Override public void callback(Context ctx) { ctx.send(user.toString() + " name = " + name + " age = " + age + " sex = " + sex); } } ``` ### 处理 JSON 数据 ```java public class App { public static void main(String[] args) { final DApp app = new DApp(App.class); app.use("/aa", ctx -> { // post 请求传来的 json 字符串 final Object o = ctx.getParams().get("request-json-data"); System.out.println(o); ctx.send("ok"); }); app.listen(); } } ``` ### 实体类转 JSON ```java public class App { public static void main(String[] args) { // 把实体类列表转成 json 数组形式字符串 System.out.println(Utils.parseListToJsonString( Arrays.asList(new User("a"), new User("b"), new User("c")) )); // 输出:{"User":[{"name":"a"},{"name":"b"},{"name":"c"}]} } } class User { public String name; public User(String name) { this.name = name; } } ``` ## WebSocket 功能 ### 完整示例 #### 1. 创建 WebSocket 监听器 ```java import com.da.web.annotations.Component; import com.da.web.core.Context; import com.da.web.function.WsListener; import com.da.web.websocket.WebSocketManager; // 注册到容器,并且实现 WsListener 接口 @Component("ws") public class WsImpl implements WsListener { @Override public void onOpen(Context ctx) throws Exception { System.out.println("新客户端连接!当前连接数:" + WebSocketManager.getConnectionCount()); // 发送欢迎消息 WebSocketManager.sendMessage(ctx.getChannel(), "欢迎连接 WebSocket 服务器!"); } @Override public void onMessage(Context ctx, String message) throws Exception { System.out.println("收到客户端消息:" + message); // 回复消息 WebSocketManager.sendMessage(ctx.getChannel(), "服务器收到:" + message); // 或者广播给所有客户端 // WebSocketManager.broadcast("广播消息:" + message); } @Override public void onError(Context ctx, Exception e) { if (e == null) { System.out.println("客户端正常断开连接"); } else { System.out.println("连接错误:" + e.getMessage()); } } @Override public void onClose(Context ctx) throws Exception { System.out.println("连接关闭!当前连接数:" + WebSocketManager.getConnectionCount()); } } ``` #### 2. 注册 WebSocket 路由 ```java import com.da.web.annotations.Inject; import com.da.web.annotations.Path; import com.da.web.core.Context; import com.da.web.function.Handler; import com.da.web.function.WsListener; @Path("/ws") public class WebSocketController implements Handler { @Inject("ws") WsListener wsListener; @Override public void callback(Context ctx) throws Exception { // 注册监听器,完成 WebSocket 握手 ctx.setWsListener(wsListener); } } ``` #### 3. 前端测试页面 ```html WebSocket 测试

WebSocket 测试

状态:未连接
``` ### WebSocketManager API | 方法 | 说明 | |------|------| | `addConnection(SocketChannel, Context)` | 添加 WebSocket 连接 | | `removeConnection(SocketChannel)` | 移除并关闭连接 | | `getContext(SocketChannel)` | 获取连接的上下文 | | `hasConnection(SocketChannel)` | 检查连接是否存在 | | `getConnectionCount()` | 获取当前连接数 | | `sendMessage(SocketChannel, String)` | 向指定连接发送消息 | | `broadcast(String)` | 广播消息给所有客户端 | | `closeAll()` | 关闭所有连接 | ### WsListener 接口 ```java public interface WsListener { // 连接建立时调用(可选实现) default void onOpen(Context ctx) throws Exception { } // 收到消息时调用(必须实现) void onMessage(Context ctx, String message) throws Exception; // 发生错误或关闭时调用(必须实现) void onError(Context ctx, Exception e); // 连接关闭时调用(可选实现) default void onClose(Context ctx) throws Exception { } } ``` ## 项目结构 ``` src/main/java/com/da/web/ ├── annotations/ # 注解定义 │ ├── Component.java │ ├── Inject.java │ └── Path.java ├── bean/ # Bean 容器 │ └── BeanContainer.java ├── config/ # 配置管理 │ └── ServerConfig.java ├── constant/ # 常量定义 │ ├── HttpStatus.java │ └── ContentTypes.java ├── core/ # 核心类 │ ├── DApp.java # 服务器主类 │ └── Context.java # 请求上下文 ├── enums/ # 枚举类型 ├── exception/ # 异常处理 ├── function/ # 函数式接口 │ ├── Handler.java │ └── WsListener.java ├── io/ # IO 相关 │ └── StaticFileRegistry.java ├── router/ # 路由管理 │ ├── RouteRegistry.java │ └── RouteMapping.java ├── util/ # 工具类 │ └── Utils.java └── websocket/ # WebSocket 支持 └── WebSocketManager.java ``` ## 注意事项 1. **线程安全**:服务器使用 NIO 多路复用模型,支持高并发连接 2. **WebSocket 帧解析**:支持标准的 WebSocket 协议帧格式(包括掩码处理) 3. **连接管理**:使用 ConcurrentHashMap 和 CopyOnWriteArraySet 确保线程安全 4. **自动重连端口**:如果指定端口被占用,会自动尝试下一个可用端口 ## License MIT License