欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 新车 > Java-50 深入浅出 Tomcat 手写 Tomcat 实现【03】启动测试!StatisResourceUtil Servlet

Java-50 深入浅出 Tomcat 手写 Tomcat 实现【03】启动测试!StatisResourceUtil Servlet

2025/6/21 7:35:47 来源:https://blog.csdn.net/w776341482/article/details/148754534  浏览:    关键词:Java-50 深入浅出 Tomcat 手写 Tomcat 实现【03】启动测试!StatisResourceUtil Servlet

点一下关注吧!!!非常感谢!!持续更新!!!

🚀 AI篇持续更新中!(长期更新)

目前2025年06月13日更新到:
AI炼丹日志-28 - Audiblez 将你的电子书epub转换为音频mp3 做有声书,持续打造实用AI工具指南!📐🤖

💻 Java篇正式开启!(300篇)

目前2025年06月11日更新到:
Java-44 深入浅出 Nginx - 底层进程机制 Master Worker 机制原理 常用指令
MyBatis 已完结,Spring 已完结,深入浅出助你打牢基础!

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
目前2025年06月13日更新到:
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解

请添加图片描述

MiniCat

基本介绍

我们要手写实现一个 Mini 版的 Tomcat,我们要实现的是,作为一个服务器软件,可以通过我们的浏览器客户端发送HTTP请求,Minicat处理之后,处理结果可以返回给浏览器的客户端。
● 提供服务,接受请求(Socket通信)
● 请求信息封装成 Request 对象(Response对象)
● 客户端请求资源,资源分为静态资源(HTML)和动态资源(Servlet)
● 资源返回客户端浏览器

Response 请求响应类

定义了一个名为 Response 的公共类,用于封装向客户端发送数据(如 HTML、文本等)的逻辑。

public class Response {private OutputStream outputStream;public Response() {}public Response(OutputStream outputStream) {this.outputStream = outputStream;}public void output(String content) throws IOException {outputStream.write(content.getBytes());}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 {output(HttpProtocoUtil.getHttpHeader404());}}
}

OutputStream 是 Java I/O 的基类,用于向外部(如客户端的 socket)输出字节数据。它的典型使用场景是在 Web 服务中向浏览器写入响应内容。

对于 output 方法,这个方法将一个字符串 content 转换成字节数组,然后写入 outputStream。实质上,它把一段内容(如 HTML 文本)直接返回给客户端。

其中用到的工具类,StaticResourceUtil.getAbsolutePath(path) 是一个工具方法(未给出具体代码),通常作用是将相对路径转换为项目中的绝对路径。

对于 Response 类来说,主要的职责就是:

  • 封装输出流:把 OutputStream 作为类的核心资源,用于向客户端写数据
  • 文本输出:可以直接输出一个字符串到客户端(如返回 HTTP 响应头和正文)
  • HTML输出:从文件系统中读取静态 HTML 文件并写回客户端
  • 404处理:文件不存在时自动返回标准的 404 响应

Servlet 接口

public interface Servlet {void init() throws Exception;void destroy() throws Exception;void service(Request request, Response response) throws Exception;}

StaticResourceUtil 静态资源

public class StaticResourceUtil {public static String getAbsolutePath(String path) {String absolutePath = StaticResourceUtil.class.getResource("/").getPath();return absolutePath.replace("\\\\", "/") + path;}public static void outputStaticResource(InputStream inputStream, OutputStream outputStream) throws IOException {int count = 0;while (count == 0) {count = inputStream.available();}int resourceSize = count;outputStream.write(HttpProtocoUtil.getHttpHeader200(resourceSize).getBytes());long written = 0;int byteSize = 1024;byte[] bytes = new byte[byteSize];while (written < resourceSize) {if (written + byteSize > resourceSize) {byteSize = (int) (resourceSize - written);bytes = new byte[byteSize];}inputStream.read(bytes);outputStream.write(bytes);outputStream.flush();written += byteSize;}}}

获取资源的绝对路径:getAbsolutePath

  • StaticResourceUtil.class.getResource(“/”) 会获取到当前类所在的类路径(classpath 根目录)。
  • .getPath() 获取的是该目录的实际路径(如:/home/user/project/target/classes/)。
  • replace(“\\”, “/”) 是为了处理 Windows 路径中的反斜杠转为正斜杠,但这里写得 有问题(见下文)。
  • 最终将 path 拼接在 classpath 后,返回静态资源的绝对路径。

输出静态资源内容:outputStaticResource

  • inputStream.available() 试图获取文件长度(单位为字节数);
  • 但是用 while (count == 0) 等待它非 0 的方式是 不稳定的。
  • available() 并不等价于“文件大小”,它是“当前可读字节数”,不适合用于预估资源总长度。

逐段读取并写出数据: “while (written < resourceSize)”:

  • 分块读写,每次最多读取 1024 字节;
  • 如果最后一块不足 1024 字节,动态调整 byteSize 和 bytes[] 大小;
  • 每读取一块,立即写入并 flush(即时响应给客户端)。

整体的小总结:

  • 类名:StaticResourceUtil,工具类
  • 功能:获取资源路径、输出文件内容到 HTTP
  • 亮点:模拟 Web Server 发送 HTML 等静态文件
  • 关键问题:误用 available()、不检查读取字节数、频繁分配数组
  • 优化方向:用 readAllBytes() 或 while(read != -1) 模式代替原始读取逻辑

WzkServlet 实现类

这里就是对之前的内容的使用,建立了一自己的Servlet,然后启动服务即可!

public class WzkServlet extends HttpServlet {@Overridepublic void doGet(Request request, Response response) {String content = "<h1>WzkServlet GET Hello World!</h1>";try {response.output(HttpProtocoUtil.getHttpHeader200(content.getBytes().length) + content);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void doPost(Request request, Response response) {String content = "<h1>WzkServlet POST Hello World!</h1>";try {response.output(HttpProtocoUtil.getHttpHeader200(content.getBytes().length) + content);} catch (Exception e) {e.printStackTrace();}}@Overridepublic void init() throws Exception {}@Overridepublic void destroy() throws Exception {}}

资源文件

index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>wzk-icu</title>
</head>
<body>
<h1>wzk-icu 测试页面!
</h1>
</body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8" ?>
<web-app><servlet><servlet-name>wzkicu</servlet-name><servlet-class>icu.wzk.WzkServlet</servlet-class></servlet><servlet-mapping><servlet-name>wzkicu</servlet-name><url-pattern>/wzkicu</url-pattern></servlet-mapping>
</web-app>

启动测试

目前我们的代码概览是这样的:
请添加图片描述

我们启动服务:
请添加图片描述
接着我们访问8080端口:
请添加图片描述

我们可以看到控制台输出了对应的内容
请添加图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词