• 手动实现一个简易版 tomcat(yet)


    https://mp.weixin.qq.com/s?__biz=MzA5MzcxNjY4Ng==&mid=2648107477&idx=1&sn=237afdcd8dc67f3a36aac8a38fcaada9&chksm=887be074bf0c69627659d3f076420ba7d477bc08405437eafe4d99ed22e6d2f9a53c80a73d87&mpshare=1&scene=1&srcid=0606qoAMsGtii5eGzil3h35x&key=abc5240e014eede13ee3b36db10a8651176fd1ff480250a3b2660676db6e3a4f4c0857207a64f65dbafc7c5276b2d8e8375d9a65c25572ed6df33fa45995f85c0fc5588801f2def497593ae43d6347d5&ascene=0&uin=MTA2NzUxMDAyNQ%3D%3D&devicetype=iMac+MacBookAir6%2C2+OSX+OSX+10.10.5+build(14F2511)&version=11020012&lang=zh_CN&pass_ticket=mxEo2xKCtH9iR2PLbxrAcJSXJ7pfbLGSU5PqNtNoXLtIgAf3or95FesHIZkUX27e

    tomcat简介

    Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

    2手动实现

    项目结构如下图所示

    接下来我们就开始一步步实现,有servlet开发经验的对于Request和Response一定不陌生,所以就先实现自己的Request和Response。首先实现Response如下所示。

    package com.duomeng.tomcat;
    import java.io.IOException;
    import java.io.InputStream;
    /**
    *
    */
    public class MyRequest {
       private String url;
       private String method;
       public MyRequest(InputStream inputStream) throws IOException {
           StringBuilder httpRequest = new StringBuilder();
           byte[] httpRequestByte = new byte[1014];
           int length = 0;
           if ((length = inputStream.read(httpRequestByte)) > 0) {
               httpRequest.append(new String(httpRequestByte,0,length));
           }
           System.out.println("httpRequest = [" + httpRequest + "]");
           /**
           GET /student HTTP/1.1
           Host: localhost:8080
           Connection: keep-alive
           Cache-Control: max-age=0
           Upgrade-Insecure-Requests: 1
           User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
           Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,
            */
           String httpHead = httpRequest.toString().split(" ")[0];
           url = httpHead.split("\s")[1];
           method = httpHead.split("\s")[0];
           System.out.println("MyRequests = [" + this + "]");
       }
       public String getUrl() {
           return url;
       }
       public void setUrl(String url) {
           this.url = url;
       }
       public String getMethod() {
           return method;
       }
       public void setMethod(String method) {
           this.method = method;
       }
    }

    接着来实现自己的Reponse,如下图所示。

    package com.duomeng.tomcat;
    import java.io.IOException;
    import java.io.OutputStream;
    public class MyResponse {
       private OutputStream outputStream;
       public MyResponse(OutputStream outputStream) {
           this.outputStream = outputStream;
       }
       public  void write(String content) throws IOException {
           /**
            * HTTP/1.1 200 OK
            Content-type:text/html
            */
           StringBuffer stringBuffer = new StringBuffer();
           stringBuffer.append("HTTP/1.1 200 OK ")
                   .append("Content-type:text/html ")
                   .append(" ")
                   .append("<html><head><title>Hello World</title></head><body>")
                   .append(content)
                   .append("</body><html>");
           outputStream.write(stringBuffer .toString().getBytes());
           outputStream.close();
       }
    }

    有了自己的请求信息和响应信息,那接下来就要写servlet了。通常写自己的Servlet的时候要继承一个Servlet的父类HttpServlet,所以首先要写一个Servlet的父类,代码如下。

    package com.duomeng.tomcat;
    public abstract class MyServlet {
       protected abstract void doGet(MyRequest request,MyResponse response);
       protected abstract void doPost(MyRequest request,MyResponse response);
       public void service(MyRequest request,MyResponse response) throws NoSuchMethodException {
           if (request.getMethod().equalsIgnoreCase("POST")) {
               doPost(request,response);
           }else if(request.getMethod().equalsIgnoreCase("GET")){
               doGet(request,response);
           }else {
               throw new NoSuchMethodException("not support");
           }
       }
    }

    那么接下来就要写自己业务相关的Servlet,这里写一个和学生相关的Servlet,叫StudentServlet,还有一个和老师相关的Servlet,叫TeacherServlet。具体的代码分别如下。

    package com.duomeng.tomcat;
    import java.io.IOException;
    public class StudentServlet extends MyServlet{
       @Override
       protected void doGet(MyRequest request, MyResponse response) {
           try {
               response.write("I am a student.");
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       @Override
       protected void doPost(MyRequest request, MyResponse response) {
           try {
               response.write("I am a student.");
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
    }

    和老师相关的Servlet如下:

    package com.duomeng.tomcat;
    import java.io.IOException;
    public class TeacherServlet extends MyServlet{
       @Override
       protected void doGet(MyRequest request, MyResponse response) {
           try {
               response.write("I am a treacher.");
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       @Override
       protected void doPost(MyRequest request, MyResponse response) {
           try {
               response.write("I am a treacher.");
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
    }

    因为浏览器在请求的时候还会请求浏览器上面显示的favicon.ico,所以要编写一个相关的servlet来处理请求,代码如下。

    package com.duomeng.tomcat;
    import java.io.IOException;
    public class FaviconServlet extends MyServlet{
       @Override
       protected void doGet(MyRequest request, MyResponse response) {
           try {
               response.write("Favicon");
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       @Override
       protected void doPost(MyRequest request, MyResponse response) {
           try {
               response.write("Favicon");
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
    }

    以上就是写的跟具体实际当中业务相关的代码,还记得在Servlet的时候要在项目web.xml中配置请求地址和具体的servlet的映射关系,所以此处要手动来实现一个映射的关系。具体代码如下。

    package com.duomeng.tomcat;
    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;
       }
       public String getServletName() {
           return servletName;
       }
       public void setServletName(String servletName) {
           this.servletName = servletName;
       }
       public String getUrl() {
           return url;
       }
       public void setUrl(String url) {
           this.url = url;
       }
       public String getClazz() {
           return clazz;
       }
       public void setClazz(String clazz) {
           this.clazz = clazz;
       }
    }

    以上是每个具体的Servlet的信息,接下来要写一个存储有映射关系的类,代码如下。

    package com.duomeng.tomcat;
    import java.util.ArrayList;
    import java.util.List;
    public class ServletMappingConfig {
       public static List<ServletMapping> servletMappings = new ArrayList<ServletMapping>(16);
       static {
           servletMappings.add(new ServletMapping("student","/student","com.duomeng.tomcat.StudentServlet"));
           servletMappings.add(new ServletMapping("teacher","/teacher","com.duomeng.tomcat.TeacherServlet"));
           servletMappings.add(new ServletMapping("favicon","/favicon.ico","com.duomeng.tomcat.FaviconServlet"));
       }
    }

    接下来就是真正的主角登场了,那就是对于请求做分发处理的相关逻辑了,具体代码如下所示。

    package com.duomeng.tomcat;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.HashMap;
    import java.util.Map;
    public class MyTomcat {
       private int port = 8080;
       private Map<String,String> urlServletMap = new HashMap<String, String>(16);
       public MyTomcat(int port) {
           this.port = port;
       }
       public void start(){
           //初始化请求映射关系
           initServletMapping();
           ServerSocket serverSocket = null;
           try {
               serverSocket = new ServerSocket(port);
               System.out.println("My tomcat begin start");
               while (true){
                   Socket socket = serverSocket.accept();
                   InputStream inputStream = socket.getInputStream();
                   OutputStream outputStream = socket.getOutputStream();
                   MyRequest request = new MyRequest(inputStream);
                   MyResponse response = new MyResponse(outputStream);
                   //分发请求
                   dispatch(request,response);
                   socket.close();
               }
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       private void initServletMapping(){
           for (ServletMapping servletMapping:ServletMappingConfig.servletMappings) {
               urlServletMap.put(servletMapping.getUrl(),servletMapping.getClazz());
           }
       }
       private void dispatch(MyRequest request,MyResponse response){
           String clazz = urlServletMap.get(request.getUrl());
           try {
               Class servletClass = Class.forName(clazz);
               MyServlet myServlet = (MyServlet)servletClass.newInstance();
               myServlet.service(request,response);
           } catch (ClassNotFoundException e) {
               e.printStackTrace();
           } catch (IllegalAccessException e) {
               e.printStackTrace();
           } catch (InstantiationException e) {
               e.printStackTrace();
           } catch (NoSuchMethodException e) {
               e.printStackTrace();
           }
       }
       public static void main(String[] args) {
           new MyTomcat(8080).start();
       }
    }

    如果没有问题的话,启动main函数之后,在浏览器发起具体的请求会看到如下显示内容。

  • 相关阅读:
    偶遇问题
    上机实践
    知识点摸清
    实用脚本
    实用脚本
    对于问题,要打破砂锅问到底,也要懂得不求甚解——不执着于问题本身
    偶遇问题
    知识点摸清
    偶遇问题
    程序员论坛
  • 原文地址:https://www.cnblogs.com/silyvin/p/9164072.html
Copyright © 2020-2023  润新知