BIO模型手写一个miniTomcat

先理思路

开启监听-> 接受请求-> 拿到request 和response ->分发请求到相应的servlet->执行

开始动手

从包来看
这个手写是完全模拟了servlet一整套的流程
在这里插入图片描述

MyRequest

request需要一个输入流 得到请求信息 封装好 这个mini版本是基于http协议 拿到method和path就可以了

public class MyRequest {
    private String method;

    private String path;
		//这里的资源交给外层关闭
    public MyRequest(InputStream inputStream) throws IOException {
        String content = "";
        byte[] buff = new byte[1024];
        int len;
        if((len =inputStream.read(buff))!=-1){
            content = new String(buff,0,len);
        }
        //第一行是请求方式
        String line1 = content.split("\\n")[0];
        String[] s = line1.split(" ");
        method = s[0];
         path = s[1];
        System.out.println(content);
    }

    public String getMethod() {
        return method;
    }

    public String getPath() {
        return path;
    }
}

打印一下接受的字符串信息 可以自行对应
在这里插入图片描述

MyResponse

public class MyResponse {

    private OutputStream outputStream;

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

    public void write(String str) {
        //http协议需要返回一些信息 否则看不到
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.1 200 OK\n")
                .append("Content-Type: text/html\n")
                .append("\r\n")
                .append("<html><body>")
                .append(str)
                .append("</body></html>");
        try {
            outputStream.write(sb.toString().getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Servlet

简单的一个抽象类 当然接口也可以 不影响,
生命周期相关

public abstract class Servlet {

    public abstract void init();

    public abstract void destroy();

}

HttpServlet

同servlet 其实也可以是接口 只是我都写成了抽象类…

public  abstract class HttpServlet {

   public abstract void service(MyRequest request, MyResponse response);

   public abstract void doPost(MyRequest request, MyResponse response);

   public abstract void doGet(MyRequest request, MyResponse response);

}

MyServlet

自定义一个servlet 用于生命周期的内容

public class MyServlet extends Servlet {


    @Override
    public void init() {
        System.out.println("初始化成功");
    }

    @Override
    public void destroy() {
        System.out.println("tomcat销毁了");
    }
}

MyHttpServlet

自定义HttpServlet 用于处理请求

public class MyHttpServlet extends HttpServlet {

    @Override
    public void service(MyRequest request, MyResponse response) {
        if ("get".equalsIgnoreCase(request.getMethod())) {
            doGet(request,response);
        }else{
            doPost(request,response);
        }
    }

    @Override
    public void doPost(MyRequest request, MyResponse response) {
        response.write("this is servlet do post");
    }

    @Override
    public void doGet(MyRequest request, MyResponse response) {
        response.write("this is servlet do get");
    }
}

MyHttpServlet1

再自定义一个servlet 因为正式环境是可以配置多个的

public class MyHttpServlet1 extends HttpServlet {

    @Override
    public void service(MyRequest request, MyResponse response) {
        if ("get".equalsIgnoreCase(request.getMethod())) {
            doGet(request,response);
        }else{
            doPost(request,response);
        }
    }

    @Override
    public void doPost(MyRequest request, MyResponse response) {
        response.write("this is servlet1 do post");
    }

    @Override
    public void doGet(MyRequest request, MyResponse response) {
        response.write("this is servlet1 do get");
    }
}

web.properties

替代web.xml 反正就是配置请求和处理的servlet信息 形式不重要

url=/servletTest
className=tomcat.MyHttpServlet

url1=/servletTest1
className1=tomcat.MyHttpServlet1

servlet=tomcat.servlet.MyServlet

Tomcat

核心类 不多废话上代码

public class Tomcat {

    private int port = 8080;
    private ServerSocket server;
    private Map<String, HttpServlet> servletMap = new HashMap<>();

    private Properties xml = new Properties();

    private Servlet servlet;


    public void init() {
    //初始化  读取配置 并把请求和处理器的映射情况对应起来
        String webInfo = this.getClass().getResource("/").getPath();
        try (FileInputStream fis = new FileInputStream(webInfo + "web.properties")) {
            xml.load(fis);
            server = new ServerSocket(port);
            //这里映射就简单写死 毕竟是mini版本
            String url = xml.get("url").toString();
            String url1 = xml.get("url1").toString();
            String className = xml.get("className").toString();
            String className1 = xml.get("className1").toString();
            String servletName = xml.get("servlet").toString();
            HttpServlet servlet = (HttpServlet) Class.forName(className).newInstance();
            HttpServlet servlet1 = (HttpServlet) Class.forName(className1).newInstance();
            this.servlet = (Servlet) Class.forName(servletName).newInstance();
            this.servlet.init();
            //实例化之后放在map中
            servletMap.put(url, servlet);
            servletMap.put(url1, servlet1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void start() {
        InputStream inputStream = null;
        try {
            init();
            while (true) {
                Socket accept = server.accept();
                inputStream = accept.getInputStream();
                OutputStream outputStream = accept.getOutputStream();
                MyRequest request = new MyRequest(inputStream);
                MyResponse response = new MyResponse(outputStream);
                //如果这个请求有映射 那就进入相应的位置  如果没有就不处理 
                //这个位置可以根据需求自由分配  也可以添加过滤器之类的东西
               //我这里就写了一个简单版本的  
                if(servletMap.containsKey(request.getPath())){
                    HttpServlet servlet = servletMap.get(request.getPath());
                    servlet.service(request,response);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

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


}

最后得到了相应的内容:在这里插入图片描述

发布了24 篇原创文章 · 获赞 10 · 访问量 3081

猜你喜欢

转载自blog.csdn.net/qq_43091847/article/details/103975943