一步步教你手写迷你Tomcat

主体思路

当我们的Web运行的时候,从浏览器发出的请求,必然首先到达tomcat中,之后由tomcat进行处理,由此要考虑tomcat要进行哪些处理,首先便是提供Socket服务,之后对于请求进行分发,把请求和产生的响应封装成request和response。

  • 提供Socket服务
  • 封装请求/响应对象
  • 将不同的请求映射到具体的Servlet处理

HTTP协议

HTTP协议就是字符串协议需要截取进行处理。
在这里插入图片描述

处理请求

从HTTP请求中解析请求路径、请求方法、请求参数等。

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 + "]";
    }
}

处理响应

响应主要是输出符合浏览器协议的字符串。

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

}

封装Servlet规范

把请求和响应封装成Servlet规范要求的格式。

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服务

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

测试结果

在这里插入图片描述

发布了60 篇原创文章 · 获赞 1 · 访问量 3321

猜你喜欢

转载自blog.csdn.net/qq_16438883/article/details/103848352