1、Request
public class DyyNettyRequest {
private ChannelHandlerContext ctx;
private HttpRequest httpRequest;
public DyyNettyRequest(ChannelHandlerContext ctx, HttpRequest httpRequest) {
this.ctx = ctx;
this.httpRequest = httpRequest;
}
public String getMethod() {
return httpRequest.getMethod().name();
}
public String getUrl() {
return httpRequest.getUri().split("\\?")[0];
}
public String getUri() {
return httpRequest.getUri();
}
public Map> getParameters(){
QueryStringDecoder decoder = new QueryStringDecoder(httpRequest.getUri());
return decoder.parameters();
}
public String getParameter(String paramName){
List params = getParameters().get(paramName);
if (paramName == null){
return null;
}else {
return params.get(0);
}
}
}
2、Response
public class DyyNettyResponse {
private ChannelHandlerContext ctx;
public DyyNettyResponse(ChannelHandlerContext ctx) {
this.ctx = ctx;
}
public void write(String outStr){
try {
if (StringUtils.isEmpty(outStr)){
return;
}
FullHttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.wrappedBuffer(outStr.getBytes(StandardCharsets.UTF_8))
);
response.headers().set("Content-Type","text/html").set("charset",StandardCharsets.UTF_8.name());
ctx.write(response);
} catch (Exception e) {
e.printStackTrace();
}finally {
ctx.flush();
ctx.close();
}
}
}
3、Servlet抽象类
public abstract class DyyNettyServlet{
public void service(DyyNettyRequest request, DyyNettyResponse response) throws Exception {
if ("GET".equalsIgnoreCase(request.getMethod())){
System.out.println(String.format("获取到请求地址:%s,请求参数:%s", request.getUri(), request.getParameters()));
doGet(request,response);
}else if ("post".equalsIgnoreCase(request.getMethod())){
System.out.println(String.format("获取到请求地址:%s,请求参数:%s", request.getUri(), request.getParameters()));
doPost(request,response);
}
}
public abstract void doGet(DyyNettyRequest request, DyyNettyResponse response) throws Exception;
public abstract void doPost(DyyNettyRequest request, DyyNettyResponse response) throws Exception;
}
4、Tomcat
public class DyyNettyTomcat {
private int port = 8080;
//缓存Servlet
private Map servletMapping = new HashMap<>();
private Properties webxml = new Properties();
private void init() {
//加载web.xml 到servletMapping缓存中
String webXml = "src/main/resources/web.properties";
try (
FileInputStream fin = new FileInputStream(webXml);
) {
webxml.load(fin);
for (Object k : webxml.keySet()) {
String key = k.toString();
if (key.endsWith(".url")) {
String servletName = key.replaceAll("\\.url$", "");
String url = webxml.getProperty(key);
String classNmae = webxml.getProperty(servletName + ".className");
//单线程 多实例
DyyNettyServlet servlet = (DyyNettyServlet) Class.forName(classNmae).newInstance();
servletMapping.put(url, servlet);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void start() {
//加载web.xml 将各个servlet实例放入servletMapping缓存中
init();
//处理连接,主线程组
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
//工作线程组
NioEventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap server = new ServerBootstrap();
server.group(bossGroup, workGroup)
//NIO服务端通道,主线程处理类
.channel(NioServerSocketChannel.class)
//工作线程处理,类似NIO例子中的handle方法
.childHandler(new ChannelInitializer() {
//客户端连接后的处理
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
//netty对http的封装,对顺序有要求
socketChannel.pipeline()
//责任链模式,双向链表 InBound、OutBound
//InBound 从上至下执行
//OutBound 由下至上执行
.addLast(new HttpResponseEncoder())
.addLast(new HttpRequestDecoder())
.addLast(new DyyNettyTomcatHandler());
}
})
//初始化服务器连接队列大小 这里分配最大队列128
.option(ChannelOption.SO_BACKLOG, 128)
//工作线程配置,保持长连接
.childOption(ChannelOption.SO_KEEPALIVE, true);
//启动服务器(并绑定端口),bind是异步操作,sync方法是等待异步操作执行完毕,通过isDone()等方法可以判断异步事件的执行情况
ChannelFuture future = server.bind(port).sync();
System.out.println(String.format("DyyNettyTomcat is started...,port:%s", port));
//通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
/**
*
*/
public class DyyNettyTomcatHandler extends ChannelHandlerAdapter {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest) {
HttpRequest httpRequest = (HttpRequest) msg;
DyyNettyRequest request = new DyyNettyRequest(ctx, httpRequest);
DyyNettyResponse response = new DyyNettyResponse(ctx);
String url = request.getUrl();
if (servletMapping.containsKey(url)) {
servletMapping.get(url).service(request, response);
} else {
response.write("404 - Not Found");
}
}
}
}
/**
* 启动类
*
* @param args
*/
public static void main(String[] args) {
new DyyNettyTomcat().start();
}
}
5、FirstServlet
public class FirstServlet extends DyyNettyServlet {
@Override
public void doGet(DyyNettyRequest request, DyyNettyResponse response) throws Exception {
doPost(request,response);
}
@Override
public void doPost(DyyNettyRequest request, DyyNettyResponse response) throws Exception {
response.write("Im First Servlet!");
}
}
6、SecondServlet
public class SecondServlet extends DyyNettyServlet {
@Override
public void doGet(DyyNettyRequest request, DyyNettyResponse response) throws Exception {
doPost(request,response);
}
@Override
public void doPost(DyyNettyRequest request, DyyNettyResponse response) throws Exception {
response.write("Im Second Servlet!");
}
}
7、web.properties
servlet.one.url=/FirstServlet.do
servlet.one.className=com.dyy.demo.tomcat.netty.FirstServlet
servlet.two.url=/SecondServlet.do
servlet.two.className=com.dyy.demo.tomcat.netty.SecondServlet
8、启动tomcat中的main方法,浏览器调用地址显示