手写简易Tomcat

手写简易Tomcat

  • 一、tomcat启动类
  • 二、Servlet、Request、Response
    • 1. `BaseServlet`
    • 2. `Request`
    • 3. `Response`
  • 三、自定义Servlet
    • 1. `web.properties`
    • 2. `FirstServlet、SecondeServelt`
  • 四、运行结果

在java中涉及网络通信的,底层都是Socket通信,可以用ServerSocket(也可使用ServerSocketChannel即NIO,或使用Netty)监听本地端口,在浏览器进行访问,其本质也是Socket通信,不过是基于HTTP协议,所以需要对接受的消息需要进行解码,发送消息时需要编码,添加消息头。

一、tomcat启动类

package com.zte;


import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class TomcatBootStrap {
     
    private int port = 8080;
    private ServerSocket server;
    private Map<String, BaseServlet> servletMapping = new HashMap<String, BaseServlet>();

    private Properties webxml = new Properties();

    private void init() {
     

        //加载web.xml文件,同时初始化 ServletMapping对象
        try {
     
            String WEB_INF = this.getClass().getResource("/").getPath();
            FileInputStream fis = new FileInputStream(WEB_INF + "web.properties");

            webxml.load(fis);

            for (Object k : webxml.keySet()) {
     

                String key = k.toString();
                if (key.endsWith(".url")) {
     
                    String servletName = key.replaceAll("\\.url$", "");
                    String url = webxml.getProperty(key);
                    String className = webxml.getProperty(servletName + ".className");
                    //单实例,多线程
                    BaseServlet obj = (BaseServlet) Class.forName(className).newInstance();
                    servletMapping.put(url, obj);
                }

            }


        } catch (Exception e) {
     
            e.printStackTrace();
        }

    }

    public void start() {
     

        //加载配置文件,初始化url和servlet的映射关系
        init();

        try {
     
            server = new ServerSocket(this.port);

            System.out.println("GP TomcatBootStrap 已启动,监听的端口是:" + this.port);

            //接受用户请求
            while (true) {
     
                Socket client = server.accept();
                //HTTP请求,发送的数据就是字符串,有规律的字符串(HTTP协议)
                process(client);
                client.close();
            }

        } catch (Exception e) {
     
            e.printStackTrace();
        }
    }

    private void process(Socket client) throws Exception {
     

        try (
                InputStream is = client.getInputStream();
                OutputStream os = client.getOutputStream()
        ) {
     
            //Request(InputStrean)/Response(OutputStrean)
            Request request = new Request(is);
            Response response = new Response(os);

            //从协议内容中拿到URL,把相应的Servlet用反射进行实例化
            String url = request.getUrl();

            if (servletMapping.containsKey(url)) {
     
                //调用实例化对象的service()方法,执行具体的逻辑doGet/doPost方法
                servletMapping.get(url).service(request, response);
            } else {
     
                response.write("404 - Not Found");
            }
            os.flush();
        }
    }

    public static void main(String[] args) {
     
        new TomcatBootStrap().start();
    }

}

二、Servlet、Request、Response

1. BaseServlet

package com.zte;

import java.io.IOException;

public abstract class BaseServlet {
     
    public void service(Request request, Response response) throws IOException {
     
        if ("GET".equals(request.getMethod())) {
     
            doGet(request, response);
        }
    }

    protected abstract void doGet(Request request, Response response) throws IOException;

    protected abstract void doPost(Request request, Response response) throws IOException;
}

2. Request

对请求的输入流进行解析

package com.zte;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Request {
     
    private String method;
    private String url;

    public Request(InputStream req) {
     
        try {
     
            BufferedReader reqReader = new BufferedReader(new InputStreamReader(req));
            String line = reqReader.readLine();
            String[] strings = line.split("\\s");
            this.method = strings[0];
            //去除参数
            this.url = strings[1].split("\\?")[0];
        } catch (Exception e
        ) {
     
            e.printStackTrace();
        }
    }

    public String getMethod() {
     
        return method;
    }

    public void setMethod(String method) {
     
        this.method = method;
    }

    public String getUrl() {
     
        return url;
    }

    public void setUrl(String url) {
     
        this.url = url;
    }
}

3. Response

对输出添加消息头,使得浏览器可以解析

package com.zte;

import java.io.IOException;
import java.io.OutputStream;

public class Response {
     
    private OutputStream resp;

    public Response(OutputStream resp) {
     
        this.resp = resp;
    }

    public OutputStream getResp() {
     
        return resp;
    }

    public void setResp(OutputStream resp) {
     
        this.resp = resp;
    }

    public void write(String content) throws IOException {
     
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.1 200 OK\n")
                .append("Content-Type: text/html;\n")
                .append("\r\n")
                .append(content);
        resp.write(sb.toString().getBytes());
    }
}

三、自定义Servlet

1. web.properties

servlet.one.url=/first
servlet.one.className=com.zte.FirstServlet

servlet.two.url=/second
servlet.two.className=com.zte.SecondServlet

2. FirstServlet、SecondeServelt

package com.zte;

import java.io.IOException;

public class FirstServlet extends BaseServlet{
     
    @Override
    protected void doGet(Request request, Response response) throws IOException {
     
        doPost(request,response);
    }

    @Override
    protected void doPost(Request request, Response response) throws IOException {
     
        response.write("first servlet!");
    }
}


package com.zte;

import java.io.IOException;

public class SecondServlet extends BaseServlet{
     
    @Override
    protected void doGet(Request request, Response response) throws IOException {
     
        doPost(request,response);
    }

    @Override
    protected void doPost(Request request, Response response) throws IOException {
     
        response.write("second servlet!");
    }
}

四、运行结果

手写简易Tomcat_第1张图片

你可能感兴趣的:(框架初究,web容器,手写Tomcat,servlet,http,tomcat)