Java-49 深入淺出 Tomcat 手寫 Tomcat 實現【02】HttpServlet Request RequestProcessor

點一下關注吧!!!非常感謝!!持續更新!!!

🚀 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)
● 資源返回客戶端瀏覽器

HttpProtocoUtil 協議類

public class HttpProtocoUtil {public static String getHttpHeader200(long contentLength) {return "HTTP/1.1 200 OK \n" +"Content-Type: text/html \n" +"Content-Length: " + contentLength + " \n" +"\r\n";}public static String getHttpHeader404() {String str404 = "<h1>404 not found</h1>";return "HTTP/1.1 404 NOT Found \n" +"Content-Type: text/html \n" +"Content-Length: " + str404.getBytes().length + " \n" +"\r\n" + str404;}
}

HttpProtocoUtil,它封裝了兩個方法,用于手動構造 HTTP 響應報文字符串,分別用于:

  • 返回 HTTP 200 成功響應的報文頭;
  • 返回 HTTP 404 未找到的完整響應報文(包含 header + body)。

關鍵點分析:

  • str404: 定義了一個 HTML 格式的正文

    404 not found

  • str404.getBytes().length: 計算正文的字節數,填入 Content-Length 字段中
  • 最后 + str404: 將正文內容添加在頭部之后

HttpServlet 基礎類

public abstract class HttpServlet implements Servlet {public abstract void doGet(Request request,Response response);public abstract void doPost(Request request,Response response);@Overridepublic void service(Request request, Response response) throws Exception {if("GET".equalsIgnoreCase(request.getMethod())) {doGet(request,response);}else{doPost(request,response);}}
}

簡化版的 HttpServlet 類,是你手寫 Web 容器(例如 MiniCat)中模仿 Java EE javax.servlet.http.HttpServlet 的核心組件。

  • abstract class: 抽象類,不能直接被實例化,必須由子類實現其抽象方法。
  • implements Servlet: 表示這個類實現了一個自定義的 Servlet 接口(你可能已經自己定義了 Servlet 接口),這與 Java Web 中的標準接口 javax.servlet.Servlet 類似。

在抽象方法中:

  • 聲明了兩個抽象方法,分別用于處理 GET 請求 和 POST 請求。

  • 子類必須實現它們,否則編譯報錯。

Request request: 封裝了 HTTP 請求的信息(如 URI、參數、方法類型等)。

  • Response response: 封裝了 HTTP 響應的信息(如設置狀態碼、響應內容等)。

這兩個類也應該是你自己定義的簡化版 Request 和 Response 類,用于模擬真實的 Servlet API 行為。

而在service(Request, Response)中:

  • 實現了 Servlet 接口中的 service() 方法,作為請求處理的統一入口。

  • 根據 request.getMethod() 返回的 HTTP 方法(如 “GET” 或 “POST”),分發給 doGet() 或 doPost() 方法。

  • equalsIgnoreCase: 忽略大小寫比較,兼容 “get”, “GET” 等寫法。

  • request.getMethod(): 獲取請求方法字符串,應該是你自定義 Request 類中的一個方法。

  • throws Exception: 表明此方法可能拋出異常,讓調用方去處理,便于靈活控制異常響應。

假設我們有一個具體的實現類:

public class HelloServlet extends HttpServlet {@Overridepublic void doGet(Request req, Response resp) {resp.write("Hello, GET!");}@Overridepublic void doPost(Request req, Response resp) {resp.write("Hello, POST!");}
}

當用戶訪問你的 Web 服務 /hello 時:

  • 如果是 GET 請求,會調用 doGet(),返回 “Hello, GET!”。
  • 如果是 POST 請求,會調用 doPost(),返回 “Hello, POST!”。

Request 請求處理類

public class Request {private String method;private String url;private InputStream inputStream;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 inputStr = new String(bytes);// 請求頭String firstLineStr = inputStr.split("\\n")[0];String[] strings = firstLineStr.split(" ");this.method = strings[0];this.url = strings[1];System.out.println("Request method: " + method + ", url: " + url);}public String getMethod() {return method;}public void setMethod(String method) {this.method = method;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public InputStream getInputStream() {return inputStream;}public void setInputStream(InputStream inputStream) {this.inputStream = inputStream;}
}

在類屬性中:

  • method:HTTP 請求方法(如 GET, POST)
  • url:請求的資源路徑(如 /index.html)
  • inputStream:從客戶端 socket 獲取的原始請求數據流

在 inputStream.available() 循環讀取,目的是等到客戶端數據準備好再讀取。

while (count == 0) {count = inputStream.available();
}

RequestProcessor 響應類

public class RequestProcessor extends Thread {private Socket socket;private Map<String, HttpServlet> servletMap;public RequestProcessor(Socket socket, Map<String, HttpServlet> servletMap) {this.socket = socket;this.servletMap = servletMap;}@Overridepublic void run() {try {InputStream inputStream = socket.getInputStream();Request request = new Request(inputStream);Response response = new Response(socket.getOutputStream());// 靜態資源if (servletMap.get(request.getUrl()) == null) {response.outputHtml(request.getUrl());} else {HttpServlet servlet = servletMap.get(request.getUrl());servlet.service(request, response);}socket.close();} catch (Exception e) {e.printStackTrace();}}
}

RequestProcessor 這是一個繼承了 Thread 的類,意味著每次請求會以獨立線程的方式進行處理。它負責解析 HTTP 請求、查找對應的 Servlet 處理器,或返回靜態資源。在簡易 Web Server 中,每當 ServerSocket.accept() 接收到一個連接,就會創建這個類的一個實例,并調用 start() 進入 run() 方法處理。

此外,在RequestProcessor(Socket socket, Map<String, HttpServlet> servletMap)構造函數中,將 socket 和 servlet 映射傳入,以便在 run() 方法中使用。這也是多線程處理請求的基礎結構:每個線程獨立處理一個連接,不共享 socket。

在核心處理邏輯中 run():從 socket 獲取輸入流、輸出流,構造出 Request 和 Response 對象。Request 負責解析 HTTP 請求頭;Response 封裝輸出功能(例如寫 HTML 響應)。

另外,在請求分發邏輯中,“servletMap.get(request.getUrl())”:

  • 靜態資源路徑(如 /index.html):不在 servletMap 中,調用 response.outputHtml(),你很可能實現了這個方法來讀取本地文件并寫入 socket。
  • 動態 Servlet 路徑(如 /hello):在 servletMap 中,調用 servlet.service(),執行對應的業務邏輯(最終調用 doGet() 或 doPost())。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84799.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84799.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84799.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在VB.net中,文本插入的幾個自定義函數

一、如果你是高手&#xff0c;一定“識貨”&#xff0c;分享給你 二、可應用于文本插入的幾種方式&#xff1a;6種 三、需要用到以下的幾個函數&#xff1a; 上代碼&#xff1a; Module TextModule <summary> 在指定位置插入文本 </summary> <p…

QC -io 服務器排查報錯方式/報錯: Failed to convert string to integer of varId variable!“

進斷點控制臺有報錯之后&#xff0c;復制報錯信息到 頭部菜單欄 1.編輯 -> 2.Find/Replace ->3.Advanced Find ->4. Project“xxxxx” 能找到問題點 再分析定位 在排查報錯時候&#xff0c;進入了這個報錯&#xff0c;msgInfo "MyTcpRedis: Failed to conver…

c++中auto與decltype使用

在 C11及后續版本中&#xff0c;關鍵字auto和decltype都是用于類型推導的&#xff0c;但它們的使用場景和行為有所不同。 1. auto 關鍵字 作用 auto 用于自動推導變量的類型&#xff0c;由編譯器根據初始化表達式來確定。 常見用法 // 基本用法 auto x 42; // int…

LabVIEW機器視覺零件檢測

基于LabVIEW 圖形化編程平臺與機器視覺技術&#xff0c;構建集圖像采集、處理、尺寸計算與合格性分析于一體的自動化檢測方案。通過模塊化硬件架構與自適應算法設計&#xff0c;實現對機械零件多維度尺寸的非接觸式高精度測量&#xff0c;相比人工檢測效率提升 12 倍&#xff0…

大數據治理域——實時數據開發

摘要 本文深入探討了大數據治理域中的實時數據開發&#xff0c;重點介紹了流式數據處理的核心價值、特點、技術挑戰、典型能力和應用場景。同時&#xff0c;詳細闡述了流式技術架構&#xff0c;包括數據采集、處理、存儲和服務等環節&#xff0c;并針對大促場景提出了相應的技…

Halcon/C# 圖像窗口、讀取圖片及仿射變換

一、Halcon 清理窗口 清除圖像窗口的顯示。 dev_clear_window() 二、Halcon 讀取圖片 (一) 讀取一張圖片 read_image (Image, printer_chip/printer_chip_01)Image&#xff1a;&#xff08;輸出參數&#xff09;讀取到的圖片變量名 第二個參數&#xff1a;圖片路徑&#xf…

Nginx 反向代理服務和安裝docker-compose

Nginx 反向代理服務和安裝docker-compose Nginx Proxy Manager 他是一個可視化的nginx的反向代理神器&#xff0c;動動手指輕松的配置Nginx&#xff0c;我們可以通過一些網頁&#xff0c;即可完成網站的代理配置&#xff0c;無需在動手安裝Nginx&#xff1b; dockoer-compose部…

FPGA基礎 -- Verilog 鎖存器簡介

由淺入深地講解 Verilog 中的鎖存器&#xff08;Latch&#xff09;**&#xff0c;包括&#xff1a; 什么是鎖存器&#xff08;定義與作用&#xff09;鎖存器的分類&#xff08;透明鎖存器 vs 邊沿觸發器&#xff09;Verilog 中鎖存器的建模方式鎖存器與觸發器的區別鎖存器的時…

Eclipse Memory Analyzer (MAT) 相關配置調整

一、JDK版本過低提示 已安裝高于 jdk 17 的版本依舊提示 jdk 版本過低&#xff0c;打開MAT的安裝目錄&#xff0c;在配置文件 MemoryAnalyzer.ini 中添加配置指向JDK即可。新增兩行配置&#xff1a; -vm D:/jdk_21.0.7/bin/javaw.exe //jdk安裝路徑 bin 目錄下的javaw.exe二…

機器學習常用評估指標

機器學習常用評估指標 機器學習的評價指標有精度、精確率、召回率、P-R曲線、F1 值、TPR、FPR、ROC等指標&#xff0c;還有在生物領域常用的敏感性、特異性等指標。 基礎 在分類任務中&#xff0c;各指標的計算基礎都來自于對正負樣本的分類結果&#xff0c;用混淆矩陣表示&…

視頻相似度檢測算法(帶課設報告)

摘 要 本文提出了一種基于關鍵幀特征提取的視頻相似度檢測方法&#xff0c;通過融合自適應采樣與特征降維技術實現高效準確的視頻內容比對。系統采用三階段處理流程&#xff1a;首先對輸入視頻進行自適應關鍵幀采樣&#xff0c;通過均勻間隔算法提取固定數量&#xff08;默…

微服務江湖的愛恨情仇:Spring Cloud 與 Kubernetes 的雙雄演義

引言&#xff1a;雙雄并立&#xff0c;一個時代的序幕 微服務革命&#xff0c;如同一場燎原之火&#xff0c;將龐大、笨重的單體應用燒成灰燼&#xff0c;宣告了一個敏捷、獨立、快速迭代的新紀元。然而&#xff0c;這場革命在摧毀舊世界的同時&#xff0c;也催生了一片混沌的新…

深度拆解RAGFlow分片引擎之切片實現

上一篇深度拆解RAGFlow分片引擎&#xff01;3大階段視覺增強&#xff0c;全網最硬核架構解析 講了切片的整體流程&#xff0c;今天我們來拆下切片的實現。 我們在設置的時候&#xff0c;可以選擇切片方法。這個參數是parser_id 在創建知識庫的時候&#xff0c;選擇對應的切片方…

CSS平滑滾動效果實現方法

一、純CSS實現方案 使用 scroll-behavior 屬性 屬性值 auto (默認值)&#xff1a;滾動框立即滾動smooth&#xff1a;滾動框以平滑的方式滾動 /* 全局平滑滾動 */ html {scroll-behavior: smooth; }/* 特定容器平滑滾動 */ .scroll-container {scroll-behavior: smooth;over…

李沐動手深度學習(pycharm中運行筆記)——12.權重衰退

12.權重衰退&#xff08;與課程對應&#xff09; 目錄 一、權重衰退 1、使用均方范數作為硬性限制 2、使用均方范數作為柔性限制&#xff08;通常這么做&#xff09; 3、演示對最優解的影響 4、參數更新法則 5、總結 二、代碼實現從零實現 三、代碼實現簡介實現 一、權重…

React Native【實戰范例】同步跟隨滾動

最終效果 實現原理 主動滾動區觸發滾動事件&#xff0c;原生監聽滾動值的變化&#xff0c;并用動畫的方式實時同步到跟隨滾動區 技術要點 使用 Animated.ScrollView 使用動畫變量 const scrollY useRef(new Animated.Value(0)).current;主動滾動觸發 onScroll&#xff0c;用 …

如何僅用AI開發完整的小程序<3>—創建小程序基礎框架

1、啟動小程序開發者工具-選擇小程序&#xff0c;點擊 2、創建一個項目工程 項目名稱&#xff1a;自己填默認的也行&#xff0c;最好不要中文&#xff0c;拼音也行 目錄&#xff1a;選擇你的項目創建路徑 AppID&#xff1a;可以先點測試號&#xff0c;后面再替換自己的AppID就…

SQL等價改寫優化

or 與 union all的優化 在SQL開發中&#xff0c;我們經常會遇到這樣的情況&#xff1a;需要組合多個相似但略有不同的查詢結果。大多數開發者本能地使用UNION/UNION ALL來解決&#xff0c;這種方式直觀易懂&#xff0c;但在特定場景下卻隱藏著巨大的性能浪費。 本案例將從執行…

【已解決】 數據庫INSERT操作時,Column count doesn’t match value count at row 1

【已解決】數據庫INSERT操作時&#xff0c;ColumnColumn count doesn’t match value count at row 1 在開發過程中&#xff0c;我們經常會遇到數據庫操作錯誤&#xff0c;其中之一就是 MySQL 中的 “Column count doesn’t match value count at row1” 錯誤。這個錯誤通常發…

管件接頭的無序抓取

文章目錄 1&#xff0c;目的2&#xff0c;過程3&#xff0c;易混易錯點4&#xff0c;代碼詳解4.1&#xff0c;初始化窗口4.2&#xff0c;創建多視角立體視覺模型。4.3&#xff0c;創建表面匹配模型4.4&#xff0c;多視角立體視覺重建管件堆表面模型4.5&#xff0c;管道接頭查找…