A step by step teach you a handwritten mini Tomcat

Main idea

When we run the Web, from the request sent by the browser, must first reach the tomcat, then processed by the tomcat, tomcat thus to consider what treatment should be, first of all it is to provide Socket service, followed by a request for distribution, the response to the request and the request is generated and encapsulated into a response.

  • Socket services provided
  • Package Request / Response Object
  • Mapping different requests to the specific process Servlet

HTTP protocol

HTTP protocol is the protocol need to intercept the string processing.
Here Insert Picture Description

Processing the request

Parsing the HTTP request from the request path, a request method, the request parameters and the like.

package com;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

public class MyRequest {

    //请求路径
    private String url;

    //请求方法
    private String method;

    //请求参数
    private Map<String,String> map = new HashMap<>();

    public MyRequest(InputStream inputStream) throws Exception{
        String httpRequest = "";
        byte[] httpRequestBytes = new byte[1024];
        int length = 0;
        if((length = inputStream.read(httpRequestBytes))>0){
            httpRequest = new String(httpRequestBytes,0,length);
        }
        //解析参数
        if(httpRequest.length() > 0){
            String httpHead = httpRequest.split("\n")[0];
            //index?id=tom
            String fullUrl = httpHead.split("\\s")[1];
            //是否存在参数
            if(fullUrl.contains("?")){
               String[] arr = fullUrl.split("\\?");
               url = arr[0];
               String[] params = arr[1].split("&");
               for(String parm : params){
                   String[] param = parm.split("=");
                   map.put(param[0],param[1]);
               }
            }else{
               url = fullUrl;
            }
            method = httpHead.split("\\s")[0];
            System.out.println(this.toString());
        }
    }

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

    public Map<String, String> getMap() {
        return map;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public String toString() {
        return "MyRequest [url=" + url + ", method=" + method + "]";
    }
}

Treatment response

The main output response is in line with the browser protocol string.

package com;
import java.io.OutputStream;

public class MyResponse {
    private OutputStream outputStream;

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

    //将文本转换成字节流
    public void write(String content) throws Exception{
       //HTTP响应协议
       StringBuffer httpResponse = new StringBuffer();
       httpResponse.append("HTTP/1.1 200 0K\n")
               .append("Content-Type:text/html\n")
               .append("\r\n")
               .append("<html><head><link rel=\"icon\" href=\"data:;base64,=\"></head><body>")
               .append(content)
               .append("</body></html>");
       outputStream.write(httpResponse.toString().getBytes());
       outputStream.close();
    }

}

Packaging Servlet specification

The request and response format packaged into Servlet specifications.

package com;

public abstract class MyServlet {

    public abstract void doGet(MyRequest myRequest,MyResponse myResponse);

    public abstract void doPost(MyRequest myRequest,MyResponse myResponse);

    public void service(MyRequest myRequest,MyResponse myResponse){
        if(myRequest.getMethod().equalsIgnoreCase("POST")){
           doPost(myRequest,myResponse);
        }else if(myRequest.getMethod().equalsIgnoreCase("GET")){
           doGet(myRequest,myResponse);
        }
    }
}
package com;

public class HelloWorldServlet extends MyServlet {

    @Override
    public void doGet(MyRequest myRequest, MyResponse myResponse) {
        try {
            myResponse.write("get world");
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(MyRequest myRequest, MyResponse myResponse) {
         try {
             myResponse.write("post world");
         }catch (Exception e){
             e.printStackTrace();
         }
    }
}
package com;

import java.util.Map;

public class IndexServlet extends MyServlet {

    @Override
    public void doGet(MyRequest myRequest, MyResponse myResponse) {
        try {
            StringBuffer content = new StringBuffer();
            content.append("<h1>Hello Get</h1><br>");
            if(myRequest.getMap().size() > 0){
                for(Map.Entry<String,String> map : myRequest.getMap().entrySet()){
                    content.append("<h2>"+map.getKey()+"="+map.getValue()+"</h2><br>");
                }
            }
            myResponse.write(content.toString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(MyRequest myRequest, MyResponse myResponse) {
        try {
            String content = "<h1>Hello Post</h1>";
            myResponse.write(content);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

Socket Services

package com;
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<>();

    public MyTomcat(int port){
       this.port = port;
    }

    public void start(){

        //初始化 URL与对应处理的servlet的关系
       initServletMapping();
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(port);
            System.out.println("MyTomcat is start");
            while (true){
               Socket socket = serverSocket.accept();
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();

                MyRequest myRequest = new MyRequest(inputStream);
                MyResponse myResponse = new MyResponse(outputStream);
                //请求分发
                dispatcher(myRequest,myResponse);
                socket.close();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 初始化映射
     */
    private void initServletMapping(){
        for(ServletMapping servletMapping : ServletMappingConfig.servletMappingList){
            urlServletMap.put(servletMapping.getUrl(),servletMapping.getClazz());
        }
    }

    private void dispatcher(MyRequest myRequest,MyResponse myResponse){

       String clazz = urlServletMap.get(myRequest.getUrl());
       try {
         //反射
           if(clazz != null){
               Class<MyServlet> myServletClass = (Class<MyServlet>)Class.forName(clazz);
               MyServlet myServlet = myServletClass.newInstance();
               myServlet.service(myRequest,myResponse);
           }
       }catch (Exception e){
           e.printStackTrace();
       }
    }

    public static void main(String[] args) {
        new MyTomcat(8080).start();
    }
}
package com;

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;
    }
}
package com;
import java.util.ArrayList;
import java.util.List;

public class ServletMappingConfig {

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

    static {
        servletMappingList.add(new ServletMapping("index","/index","com.IndexServlet"));
        servletMappingList.add(new ServletMapping("world","/world","com.HelloWorldServlet"));
    }
}

Test Results

Here Insert Picture Description

Published 60 original articles · won praise 1 · views 3321

Guess you like

Origin blog.csdn.net/qq_16438883/article/details/103848352