手写一个民用Tomcat (01)

本文介绍了如何在Java中实现一个简易的Tomcat环境,包括定义接口、请求和响应类,以及如何处理静态资源和动态Servlet请求,以HelloWorldServlet为例展示基本操作。作者强调了接口作为规范的重要性。
摘要由CSDN通过智能技术生成

写一个下民用版的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  下一期我们对他进行一个优化 最后逐渐达到 准 民用级别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值