二.手写迷你版Tomcat-minicat2.0

minicat 1.0我们实现了返回固定的字符串"Hello minicat"。
minicat 2.0需求:
封装Request和Response对象,返回html静态资源文件。

封装Request对象

想要封装Request对象,得要先知道请求信息里面有哪些数据,所以我们先打印请求信息。

/**
     * minicat启动需要初始化展开的一些操作
     */
    public void start() throws IOException {
        // 监听端口
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("---->>>minicat start on port:"+port);

        //minicat 1.0
//        while (true) {
//            String data = "Hello minicat!";
//            Socket socket = serverSocket.accept();
//            // 有了socket,接收到请求,获取输出流
//            OutputStream outputStream = socket.getOutputStream();
//            String responseText = HttpProtocolUtil.getHttpHeader200(data.getBytes().length)+data;
//            outputStream.write(responseText.getBytes());
//            socket.close();
//        }

        // minicat 2.0
        while (true) {
            Socket socket = serverSocket.accept();
            // 获取输入流
            InputStream inputStream = socket.getInputStream();
            // 因为网络请求会有间断性,所以需要确认数据流必须存在
            int count = 0;
            while (count == 0) {
                // 从输入流中获取请求信息
                count = inputStream.available();
            }

            byte[] bytes = new byte[count];
            // 读取数组
            inputStream.read(bytes);
            System.out.println("====>>> 请求信息:"+new String(bytes));

            socket.close();
        }
    }

打印信息如下:

====>>> 请求信息:GET / 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; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7

根据打印出来的请求信息,找到重点要封装的地方 “GET / HTTP/1.1” 。

  • “GET”请求方式需要封装,因为后面会根据不同的请求方式找不同的servlet。
  • GET后面的“/”也需要封装,这代表的是请求路径。
  • “HTTP/1.1”这里不需要要封装,tomcat默认就用HTTP/1.1。

定义Request对象
经过分析,我们需要封装请求方式和请求路径,所以Request定义如下:

/**
 * 把请求信息封装成Request对象(根据inputStream输入流封装)
 */
public class Request {
    // 请求方式,GET/POST
    private String method;
    // 请求路径,例如:/,/index.html
    private String url;

    // 输入流,其他属性从输入流中解析出来
    private InputStream inputStream;
    
	// getter setter...
}

在Request实体中增加构造方法,给method和url赋值

public Request() {
    }

public Request(InputStream inputStream) throws IOException {
     this.inputStream = inputStream;

     // 因为网络请求会有间断性,所以需要确认数据流必须存在
     int count = 0;
     while (count == 0) {
         // 从输入流中获取请求信息
         count = inputStream.available();
     }

     byte[] bytes = new byte[count];
     // 读取数组
     inputStream.read(bytes);
     // 转换成String
     String inputStr = new String(bytes);

     //获取第一行请求信息
     String firstLineStr = inputStr.split("\\n")[0]; // GET / HTTP/1.1
     String[] strings = firstLineStr.split(" ");
     // 请求方式
     this.method = strings[0];
     // 请求路径
     this.url = strings[1];
 }

封装Response对象

Response对象中需要做的事情,根据url获取静态资源绝对路径,进一步根据绝对路径获取静态资源,最终通过输出流输出
获取静态资源文件的绝对路径

public class StaticResourceUtil {
	 public static String getAbsolutePath(String path) {
	     // 获取绝对路径
	     String absolutePath = StaticResourceUtil.class.getResource("/").getPath();
	     return absolutePath.replaceAll("\\\\","/")+path;
	 }
}

根据绝对路径获取静态资源

        File file = new File(absoluteResourcePath);

通过输出流输出

public class StaticResourceUtil {
	 public static void outputStaticResource(InputStream inputStream, OutputStream outputStream) throws IOException {
        int count = 0;
        while (count == 0) {
            count = inputStream.available();
        }

        int resourceSize = count;
        // 输出http请求头
        outputStream.write(HttpProtocolUtil.getHttpHeader200(resourceSize).getBytes());
        // 读取内容
        long written = 0; // 已经读取的内容长度
        int byteSize = 1024; // 计划每次缓冲的长度
        byte[] bytes = new byte[byteSize];

        // 输出具体内容
        // 循环读取,直到读取完
        while (written < resourceSize) {
            if (written + byteSize > resourceSize) { // 说明剩余未读取大小不足一个1024长度,那就按真实长度处理
                // 剩余的文件长度
                byteSize = (int) (resourceSize - written);
                bytes = new byte[byteSize];
            }

            inputStream.read(bytes);
            outputStream.write(bytes);

            written+=byteSize;
        }
    }
}

Response完整代码如下:

/**
 * 封装Response对象,需要依赖于OutputStream
 *
 * 该对象需要提供核心方法,输出html
 */
public class Response {

    private OutputStream outputStream;

    public Response() {
    }

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

    /**
     * 使用输出流输出指定字符串
     * @param content
     * @throws IOException
     */
    public void output (String content) throws IOException {
        outputStream.write(content.getBytes());
    }

    /**
     * 根据url获取静态资源绝对路径,进一步根据绝对路径获取静态资源,最终通过输出流输出
     * @param path
     */
    public void outputHtml(String path) throws IOException {
        // 获取静态资源绝对路径
        String absoluteResourcePath = StaticResourceUtil.getAbsolutePath(path);

        // 输出静态资源文件
        File file = new File(absoluteResourcePath);
        if (file.exists() && file.isFile()) {
            // 读取静态资源文件,输出静态资源
            StaticResourceUtil.outputStaticResource(new FileInputStream(file),outputStream);
        }else{
            // 输出404
            output(HttpProtocolUtil.getHttpHeader404());
        }
    }
}

V2.0测试

启动类中更改如下

/**
     * minicat启动需要初始化展开的一些操作
     */
    public void start() throws IOException {
        // 监听端口
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("---->>>minicat start on port:"+port);

        //minicat 1.0
//        while (true) {
//            String data = "Hello minicat!";
//            Socket socket = serverSocket.accept();
//            // 有了socket,接收到请求,获取输出流
//            OutputStream outputStream = socket.getOutputStream();
//            String responseText = HttpProtocolUtil.getHttpHeader200(data.getBytes().length)+data;
//            outputStream.write(responseText.getBytes());
//            socket.close();
//        }

        // minicat 2.0
        while (true) {
            Socket socket = serverSocket.accept();
            // 获取输入流
            InputStream inputStream = socket.getInputStream();

            //封装Request和Response
            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());

            response.outputHtml(request.getUrl());
            socket.close();

        }
    }

	/**
     * minicat 的程序启动入口
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在resources目录下增加index.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>静态资源</title>
</head>
<body>
Hello minicat 静态资源
</body>
</html>

启动效果如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值