Вручную реализовать простой Tomcat с нуля

Tomcat
Всем привет, в этой главе мы реализуем упрощенную версию tomcat. Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь со мной по адресу mr_beany@163.com. Также попросите руководства великих богов, спасибо

Работа программы необходима для поддержки сервера, и tomcat глубоко любим энтузиастами Java и признан некоторыми разработчиками программного обеспечения из-за его стабильной работы и бесплатной производительности.В настоящее время это популярный сервер веб-приложений.

Итак, как именно это работает? Сегодня мы реализуем упрощенную версию tomcat, чтобы это почувствовать.

Один: импортируйте пакет jar, который анализирует xml

<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6.1</version>
</dependency>

Второе: напишите класс разбора XML

package com.example.demo.utils;

import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * @author zy
 */
public class XmlUtils {
    /**
     * 定义解析器和文档对象
     */
    public SAXReader saxReader;
    public Document document;

    public XmlUtils(String path) {
        //获取解析器
        saxReader = new SAXReader();
        try {
            //获取文档对象
            document = saxReader.read(path);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取节点下的所有节点
     *
     * @param name
     * @return
     */
    public List<Element> getNodes(String name) {
        Element root = document.getRootElement();
        return root.elements(name);
    }
}

Третий: реализовать запрос и ответ

Запрос — это инкапсуляция запроса браузера, а Ответ — это ответ на запрос браузера. Другими словами, Запрос используется для получения информации о запросе, а Ответ используется для добавления информации, которая должна быть возвращена в браузер. .

Создать Запрос.java

package com.example.demo.http;

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

/**
 * @author zy
 */
public class Request {

    private String method;

    private String url;

    public Request(InputStream inputStream) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String[] methodAndUrl = bufferedReader.readLine().split(" ");
        this.method = methodAndUrl[0];
        this.url = methodAndUrl[1];
        System.out.println("请求类型:"+ method);
        System.out.println("请求路径:"+ url);
    }

    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;
    }
    
}

Создать ответ.java

package com.example.demo.http;

import java.io.OutputStream;

/**
 * @author zy
 */
public class Response {

    private OutputStream outputStream;

    private String write;

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

    public String getWrite() {
        return write;
    }

    public void setWrite(String write) {
        this.write = write;
    }

}

Четвертое: реализовать сервлет

сделать интерфейс

package com.example.demo.servlet;

import com.example.demo.http.Request;
import com.example.demo.http.Response;

/**
 * @author zy
 */
public abstract class AbstractServlet {

    public abstract void doGet(Request request, Response response);

    public abstract void doPost(Request request, Response response);
}

Затем реализуйте свой собственный сервлет

package com.example.demo.servlet;

import com.example.demo.http.Request;
import com.example.demo.http.Response;

/**
 * @author zy
 */
public class FirstServlet extends AbstractServlet {

    @Override
    public void doGet(Request request, Response response) {
        response.setWrite("我的第一个Servlet");
    }

    @Override
    public void doPost(Request request, Response response) {
        this.doGet(request, response);
    }
}

Пятое: Создайте файл web.xml

Здесь настраивается соответствующее отношение сервлета пути запроса, а файл помещается в папку ресурсов

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

    <servlet>
        <servlet-name>first.html</servlet-name>
        <servlet-class>com.example.demo.servlet.FirstServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>first.html</servlet-name>
        <url-pattern>/first.html</url-pattern>
    </servlet-mapping>

</web-app>

Шесть, создайте tomcat, инициализируйте файл конфигурации

package com.example.demo.tomcat;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.List;

import com.example.demo.utils.XmlUtils;
import org.dom4j.Element;

/**
 * @author zy
 */
public class Tomcat {
    /**
     * 设置端口号
     */
    private static final int PORT = 8080;

    public static final HashMap<String, Object> SERVLET_MAPPING = new HashMap<>();

    public static final HashMap<String, Object> SERVLET = new HashMap<>();

    /**
     * 控制服务器启动关闭
     */
    public boolean tomcatStarBool = true;

    private void init() {
        InputStream io = null;
        try {
            System.out.println("加载配置文件开始");
            //读取配置文件
            XmlUtils xml = new XmlUtils(XmlUtils.class.getResource("/")+"web.xml");
            //将所有的类都存储到容器中
            List<Element> list = xml.getNodes("servlet");
            for (Element element : list) {
                SERVLET.put(element.element("servlet-name").getText(),
                        Class.forName(element.element("servlet-class").getText()).newInstance());
            }
            //映射关系创建
            List<Element> list2 = xml.getNodes("servlet-mapping");
            for (Element element : list2) {
                SERVLET_MAPPING.put(element.element("url-pattern").getText(),
                        element.element("servlet-name").getText());
            }
            System.out.println("加载配置文件结束");
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (io != null) {
                try {
                    io.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

Семь: Создайте SocketProcess, который обрабатывает задачу запроса

package com.example.demo.tomcat;

import com.example.demo.http.Request;
import com.example.demo.http.Response;
import com.example.demo.servlet.AbstractServlet;

import java.io.OutputStream;
import java.net.Socket;

/**
 * @author zy
 */
public class SocketProcess extends Thread{

    protected Socket socket;

    public SocketProcess(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            Request request = new Request(socket.getInputStream());
            Response response = new Response(socket.getOutputStream());
            String servletName = (String) Tomcat.SERVLET_MAPPING.get(request.getUrl());
            if(servletName!=null && !servletName.isEmpty()) {
                //映射有的话找到对应的对象
                AbstractServlet servlet = (AbstractServlet) Tomcat.SERVLET.get(servletName);
                if(servlet!=null) {
                    servlet.doGet(request, response);
                }else {
                    System.out.println("找不到对应的servlet");
                }
            }else {
                System.out.println("找不到对应的servletMapping");
            }
            String res = response.getWrite();
            OutputStream outputStream = socket.getOutputStream();

            outputStream.write(res.getBytes("GBK"));
            outputStream.flush();
            outputStream.close();

        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Восемь: добавьте метод запуска в tomcat.java

private void start() {
    try {
        ServerSocket serverSocket = new ServerSocket(PORT);
        System.out.println("Tomcat 服务已启动,地址:localhost ,端口:" + PORT);
        this.init();
        //持续监听
        do {
            Socket socket = serverSocket.accept();
            //处理任务
            Thread thread = new SocketProcess(socket);
            thread.start();
        } while (tomcatStarBool);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

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

Девять: Тест

Начните запускать основной метод void в tomcat.java.


Следующие слова появляются, чтобы указать, что запуск прошел успешно, а затем введите в адресной строке

http://localhost:8080/first.html

? ? ? ? ? почему это так. . . . . .

Какие! Исходная информация заголовка ответа не была добавлена

Response.java добавлен

/**
 * 响应头信息
 */
public static final String RESPONSE_HEADER ="HTTP/1.1 200 \r\n"
        + "Content-Type: text/html\r\n"
        + "\r\n";

SocketProcess.java

String res = response.getWrite();

изменить на

String res = Response.RESPONSE_HEADER + response.getWrite();

перезагрузиться, посетить




конец

Желаю всем счастливого Нового года. Спасибо за поддержку!


Другие статьи:

Создайте свой собственный фоновый фреймворк SpringBoot с нуля

Адрес облака кода:git ee.com/bean также/no SPR…

Адрес гитхаба:GitHub.com/my bean also/no s…