自己手寫tomcat項目

一:Servlet的原理

在Servlet(接口中)有:

1.init():初始化servlet

2.getServletConfig():獲取當前servlet的配置信息

3.service():服務器(在HttpServlet中實現,目的是為了更好的匹配http的請求方式)

4.getServletInfo():獲取servlet當前運行過程中的信息

5.destroy():銷毀,回收內存

在I/O中應包含:1.請求頭(f12+網絡) 2.請求方式(get/post) 3.請求內容

get請求:將請求的內容放在url中(相對不安全),url長度有限(導致發送的內容不能太長),get請求做查詢

post請求:請求內容放在請求體當中,無法看到(相對安全),一般用來做文件上傳、下載,post請求做增刪改操作

在ServletRequest中應該有:1.method:請求方式 2.編碼方式 3.parmater 4.url 5.cookie

在ServletResponse中應該有:1.狀態碼 2.編碼方式 3.字符集 4.data數據

每一個和外界進行通訊的進程(端口號0~65535)

端口號區分當前的進程

serverSocket.accept():阻塞監聽(停在這里等到程序的到來)

二:tomcat原理

下面用一個圖給大家展示

注解:給程序看的(@webservlet等等)

注釋:給人看得(//)

實現自定義注解:需要使用jdk提供元注解(主要使用前兩個)

1.@Target注解(用來描述注解的使用范圍)

2.@Retention注解(表示這個注解在什么時候還有效,用于描述注解的生命周期)

3.@Documented注解

4.@Inherited注解 這四個幫助實現自定義注解

前兩個的使用方法

1.

2.

利用上面兩個就能夠實現自定義注解(下面就是實現)

三、手寫tomcat

首先先創建idea項目(名稱和位置可以隨意)

在創建好項目之后會有一個.java文件(可刪可不刪)

之后在創建下面幾個軟件包和MyTomcat文件(MyTomcat和剛開始有的那個java文件不一樣)

之后在每個軟件包中創建好java文件和注解文件、接口文件(其中zj軟件包中的注解文件可用自己的姓名起,因為是自己手寫的tomcat文件)

創建完成之后,首先在HttpServletRequest和HttpServletResponse中分別寫

package com.qcby.request;public class HttpServletRequest {private String method;private String 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;}
}
package com.qcby.response;import com.qcby.request.HttpServletRequest;import java.io.IOException;
import java.io.OutputStream;public class HttpServletResponse {private OutputStream outputStream;public HttpServletResponse(OutputStream outputStream){this.outputStream = outputStream;}public  void writeServlet(String context) throws IOException {outputStream.write(context.getBytes());}
}

寫好之后就可以在寫servlet軟件包中的內容了

這是接口

package com.qcby.servlet;import com.qcby.request.HttpServletRequest;
import com.qcby.response.HttpServletResponse;import java.io.IOException;public interface servlet {public void service(HttpServletRequest request, HttpServletResponse response) throws IOException;
}

這是java

package com.qcby.servlet;import com.qcby.request.HttpServletRequest;
import com.qcby.response.HttpServletResponse;import java.io.IOException;public abstract class HttpServlet implements servlet{public void doPost(HttpServletRequest request, HttpServletResponse response) {}public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {}@Overridepublic void service(HttpServletRequest request, HttpServletResponse response) throws IOException {if(request.getMethod().equals("GET")){doGet(request,response);}else if(request.getMethod().equals("POST")){doPost(request,response);}}
}

寫關于自己的注解

package com.qcby.zj;import java.lang.annotation.*;@Target(ElementType.TYPE)//該注解用在類上面
@Retention(RetentionPolicy.RUNTIME)//在運行期間表達
public @interface LRHServlet {String url();
}

之后寫myweb中的

package com.qcby.myweb;import com.qcby.request.HttpServletRequest;
import com.qcby.response.HttpServletResponse;
import com.qcby.servlet.HttpServlet;
import com.qcby.util.ResponseUtil;
import com.qcby.zj.LRHServlet;import java.io.IOException;@LRHServlet(url="/myservlet")
public class MyFirstServlet extends HttpServlet {@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {System.out.println("hello word");response.writeServlet(ResponseUtil.getResponseHeader200("First hello word"));}@Overridepublic void doPost(HttpServletRequest request,HttpServletResponse response){}
}
package com.qcby.myweb;import com.qcby.request.HttpServletRequest;
import com.qcby.response.HttpServletResponse;
import com.qcby.servlet.HttpServlet;
import com.qcby.zj.LRHServlet;@LRHServlet(url="/insert")
public class insertServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response){System.out.println("I am insert");}@Overridepublic void doPost(HttpServletRequest request,HttpServletResponse response){}
}

util中放的是工具類,可直接復制

package com.qcby.util;import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;/*** 掃描指定包,獲取該包下所有的類的全路徑信息*/
public class SearchClassUtil {/*** 掃描指定包路徑下的所有類* @param basePack 需要掃描的包名* @return 類的全路徑列表*/public static List<String> searchClass(String basePack) {//創建存儲類路徑的列表List<String> classPaths = new ArrayList<>();try {// 獲取類加載器(用于查找類路徑資源)ClassLoader classLoader = Thread.currentThread().getContextClassLoader();// 將包名轉換為路徑格式(如 com.qcby.test)轉換為路徑格式(com/qcby/test)String path = basePack.replace('.', '/');// 獲取資源枚舉通過類加載器獲取該路徑下的所有資源(可能來自文件系統或 JAR 包)Enumeration<URL> resources = classLoader.getResources(path);//resources 是通過類加載器獲取的資源枚舉(包含文件系統和 JAR 包中的資源)while (resources.hasMoreElements()) {//每次循環處理一個資源 URLURL resource = resources.nextElement();// 判斷資源類型(文件系統或JAR包)if (resource.getProtocol().equalsIgnoreCase("file")) {// 處理文件系統中的類//獲取 URL 中的路徑部分String filePath = resource.getPath();//解碼特殊字符filePath = java.net.URLDecoder.decode(filePath, "UTF-8");//調用 findAndAddClassesInPackageByFile() 遞歸掃描目錄findAndAddClassesInPackageByFile(basePack, filePath, classPaths);} else if (resource.getProtocol().equalsIgnoreCase("jar")) {// 處理JAR包中的類//從 JAR 資源 URL 中提取實際的 JAR 文件路徑。跳過前綴 jar:file:(長度為 5)。//indexOf("!"):找到 ! 的位置,截取到此前的部分,得到 JAR 文件的路徑String jarPath = resource.getPath().substring(5, resource.getPath().indexOf("!"));//解碼 URL 編碼的特殊字符jarPath = java.net.URLDecoder.decode(jarPath, "UTF-8");//打開 JAR 文件,掃描指定包下的所有類文件。findAndAddClassesInPackageByJar(basePack, jarPath, classPaths);}}} catch (Exception e) {e.printStackTrace();}return classPaths;}/*** 從文件系統中查找類*/private static void findAndAddClassesInPackageByFile(String packageName, String packagePath, List<String> classPaths) {//創建文件對象將傳入的路徑字符串轉換為 File 對象,用于文件系統操作。File dir = new File(packagePath);//確保當前路徑是一個存在且有效的目錄。if (!dir.exists() || !dir.isDirectory()) {return;}// 獲取目錄下的所有文件和子目錄,并過濾出以下兩類File[] dirfiles = dir.listFiles(file ->// 文件夾或.class文件//使用 Lambda 表達式作為 listFiles 的過濾器,簡潔地指定篩選條件。file.isDirectory() || file.getName().endsWith(".class"));//目錄無法訪問(如權限不足)或為空時,listFiles 可能返回 null,此處直接跳過。if (dirfiles == null) {return;}// 遍歷所有文件for (File file : dirfiles) {if (file.isDirectory()) {// 遞歸處理子目錄findAndAddClassesInPackageByFile(packageName + "." + file.getName(), //包名file.getAbsolutePath(),   //文件或目錄的絕對路徑classPaths    //類路徑集合(用于儲存結果));} else {// 處理class文件String className = file.getName().substring(0, file.getName().length() - 6);classPaths.add(packageName + '.' + className);}}}/*** 從JAR包中查找類*/private static void findAndAddClassesInPackageByJar(String packageName, String jarPath, List<String> classPaths) {//嘗試打開 JAR 文件(資源自動關閉)try (JarFile jar = new JarFile(jarPath)) {//獲取 JAR 文件中所有條目的枚舉Enumeration<JarEntry> entries = jar.entries();//逐個處理 JAR 中的每個條目。while (entries.hasMoreElements()) {JarEntry entry = entries.nextElement();String name = entry.getName();// 判斷是否是類文件并且在指定包路徑下//確保只提取指定包及其子包下的類文件。if (name.endsWith(".class") && name.startsWith(packageName.replace('.', '/'))) {//提取類全限定名去除 .class 后綴:String className = name.substring(0, name.length() - 6).replace('/', '.');//添加類名到結果列表classPaths.add(className);}}} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {// 測試示例//測試掃描指定包List<String> classes = searchClass("com.qcby.myweb");//遍歷并打印結果for (String className : classes) {System.out.println(className);}}public static List<String> searchClass() {return null;}
}
package com.qcby.util;public class ResponseUtil {public  static  final String responseHeader200 = "HTTP/1.1 200 \r\n"+"Content-Type:text/html; charset=utf-8 \r\n"+"\r\n";public static String getResponseHeader404(){return "HTTP/1.1 404 \r\n"+"Content-Type:text/html; charset=utf-8 \r\n"+"\r\n" + "404";}public static String getResponseHeader200(String context){return "HTTP/1.1 200 \r\n"+"Content-Type:text/html; charset=utf-8 \r\n"+"\r\n" + context;}
}

在config中寫入

package com.qcby.config;import com.qcby.servlet.HttpServlet;
import com.qcby.util.SearchClassUtil;
import com.qcby.zj.LRHServlet;import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;/*** tomcat路由*/
public class TomcatRoute {//HashMap<String, HttpServlet> HttpServlet向上轉型(使用多態),因為myweb中的父類全是HttpServlet//將public static HashMap<String, HttpServlet> routes = new HashMap<>();寫入static{}中會導致無法調用public static HashMap<String, HttpServlet> routes = new HashMap<>();static{// 傳入要掃描的包名List<String> paths = SearchClassUtil.searchClass("com.qcby.myweb");for(String path : paths){try{//urlClass clazz = Class.forName(path);LRHServlet webServlet = (LRHServlet) clazz.getDeclaredAnnotation(LRHServlet.class);routes.put(webServlet.url(), (HttpServlet) clazz.getDeclaredConstructor().newInstance());System.out.println(webServlet.url());
//                if (webServlet != null) {
//                    System.out.println(webServlet.url());
//                }//對象clazz.getDeclaredConstructor().newInstance();}catch(ClassNotFoundException e){e.printStackTrace();} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);}}}
}

最后就是直接的MyTomcat

package com.qcby;import com.qcby.config.TomcatRoute;
import com.qcby.request.HttpServletRequest;
import com.qcby.response.HttpServletResponse;
import com.qcby.servlet.HttpServlet;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;/*** tomcat主啟動類*/
public class MyTomcat {static HashMap<String, HttpServlet> routes = TomcatRoute.routes;static HttpServletRequest request = new HttpServletRequest();/*** 分發器*/public static void dispatch(HttpServletResponse response) throws IOException {HttpServlet servlet = routes.get(request.getUrl());System.out.println(servlet);if (servlet != null) {servlet.service(request, response);}}public static void start() throws IOException {System.out.append("服務器端啟動...");//1.定義ServerSocket對象進行服務器端的端口注冊ServerSocket serverSocket = new ServerSocket(8080);while (true) {//2.監聽客戶端的Socket鏈接程序Socket socket = serverSocket.accept(); // 阻塞監聽//3.打開輸入流,解析客戶端發來的內容InputStream inputStream = socket.getInputStream();//輸入流BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));//將字節流轉換成字符流String str = reader.readLine();request.setMethod(str.split("\\s")[0]);request.setUrl(str.split("\\s")[1]);//4.打開輸出流OutputStream outputStream = socket.getOutputStream();HttpServletResponse response = new HttpServletResponse(outputStream);dispatch(response);}}public static void main(String[] args) throws IOException {start();}
}

這樣就完成三分之二了

之后運行MyTomcat程序后,回顯示com.qcby.myweb下的所有軟件包名,和服務器端啟動的字樣

在瀏覽器的地址欄里輸入(localhost:8080/myservlet)這里的8080要根據你實際寫的端口號是多少寫多少(myservlet要寫自己定義的url)

在瀏覽器中就能夠看到下面寫在MyFirstServlet中的內容

在控制臺能夠看到MyFirstservlet中打印的內容

這樣一個簡單的tomcat就寫好了

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

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

相關文章

蘭亭妙微:用系統化思維重構智能座艙 UI 體驗

蘭亭妙微設計專注于以產品邏輯驅動的界面體驗優化&#xff0c;服務領域覆蓋AI交互、智能穿戴、IoT設備、智慧出行等多個技術密集型產業。我們倡導以“系統性設計”為方法論&#xff0c;在用戶需求與技術邊界之間找到最優解。 此次智能駕駛項目&#xff0c;我們為某車載平臺提供…

ubuntu安裝google chrome

更新系統 sudo apt update安裝依賴 sudo apt install curl software-properties-common apt-transport-https ca-certificates -y導入 GPG key curl -fSsL https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/google-chrom…

技術測評:小型單文件加密工具的功能解析

最近在測試一款名為OEMexe的文件加密工具&#xff0c;發現它確實有一些獨特之處值得分享。這款軟件體積非常小巧&#xff0c;僅209KB&#xff0c;屬于綠色單文件版程序&#xff0c;無需安裝即可直接運行。 主要特點 多格式支持&#xff1a;能夠處理多種常見文件格式&#xff0…

Java-Objects類高效應用的全面指南

Java_Objects類高效應用的全面指南 前言一、Objects 類概述二、Objects 類的核心方法解析2.1 requireNonNull系列方法&#xff1a;空指針檢查的利器2.2 equals方法&#xff1a;安全的對象比較2.3 hashCode方法&#xff1a;統一的哈希值生成2.4 toString方法&#xff1a;靈活的對…

計網| 網際控制報文協議(ICMP)

目錄 網際控制報文協議&#xff08;ICMP&#xff09; 一、ICMP 基礎特性 二、ICMP 報文分類及作用 差錯報告報文 詢問報文 網際控制報文協議&#xff08;ICMP&#xff09; ICMP&#xff08;Internet Control Message Protocol&#xff0c;網際控制報文協議&#xff09;是 …

微服務初步學習

系統架構演變過程 一、單體架構 前后端都在一個項目中&#xff0c;包括我們現在的前后端分離開發&#xff0c;都可以看作是一個單體項目。 二、集群架構 把一個服務部署多次&#xff0c;可以解決服務不夠的問題&#xff0c;但是有些不必要的功能也跟著部署多次。 三、垂直架…

Web安全基礎:深度解析與實戰指南

一、Web安全體系架構的全面剖析 1.1 分層防御模型(Defense in Depth) 1.1.1 網絡層防護 ??防火墻技術??: 狀態檢測防火墻(SPI):基于連接狀態跟蹤,阻斷非法會話(如SYN Flood攻擊)下一代防火墻(NGFW):集成IPS、AV、URL過濾(如Palo Alto PA-5400系列)配置示例…

使用大語言模型從零構建知識圖譜(上)

從零到一&#xff1a;大語言模型在知識圖譜構建中的實操指南 ©作者|Ninja Geek 來源|神州問學 將你的 Pandas data frame 利用大語言模型轉換為知識圖譜。從零開始構建自己的基于大語言模型的圖譜構建器&#xff0c;實際使用 Langchain 的 LLMGraphTransformer &#xff…

18.自動化生成知識圖譜的多維度質量評估方法論

文章目錄 一、結構維度評估1.1 拓撲結構評估1.1.1 基礎圖論指標1.1.2 層級結構指標 1.2 邏輯一致性評估1.2.1 形式邏輯驗證1.2.2 約束滿足度 二、語義維度評估2.1 語義一致性評估2.1.1 標簽語義分析2.1.2 關系語義評估 2.2 語義表示質量2.2.1 嵌入質量2.2.2 上下文語義評估 三、…

go 集成base64Captcha 支持多種驗證碼

base64Captcha 是一個基于 Go 語言開發的驗證碼生成庫&#xff0c;主要用于在 Web 應用中集成驗證碼功能&#xff0c;以增強系統的安全性。以下是其主要特點和簡介&#xff1a; base64Captcha主要功能 驗證碼類型豐富&#xff1a;支持生成多種類型的驗證碼&#xff0c;包括純…

制作大風車動畫

這個案例的風車旋轉應用了圖形變換來實現&#xff0c;速度和縮放比例應用slider來實現&#xff0c;其中圖片的速度&#xff0c;圖片大小的信息通過State來定義變量管理&#xff0c;速度和和縮放比例的即時的值通過Prop來管理。 1. 案例效果截圖 2. 案例運用到的知識點 2.1. 核…

代碼隨想錄算法訓練營第四十二四十三天

LeetCode/卡碼網題目: 42. 接雨水84. 柱狀圖中最大的矩形98. 所有可達路徑 其他: 今日總結 往期打卡 42. 接雨水 跳轉: 42. 接雨水 學習: 代碼隨想錄公開講解 問題: 給定 n 個非負整數表示每個寬度為 1 的柱子的高度圖&#xff0c;計算按此排列的柱子&#xff0c;下雨之后能…

SEO 優化實戰:ZKmall模板商城的 B2C商城的 URL 重構與結構化數據

在搜索引擎算法日益復雜的今天&#xff0c;B2C商城想要在海量信息中脫穎而出&#xff0c;僅靠優質商品和營銷活動遠遠不夠。ZKmall模板商城以實戰為導向&#xff0c;通過URL 重構與結構化數據優化兩大核心策略&#xff0c;幫助 B2C 商城實現從底層架構到搜索展示的全面升級&…

Linux自有服務

自有服務概述 概述 自有服務&#xff0c;即不需要用戶獨立去安裝的軟件的服務&#xff0c;而是當系統安裝好之后就可以直接使用的服務&#xff08;內置&#xff09; 顯示服務 顯示服務 命令&#xff1a;systemctl \[選項] 選項參數 list-units --type service --all&#x…

ZYNQ Overlay硬件庫使用指南:用Python玩轉FPGA加速

在傳統的FPGA開發中,硬件設計需要掌握Verilog/VHDL等硬件描述語言,這對軟件開發者而言門檻較高。Xilinx的PYNQ框架通過Overlay硬件庫徹底改變了這一現狀——開發者只需調用Python API即可控制FPGA的硬件模塊,實現硬件加速與靈活配置。本文將深入探討ZYNQ Overlay的核心概念、…

JavaScript入門【1】概述

1.JavaScript是什么? <font style"color:rgb(38,38,38);">Javascript &#xff08;簡稱“JS”&#xff09;是?種直譯式腳本語?&#xff0c;?段腳本其實就是?系列指令&#xff0c;計算機通過這些指令來達成?標。它?是?種動態類型的編程語?。JS?來在?…

c++從入門到精通(五)--異常處理,命名空間,多繼承與虛繼承

異常處理 棧展開過程&#xff1a; 棧展開過程沿著嵌套函數的調用鏈不斷查找&#xff0c;直到找到了與異常匹配的catch子句為止&#xff1b;也可能一直沒找到匹配的catch&#xff0c;則退出主函數后查找過程終止。棧展開過程中的對象被自動銷毀。 在棧展開的過程中&#xff0c…

自適應稀疏核卷積網絡:一種高效靈活的圖像處理方案

自適應稀疏核卷積網絡&#xff1a;一種高效靈活的圖像處理方案 引言 在深度學習的大潮中&#xff0c;計算機視覺技術取得了長足的進步。其中&#xff0c;卷積神經網絡&#xff08;CNN&#xff09;作為圖像處理的核心工具&#xff0c;極大地推動了各類圖像識別任務的效果提升。…

Nginx:利用 FreeSSL 申請(Https)免費證書的技術指南

1、簡述 在現代互聯網應用中,使用 HTTPS 連接是確保數據傳輸安全的基本需求。SSL/TLS 證書能夠加密客戶端與服務器之間的通信,防止中間人攻擊等安全隱患。而許多開發者和小型企業可能會擔心 SSL 證書的費用問題。幸運的是,FreeSSL 提供了一個簡單易用的平臺,允許我們申請免…

自定義庫模塊增加自定義許可操作詳細方法

自定義庫模塊增加自定義許可操作詳細方法 用到的工具: 后面程序用到的所有代碼均是該工具生成的秘密&#xff01;&#xff01;&#xff01;&#xff01; 【切記切記&#xff01;&#xff01;&#xff01; 一定要記住密碼&#xff0c;不然如果你想將庫的許可認證移除&#xf…