JSP+Servlet+Tomcat应用开发中 手写tomcat的内容理解

这篇文章用于理解老师手写的tomcat的具体实现

引言 (可忽略)

B站马士兵老师的
学完java基础找了直接来看了这个视频,前面看的挺好,看到老师手写这个tomcat的时候蒙了,先花了两天时间重新学了IO流的知识(推荐B站尚硅谷java基础)回顾了网络的知识,今天把代码跟着敲完细读代码,一步步调试把过程中的变量拿出来看才看懂了整个结构,后附有代码

先附视频https://www.bilibili.com/video/BV1z5411A7DL?p=11

01ServeLet之Tomcat

定义:服务端上一直运行的常服务
tomcat组成:
————首先是和客户端连接的用的request 和response的两个对象,
这两个对象统称server,
通过这两个对象访问多个applet(也就是ServeLet),
在applet中实现接口类来做具体的事,
接口类是一套规范里面有很多需要处理数据用的方法,
server会根据信息要求applet实现各个请求,
所以他们合起来叫servelet

听起来很乱,不要着急,往下看,回头再来看总结

tomcat

跟着视频自己写了Tomcat
基于TCP协议。Socket套接字
首先主要就是ServerSocket创建好后获取相应的Socket对象,以及Soket对象的输入输出流
这个输入输出流我们把他具体化为两个请求
Request和响应Response的类,

先讲响应 response

response这个类的对象由Socket的输出流为构造参数创建,类中有类成员变量OutputStream,
也就是说OutputStream就是Socket的输出流,他的写操作会直接进行传输,
于是response这个类有write()方法(字节流字符流的IO都是read()和write()方法),
write()方法中根据传入的String参数改变了响应体中的标签内容以外,就是标准的HTTP响应格式书写的

再讲请求request 请求是指处理别人的请求

request类对象也是由Socket的输入流为构造参数创建,
类中有类成员变量InputStream,这个对象除了了构造函数和读写函数没有方法
主要功能在构造方法中,整个类就是为了接收到InputStream中需要的信息并且分析然后给出服务器特定的参数———
事例是通过自身的类成员提供了两个信息

 //请求方法  GET/POST  
    private String requestMethod;  
//请求地址资源定位  URL  
    private String requestUrl;   

这两个信息中
1-请求方法用于传递给所有ServerLet的抽象父亲HttpServerLet,作用下文会讲到
2-URL用于给MAP来根据URL(获取到的是整个tomcat工程的路径)获取到相应的ServeLet类,

这里有疑点就是Socket如何获取到这个路径的?

接下来是map类

前面讲到request带给我们两个信息的第二个是URL,
map类中只有一个成员变量里就是一个HashMap,并且具体的键值对信息由static申明好
这样就可以在服务器获得请求时给出相应的ServLet(会调用response())来响应
当然map中还有get方法,方便被调用获取键值

ServeLet

ServeLet可以有很多个,就是根据请求中的URL被map挑选到的用来根据需要返回特定信息的方法类;
所有ServeLet都继承了一个接口HttpServeLet,(下文会讲到,实际用了抽象类)
并且ServeLet要重写两个继承方法用于实现 在获得GET 和POST两种请求时的响应
案例中就单纯的调用了response的写方法来发送了回应,
response来自于接口重写方法中的参数

HttpServeLet

就是上文讲到的所有ServeLet的继承的接口,但事实上老师用了抽象类,
因为抽象类里面能定义非抽象的能被完整继承的方法Server()提供给ServeLet们使用,
这个方法用于判断POST 和GET请求,参数为request和response
将request中的GetrequestUrl()方法的返回值与类中静态常量"POST""GET"对比得出
并且直接执行对应的抽象方法(子类调用的时候就会执行自己重写好的方法)

具体实现

首先创建好ServerSocket对象,通过ServerSocket对象获得Socket对象。
再通过Socket对象分别获得OutputStream 和 InputStream
再拿来分别用来创建Request对象和Response对象
这时通过Request对象的GetRequestUrl来获取到请求中的URL,
再通过map获得请求的ServerLet对象对应类名
通过类名用反射来创建对象,
通过对象来调用Service方法(继承自父类,)
参数就是上面创建好的请求和响应对象
就这么多了,没看懂结合代码再看十遍

代码

注释不全但是保留了关键用于理解的输出

MyRequest代码

package com.hajizu;

import java.io.InputStream;

/**
 * 通过参数为输入流的构造方法获得输入流中的请求方法
 */
public class MyRequest {
    //请求方法  GET/POST
    private String requestMethod;
    //请求地址资源定位  URL
    private String requestUrl;
//    //协议版本  HTML1.1
//    private String protocolType;

    public MyRequest(InputStream i)throws Exception{
        byte[] bys = new byte[1024];
        int len=0;
        String str=null;
        if((len=i.read(bys))!=-1)
        {
            str = new String(bys,0,len);
        }
        String[] s = str.split("\n")[0].split(" ");
//        GET /mytomcat HTTP/1.1
//        Host: localhost:52777
//        Connection: keep-alive
//        Cache-Control: max-age=0
//        sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"
//        sec-ch-ua-mobile: ?0
//        Upgrade-Insecure-Requests: 1
//        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 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
        this.requestMethod=s[0];
        this.requestUrl=s[1];
    }

    public String getRequestMethod() {
        return requestMethod;
    }

    public void setRequestMethod(String requestMethod) {
        this.requestMethod = requestMethod;
    }

    public String getRequestUrl() {
        return requestUrl;
    }

    public void setRequestUrl(String requestUrl) {
        this.requestUrl = requestUrl;
    }

//    public String getProtocolType() {
//        return protocolType;
//    }
//
//    public void setProtocolType(String protocolType) {
//        this.protocolType = protocolType;
//    }
}

MyResponse代码

package com.hajizu;

import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

/**
 *自动输出一个write函数参数和固定HTML报文构成的字符串;
 */
public class MyResponse {
    private OutputStream outputStream;

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

    public void write(String str)throws Exception
    {
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.1 200 OK\n")
                .append("Content-Type:text/html\n")
                .append("\r\n")
                .append("<html>")
                .append("<body>")
                .append("<h1>"+str+"</h1>")
                .append("</body>")
                .append("</html>");
        this.outputStream.write(sb.toString().getBytes());
        this.outputStream.flush();
        this.outputStream.close();

    }

    public OutputStream getOutputStream() {
        return outputStream;
    }

    public void setOutputStream(OutputStream outputStream) {
        this.outputStream = outputStream;
    }


}

MyMapping代码

package com.hajizu;

import java.util.HashMap;


/**
 * 用于通过a,b页面标签连接具体的servelet
 */
public class MyMapping {
    public static HashMap<String,String> mapping =new HashMap<>();
    static{
        mapping.put("/mytomcat","com.hajizu.Myservlet");
    }

    public static HashMap<String, String> getMapping() {
        return mapping;
    }
}

ServeLet代码

package com.hajizu;

/**
 * applet具体类 也就是具体做的事
 */
public class Myservlet extends MyHttpServlet{
    @Override
    public void doGet(MyRequest request, MyResponse response) throws Exception {
        response.write("xxkelaDSB");
    }

    @Override
    public void doPost(MyRequest request, MyResponse response) throws Exception {
        response.write("hds");
    }
}

HttpServeLet代码

package com.hajizu;

/**
 * applet具体类 也就是具体做的事
 */
package com.hajizu;

/**
 * 抽象方法,类似接口,用于给予servlet类service方法,并且service自己定义get和post的执行内容
 */
public abstract class MyHttpServlet {
    public static final String METHOD_GET="GET";
    public static final String METHOD_POST="POST";
    public abstract void doGet(MyRequest request,MyResponse response) throws Exception;
    public abstract void doPost(MyRequest request,MyResponse response) throws Exception;

    public void service (MyRequest request,MyResponse response)throws Exception{
        if(METHOD_GET.equals(request.getRequestMethod())){
            doGet(request,response);
        }
        if(METHOD_POST.equals(request.getRequestMethod())){
            doPost(request,response);
        }

    }
}



```java
package com.hajizu;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Myserver {
    public static void startServer(int port) throws Exception {
        ServerSocket serverSocket= new ServerSocket(port);
        Socket socket =null;
        while(true)
        {
            socket=serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();
            MyResponse response = new MyResponse(outputStream);//写入http报文
            MyRequest request = new MyRequest(inputStream);//收到http报文解析到RequestUrl()为 /tomcat

            String clazz= new MyMapping().getMapping().get(request.getRequestUrl());
            System.out.println(request.getRequestUrl());
            //clazz="com.hajizu.Myservlet"
            //RequestUrl = "/mytomcat"

            if (clazz!=null){
                //反射获得类对象
                Class<Myservlet> myservletClass = (Class<Myservlet>) Class.forName(clazz);
                Myservlet myservlet = myservletClass.newInstance();
                myservlet.service(request,response);
            }
        }
    }
    public static void main(String[] args) throws Exception {
        startServer(52777);

    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值