手写Tomcat之简单实现

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 手写Tomcat之简单实现,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

封装Request对象

/**
 * @author CJ
 * @description 通过输入流,对HTTP协议进行解析,拿到了HTTP请求头的方法以及URL
 * @create 2021-04-25
 **/
public class Request {
    private String url;
    private String method;

    //通过输入流,对HTTP协议进行解析,拿到了HTTP请求头的方法以及URL
    public Request(InputStream inputStream) throws IOException {
        String httpRequest = "";
        byte[] bytes = new byte[1024];
        int length = 0;
        if ((length = inputStream.read(bytes)) > 0) {
            httpRequest = new String(bytes, 0, length);
        }

//        GET /executeServlet HTTP/1.1
//        Host: localhost:8888
//        Connection: keep-alive
//        Pragma: no-cache
//        Cache-Control: no-cache
//        sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
//        sec-ch-ua-mobile: ?0
//        DNT: 1
//        Upgrade-Insecure-Requests: 1
//        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36
//        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
//        Sec-Fetch-Site: none
//        Sec-Fetch-Mode: navigate
//        Sec-Fetch-User: ?1
//        Sec-Fetch-Dest: document
//        Accept-Encoding: gzip, deflate, br
//        Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8
//        Cookie: SSO-SESSIONID=88ad2e2270a3498ea896931be14df2b4
        String httpHead = httpRequest.split("\n")[0];

        // GET /executeServlet HTTP/1.1
        url = httpHead.split("\\s")[1];
        method = httpHead.split("\\s")[0];
        System.out.println(this);
    }

//	setter() getter() toString()
}

封装Response对象

/**
 * @author CJ
 * @description 通过输出流,基于HTTP协议对响应内容进行输出
 * @create 2021-04-25
 **/
public class Response {

    private OutputStream outputStream;

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

    /**
     * HTTP响应协议 HTTP/1.1 200 ok
     * HTTP响应内容类型 Content-Type: text/html
     *
     * @param content
     * @throws IOException
     */
    public void write(String content) throws IOException {
        StringBuffer httpResponse = new StringBuffer();
        httpResponse.append("HTTP/1.1 200 OK\n")
                .append("Content-Type: text/html\n")
                .append("\r\n")
                .append("<html><body>")
                .append(content)
                .append("</body></html>");

        outputStream.write(httpResponse.toString().getBytes());
        outputStream.close();
    }
}

自定义Servlet

/**
 * @author CJ
 * @description 自定义简单Servlet
 * @create 2021-04-25
 **/
public abstract class Servlet {
    public abstract void doGet(Request request, Response response);

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

    public void service(Request request, Response response) {
        if (request.getMethod().equalsIgnoreCase("POST")) {
            doPost(request, response);
        } else if (request.getMethod().equalsIgnoreCase("GET")) {
            doGet(request, response);
        }
    }
}

定义具体的Servlet实现

/**
 * @author CJ
 * @description 定义具体的Servlet实现
 * @create 2021-04-25
 **/
public class ExecuteServlet extends Servlet {
    @Override
    public void doGet(Request request, Response response) {
        try {
            response.write("execute get Servlet....");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(Request request, Response response) {
        try {
            response.write("execute post Servlet....");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

定义Servlet映射

public class ServletMapping {
    private String servletName;
    private String url;
    private String clazz;

    public ServletMapping(String servletName, String url, String clazz) {
        this.servletName = servletName;
        this.url = url;
        this.clazz = clazz;
    }

//	setter() getter() toString()
}
/**
 * @author CJ
 * @description Servlet映射关系配置,类似web.xml文件
 * @create 2021-04-25
 **/
public class ServletMappingConfig {

    public static List<ServletMapping> servletMappingList = new ArrayList<ServletMapping>();

    static {
       servletMappingList.add(new ServletMapping("ExecuteServlet", "/executeServlet", "cn.ybzy.tomcat.servlet.ExecuteServlet"));
    }
}

Tomcat入口

public class Tomcat {
    private int prot = 8080;
    private Map<String, String> urlServletMap = new HashMap<String, String>();

    public Tomcat(int prot) {
        this.prot = prot;
    }

    public void start() {
        //初始化Url与对应Servlet的关系
        this.initServletMapping();

        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(prot);
            System.out.println("Tomcat starting ....");

            while (true) {
                Socket socket = serverSocket.accept();
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();

                Request request = new Request(inputStream);
                Response response = new Response(outputStream);

                //浏览器默认会请求favicon.ico图标
                if (!request.getUrl().equals("/favicon.ico")) {
                    dispatch(request, response);
                    socket.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    private void initServletMapping() {
        List<ServletMapping> servletMappingList = ServletMappingConfig.servletMappingList;
        for (ServletMapping servletMapping : servletMappingList) {
            urlServletMap.put(servletMapping.getUrl(), servletMapping.getClazz());
        }
    }

    private void dispatch(Request request, Response response) {
        String clazz = urlServletMap.get(request.getUrl());

        //反射加载对应类
        try {
            Class<Servlet> servlet = (Class<Servlet>) Class.forName(clazz);
            Servlet newInstance = servlet.newInstance();
            newInstance.service(request, response);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

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

}

整体包结构

在这里插入图片描述

执行测试

在这里插入图片描述

连接到目标VM, 地址: ''127.0.0.1:12371',传输: '套接字'', 传输: '{1}'
Tomcat starting ....
Request{url='/executeServlet', method='GET'}
Request{url='/favicon.ico', method='GET'}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/137063.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!