手写一个民用Tomcat (01)

写一个下民用版的Tomcat ,目的是相互学习一下 。

首先根据Servlet 协议顶一个接口

interface  JxdServlet {
    public void service(JxdRequest req, JxdResponse res) throws IOException;
}

我对接口的理解是 一种规范,我在开发的时候突然有点感悟,就是你开发一套系统,或者写一个小的业务,在你使用我这个系统、业务的时候,你要 遵守我的规范,怎么解释规范呢,就是用接口去理解。当别人看你代码的时候,通过看接口就能知道你的规范是啥 。

然后定义Request,和Response  

public class JxdRequest  {
    private InputStream input;
    private String uri;

    public JxdRequest(InputStream input) {
        this.input = input;
    }

    public void parse() {
        StringBuffer request = new StringBuffer(2048);
        int i;
        byte[] buffer = new byte[2048];
        try {
            i = input.read(buffer);
        } catch (IOException e) {
            e.printStackTrace();
            i = -1;
        }
        for (int j = 0; j < i; j++) {
            request.append((char) buffer[j]);
        }
        uri = parseUri(request.toString());
    }

    private static String parseUri(String requestString) {

        int index1, index2;
        index1 = requestString.indexOf(' ');
        if (index1 != -1) {
             index2 = requestString.indexOf(' ', index1 + 1);
             if (index2 > index1) return requestString.substring(index1 + 1, index2);
        }
        return null;
    }

    public String getUri() {
        return uri;
    }
}

public class JxdResponse {
    private static final int BUFFER_SIZE = 1024;
    JxdRequest request;

    OutputStream output;

    public OutputStream getOutput() {
        return output;
    }

    public void setOutput(OutputStream output) {
        this.output = output;
    }

    public JxdResponse(OutputStream output) {
        this.output = output;
    }

    public void setRequest(JxdRequest request) {
        this.request = request;
    }

    /**
     * 这个方法是静态方法演示,可以不关注
     * @throws IOException
     */
    public void sendStaticResource() throws IOException {
        byte[] bytes = new byte[BUFFER_SIZE];
        FileInputStream fis = null;
        try {
            File file = new File(HttpServer.FILE_ROOT, request.getUri());
            if (file.exists()) {
                fis = new FileInputStream(file);
                int ch = fis.read(bytes, 0, BUFFER_SIZE);
                while (ch != -1) {
                    output.write(bytes, 0, ch);
                    ch = fis.read(bytes, 0, BUFFER_SIZE);
                }
                output.flush();
            } else {
                String errorMessage = "HTTP/1.1 404 FIle Not Found\r\n" +
                        "Content-Type: text/html\r\n" +
                        "Content-Length: 23\r\n" +
                        "\r\n" +
                        "<h1>error未知</h1>";
                output.write(errorMessage.getBytes());
            }
        } catch (Exception e) {
            System.out.println(e.toString());
        } finally {
            if(fis != null) {
                fis.close();
            }
        }
    }
}

刚开始很简单  就是输出流 按照 http协议 进行 传输到页面就可以。

定义一个Servlet 下执行策略 

public class JxdServletProcessor {
    //根据HTTP协议响应头定义,里面包含变量
    private static String OKMessage = "HTTP/1.1 ${StatusCode} ${StatusName}\r\n" +
            "Content-Type: ${ContentType}\r\n" +
            "Server: minit\r\n" +
            "Date: ${ZonedDateTime}\r\n" +
            "\r\n";

    public void process(JxdRequest request, JxdResponse response) {
//首先根据uri最后一个/号来定位,后面的字符串认为是servlet名字
        String uri = request.getUri();
        String servletName = uri.substring(uri.lastIndexOf("/") + 1);
        URLClassLoader loader = null;
        OutputStream outputStream = null;
        try {
// create a URLClassLoader
            URL[] urls = new URL[1];
            URLStreamHandler streamHandler = null;
            File classPath = new File(HttpServer.WEB_ROOT);
            String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString();
            urls[0] = new URL(null, repository, streamHandler);
            loader = new URLClassLoader(urls);
        } catch (IOException e) {
            System.out.println(e.toString());
        }

        outputStream = response.getOutput();
        //由上面的URLClassLoader加载这个servlet
        Class<?> servletClass = null;
        try {
            servletClass = loader.loadClass(servletName);
        } catch (ClassNotFoundException e) {
            System.out.println(e.toString());
        }
//写响应头

        String head = composeResponseHead();
//创建servlet新实例,然后调用
// service(),由它来写动态内容到响应体
        JxdServlet servlet = null;
        try {
            outputStream.write(head.getBytes());
            servlet = (JxdServlet) servletClass.newInstance();
            servlet.service(request, response);
            outputStream.flush();
        } catch (Exception e) {
            System.out.println(e.toString());
        } catch (Throwable e) {
            System.out.println(e.toString());
        }

    }

    //生成响应头,填充变量值
    private String composeResponseHead() {
        Map<String, Object> valuesMap = new HashMap<>();
        valuesMap.put("StatusCode", "200");
        valuesMap.put("StatusName", "OK");
        valuesMap.put("ContentType", "text/html;charset=uft-8");
        valuesMap.put("ZonedDateTime",  DateTimeFormatter.ISO_ZONED_DATE_TIME.format(ZonedDateTime.now()));
        StrSubstitutor sub = new StrSubstitutor(valuesMap);
        String responseHead = sub.replace(OKMessage);
        return responseHead;
    }
}

设计一个main 方法 执行 http 页面的请求 

public class HttpServer {
    public static final String WEB_ROOT = System.getProperty("user.dir");

    public static final String FILE_ROOT = "D:\\";

    public static void main(String[] args) {
        HttpServer server = new HttpServer();
        server.await();
    }

    public void await() { //服务器循环等待请求并处理
        ServerSocket serverSocket = null;
        int port = 8080;
        try {
            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
        while (true) {
            Socket socket = null;
            InputStream input = null;
            OutputStream output = null;
            try {
                socket = serverSocket.accept(); //接收请求连接
                input = socket.getInputStream();
                output = socket.getOutputStream();
                // create Request object and parse
                JxdRequest request = new JxdRequest(input);
                request.parse();
                // create Response object
                JxdResponse response = new JxdResponse(output);

                if(request.getUri().startsWith("/servlet/")){
                    //加载动态资源
                    JxdServletProcessor jxdServletProcessor= new JxdServletProcessor();
                    jxdServletProcessor.process(request,response);
                }else{
                    //加载静态资源
                    StaticResourceProcessor staticResourceProcessor = new StaticResourceProcessor();
                    staticResourceProcessor.process(request,response);
                }

                // close the socket
                socket.close();
            } catch (Exception ea) {
                ea.printStackTrace();
            }
        }
    }
}

上面是一个静态资源 else  如果不关注的话 可以不看注释掉,我这边是获取D盘下边的 txt 文件 相应的页面上,没啥 东西

我们实现JxdServlet  接口 这个规范 打印一个hello world  给页面 
public class HelloWorldServlet implements JxdServlet {


    //http://localhost:8080/servlet/com.jxd.HelloWorldServlet
   // 注意包名 我是com.jxd包下边 做的HelloWorldServlet
    @Override
    public void service(JxdRequest req, JxdResponse res) throws IOException {

        System.out.println("进入>>>>>>HelloWorldServlet.service方法");

        String doc = "Hello World !!!";
        res.getOutput().write(doc.getBytes("utf-8"));
    }
}

以上就是一个很简单的 Tomcat  下一期我们对他进行一个优化 最后逐渐达到 准 民用级别。

相关推荐

  1. 一个民用Tomcat01

    2024-04-06 07:56:07       13 阅读
  2. 一个民用Tomcat02

    2024-04-06 07:56:07       15 阅读
  3. 一个民用Tomcat03

    2024-04-06 07:56:07       11 阅读
  4. 一个民用Tomcat04

    2024-04-06 07:56:07       14 阅读
  5. 一个民用Tomcat05

    2024-04-06 07:56:07       17 阅读
  6. 一个民用Tomcat06

    2024-04-06 07:56:07       12 阅读
  7. 一个民用Tomcat07

    2024-04-06 07:56:07       13 阅读
  8. 一个民用Tomcat08

    2024-04-06 07:56:07       11 阅读
  9. 从零实现 apache Tomcat-01-入门介绍

    2024-04-06 07:56:07       12 阅读
  10. 从零实现 apache Tomcat-01-入门介绍

    2024-04-06 07:56:07       10 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-06 07:56:07       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-06 07:56:07       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-06 07:56:07       20 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-06 07:56:07       20 阅读

热门阅读

  1. 4月5日排序算法总结(1)

    2024-04-06 07:56:07       18 阅读
  2. ucloud配置虚拟网卡---Ubuntu 20.04

    2024-04-06 07:56:07       11 阅读
  3. 理解七层网络协议

    2024-04-06 07:56:07       16 阅读
  4. Git入门实战教程之合并分支并解决冲突

    2024-04-06 07:56:07       17 阅读
  5. 服务器硬件基础知识

    2024-04-06 07:56:07       12 阅读
  6. 设计模式(20):责任链模式

    2024-04-06 07:56:07       10 阅读
  7. 使用Ajax的优点

    2024-04-06 07:56:07       13 阅读
  8. vue基本写法

    2024-04-06 07:56:07       15 阅读