本文主要介绍如何通过netty来手写一套简单版的HTTP服务器,同时将关于netty的许多细小知识点进行了串联,用于巩固和提升对于netty框架的掌握程度。
服务器运行效果
服务器支持对静态文件css,js,html,图片资源的访问。通过网络的形式对这些文件可以进行访问,相应截图如下所示:
支持对于js,css,html等文件的访问:
然后引用相应的pom依赖文件信息:
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.6.Final</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.13</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.6</version> </dependency> 复制代码
导入依赖之后,新建一个包itree.demo(包名可以自己随便定义)
定义一个启动类WebApplication.java(有点类似于springboot的那种思路)
package itree.demo; import com.sise.itree.ITreeApplication; /** * @author idea * @data 2019/4/30 */ public class WebApplication { public static void main(String[] args) throws IllegalAccessException, InstantiationException { ITreeApplication.start(WebApplication.class); } } 复制代码
在和这个启动类同级别的包底下,建立itree.demo.controller和itree.demo.filter包,主要是用于做测试:
建立一个测试使用的Controller:
package itree.demo.controller; import com.sise.itree.common.BaseController; import com.sise.itree.common.annotation.ControllerMapping; import com.sise.itree.core.handle.response.BaseResponse; import com.sise.itree.model.ControllerRequest; /** * @author idea * @data 2019/4/30 */ @ControllerMapping(url = "/myController") public class MyController implements BaseController { @Override public BaseResponse doGet(ControllerRequest controllerRequest) { String username= (String) controllerRequest.getParameter("username"); System.out.println(username); return new BaseResponse(1,username); } @Override public BaseResponse doPost(ControllerRequest controllerRequest) { return null; } } 复制代码
这里面的BaseController是我自己在Itree包里面编写的接口,这里面的格式有点类似于javaee的servlet,之前我在编写代码的时候有点参考了servlet的设计。(注解里面的url正是匹配了客户端访问时候所映射的url链接)
编写相应的过滤器:
package itree.demo.filter; import com.sise.itree.common.BaseFilter; import com.sise.itree.common.annotation.Filter; import com.sise.itree.model.ControllerRequest; /** * @author idea * @data 2019/4/30 */ @Filter(order = 1) public class MyFilter implements BaseFilter { @Override public void beforeFilter(ControllerRequest controllerRequest) { System.out.println("before"); } @Override public void afterFilter(ControllerRequest controllerRequest) { System.out.println("after"); } } 复制代码
通过代码的表面意思,可以很好的理解这里大致的含义。当然,如果过滤器有优先顺序的话,可以通过@Filter注解里面的order属性进行排序。搭建起多个controller和filter之后,整体项目的结构如下所示:
基础的java程序写好之后,便是相应的resources文件了:
这里提供了可适配性的配置文件,默认配置文件命名为resources的config/itree-config.properties文件:
暂时可提供的配置有以下几个:
server.port=9090 index.page=html/home.html not.found.page=html/404.html 复制代码
结合相应的静态文件放入之后,整体的项目结构图如下所示:
这个时候可以启动之前编写的WebApplication启动类
启动的时候控制台会打印出相应的信息:
启动类会扫描同级目录底下所有带有@Filter注解和@ControllerMapping注解的类,然后加入指定的容器当中。(这里借鉴了Spring里面的ioc容器的思想)
启动之后,进行对于上述controller接口的访问测试,便可以查看到以下信息的内容:
同样,我们查看控制台的信息打印:
controller接收数据之前,通过了三层的filter进行过滤,而且过滤的顺序也是和我们之前预期所想的那样一直,按照order从小到大的顺序执行(同样我们可以接受post类型的请求)
除了常规的接口类型数据响应之外,还提供有静态文件的访问功能:
对于静态文件里面的html也可以通过网络url的形式来访问:
home.html文件内容如下所示:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> this is home </body> </html> 复制代码
我们在之前说的properties文件里面提及了相应的初始化页面配置是:
index.page=html/home.html 复制代码
因此,访问的时候默认的http://localhost:9090/就会跳转到该指定页面:
假设不配置properties文件的话,则会采用默认的页面跳转,默认的端口号8080
默认的404页面为