Tomcat原理(4)——嘗試手動Servlet的實現

目錄

一、什么是Servlet

1.servlet的定義

2.servlet的結構

二、實現servlet的流程圖

三、具體實現代碼

1、server

?2.實體類request&response

3.HttpServlet抽象類

4.再定義三個servlet進行測試?


?

Tomcat原理(3)——靜&動態資源以及運行項目的基本流程-CSDN博客文章瀏覽閱讀414次,點贊2次,收藏2次。Tomcat原理(2)——注解及注解的實現-CSDN博客(1)注解一般用于對程序的說明,就像注釋一樣,但是區別是注釋是給人看的,但是注解是給程序看的。(2)讓編譯器進行編譯檢查的作用,比如下邊這個@Override注解是重寫的意思,子類重寫了父類的方法,但是改動了方法名,所以報錯。https://blog.csdn.net/2301_78566776/article/details/144508887?spm=1001.2014.3001.5502?我們在上一篇博客中已經了解到了靜動態資源和tomcat的基本流程

一、什么是Servlet

1.servlet的定義

????????Servlet,全稱為Java Servlet,是運行在Java服務器端的程序,它主要用于接收和響應來自客戶端基于HTTP協議的請求。Servlet可以看作是在服務器上運行的小程序,用于生成動態Web內容。

2.servlet的結構

這是一個servlet的基本結構。我們觀察可以發現:

  • Servlet繼承了一個HttpServlet抽象類
  • servlet文件包含兩個主要的方法:doGet和doPost
  • 觀察這兩個方法的入參一個是request 一個是response

二、實現servlet的流程圖

1.我們首先需要構造一個Server服務器模擬,來接受HTTP請求,并且返回method(get/post)

2.創建request實體類和respons實體類,在request實體類中設置method和path變量

3.創建HttpServlet抽象類,在類里定義doGet和doPost兩個抽象方法,并且判斷所傳method為什么類型,進行選擇執行。

4.具體執行的doGet和doPost方法,要在具體的servlet中執行(找抽象類的具體實現方法)——即我們每一個servlet都要對doGet和doPost進行重寫。

如圖所示

?

三、具體實現代碼

引入

我們嘗試接收整個http請求的信息

package com.qcby.tomcat.webservlet;/*
* 服務器端 tomcat ——》接收信息
* */import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class SocketServer {public static void main(String[] args) throws IOException {run();}public static void run() throws IOException {ServerSocket serverSocket= new ServerSocket(8080);//端口的范圍:0~65535while (true){//等待客戶端連接Socket socket = serverSocket.accept();//阻塞監聽:程序會在這里卡住。只有監聽到客戶端的信息后才會向下執行//輸出客戶端給我們發來的程序InputStream inputStream=socket.getInputStream();//打開輸入流:接收輸入的信息int count=0;while (count==0){count=inputStream.available();}byte[] bytes=new byte[count];//01010101010100001101010 用字節數組接收inputStream.read(bytes);String context=new String(bytes);System.out.println(context);}}
}

結果如圖

我們可以看到這個請求的全部信息。第一行的前兩個詞為其method/path,在一會的server文件中我們只要前兩個詞。

1、server

????????這個類中我們獲取到了http請求的method(get/post)和path(@WebServlet中的path)

獲取的方法是對所有請求信息進行切割。并且在最后我們將method和path放入了request中

package com.qcby.tomcat.socket;import com.qcby.tomcat.Request.Request;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {private static Request request=new Request();public static void main(String[] args) throws Exception {// 1.打開通信端口   tomcat:8080   3306  ---------》進行網絡通信ServerSocket serverSocket = new ServerSocket(8080);System.out.println("****************server start.....");//2.接受請求數據while (true) {Socket socket = serverSocket.accept();  //--------------------->注意:此時監聽網卡的是:主線程System.out.println("有客戶進行了鏈接");new Thread(() -> {//處理數據---------》數據的處理在于讀和寫try {handler(socket);} catch (Exception e) {e.printStackTrace();}}).start();}}public static void handler(Socket socket) throws Exception {//讀取請求的數據InputStream inputStream = socket.getInputStream();requestContext(inputStream);}public static void requestContext(InputStream inputStream) throws IOException {// 創建一個StringBuilder對象,用于構建請求的第一行StringBuilder sb = new StringBuilder();int context; // 用于存儲每次從輸入流中讀取的單個字節// 讀取輸入流直到遇到換行符(\n)或文件結束(-1)while ((context = inputStream.read()) != -1) {// 如果讀取到換行符,則停止讀取if (context == '\n') {break; // 遇到換行符,退出循環}// 將讀取到的字節轉換為字符,并添加到StringBuilder中sb.append((char) context);}// 從StringBuilder中獲取第一行字符串,并去除首尾空格String firstLine = sb.toString().trim();// 檢查第一行是否為空if (firstLine.isEmpty()) {// 如果為空,則打印提示信息System.out.println("你輸入了一個空請求");} else {// 如果不為空,則按空格分割第一行字符串為單詞數組String[] words = firstLine.split("\\s+");// 打印出請求方法和請求URI(通常是數組的前兩個元素)// 注意:這里沒有檢查數組長度,如果數組長度小于2,將會拋出ArrayIndexOutOfBoundsException// 在實際應用中,應該添加適當的錯誤處理或驗證邏輯String method=words[0];String path=words[2];System.out.println(words[0] + " " + words[1]);request.setMethod(method);request.setPath(path);}}
}

@WebServlet接口

package com.qcby.tomcat.webservlet;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface WebServlet {String path() default "";
}

?

?2.實體類request&response

生成了get和set方法

生成了全參和無參的構造函數

package com.qcby.tomcat.Request;public class Request {private String path;private String method;public Request(String path, String method) {this.path = path;this.method = method;}public Request() {}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public String getMethod() {return method;}public void setMethod(String method) {this.method = method;}
}

?在這里 response我并沒有實現

package com.qcby.tomcat.Response;public class Response {
}
3.HttpServlet抽象類

抽象類中既可以有抽象方法也可以有具體方法。

package com.qcby.tomcat.HttpServlet;import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;public abstract class HttpServlet {public  void service(Request request, Response response){if(request.getMethod().equals("GET")){doGet(request,response);}else if (request.getMethod().equals("POST")){doPost(request,response);}else if (request.getMethod().equals("")){System.out.println("未獲取到方法類型");}}public abstract void doGet(Request request,Response response);public abstract void doPost(Request request,Response response);}
4.再定義三個servlet進行測試?

注意!每個servlet都有繼承HttpServlet,并且在每個servlet中都要重寫doGet和doPost

package com.qcby.tomcat.MyWeb;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;
import com.qcby.tomcat.webservlet.WebServlet;@WebServlet(path ="myFirstServlet")
public class MyFirstServlet extends HttpServlet {@Overridepublic void doGet(Request request, Response response) {}@Overridepublic void doPost(Request request, Response response) {}
}
package com.qcby.tomcat.MyWeb;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;
import com.qcby.tomcat.webservlet.WebServlet;@WebServlet(path ="mySecondServlet")
public class MySecondServlet extends HttpServlet {@Overridepublic void doGet(Request request, Response response) {}@Overridepublic void doPost(Request request, Response response) {}
}

?

package com.qcby.tomcat.MyWeb;import com.qcby.tomcat.HttpServlet.HttpServlet;
import com.qcby.tomcat.Request.Request;
import com.qcby.tomcat.Response.Response;
import com.qcby.tomcat.webservlet.WebServlet;@WebServlet(path ="myThirdServlet")
public class MyThirdServlet extends HttpServlet {@Overridepublic void doGet(Request request, Response response) {}@Overridepublic void doPost(Request request, Response response) {}
}

我們會發現它已經很像Java的servlet文件模板了?

補充:

如何讀取一個軟件包,遍歷里面的servlet,返回其類名和注解的path值

package com.qcby.tomcat;import com.qcby.tomcat.webservlet.WebServlet;import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;public class MyTomcat {public static void main(String[] args) {try {// 1. 掃描包路徑 (com.wzh.tomcat.myweb)String packageName = "com.qcby.tomcat.MyWeb";List<Class<?>> classes = getClasses(packageName);// 2. 遍歷所有類,檢查是否有@WebServlet注解for (Class<?> clazz : classes) {if (clazz.isAnnotationPresent(WebServlet.class)) {// 3. 獲取@WebServlet注解的值WebServlet webServlet = clazz.getAnnotation(WebServlet.class);System.out.println("類名: " + clazz.getName() + " | URL路徑: " + webServlet.path());}}} catch (Exception e) {e.printStackTrace();}}/*** 獲取指定包下的所有類** @param packageName 包名,例如 "com.wzh.tomcat.myweb"* @return 類對象列表* @throws Exception*/private static List<Class<?>> getClasses(String packageName) throws Exception {List<Class<?>> classes = new ArrayList<>();String path = packageName.replace('.', '/'); // 將包名轉換為文件路徑// 通過類加載器獲取包的資源路徑ClassLoader classLoader = Thread.currentThread().getContextClassLoader();Enumeration<URL> resources = classLoader.getResources(path);while (resources.hasMoreElements()) {URL resource = resources.nextElement();File directory = new File(resource.toURI());// 掃描文件夾下的所有類文件if (directory.exists()) {for (File file : directory.listFiles()) {if (file.getName().endsWith(".class")) {// 獲取類的完整類名String className = packageName + "." + file.getName().replace(".class", "");classes.add(Class.forName(className));}}}}return classes;}
}

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

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

相關文章

Node.js內置模塊

1.內置模塊 Node.js的中文網參考手冊:https://nodejs.cn//api 幫助文檔 API文檔:查看對應的模塊,左邊是模塊,右邊是模塊的成員 源碼:https://github.com/nodejs/node/tree/main/lib 查看 例如: http.js 創建web服務器的模塊 -->進入源碼中,搜索…

【RAG實戰】RAG與大模型應用

1.1 大模型應用的方向&#xff1a;RAG 1.1.1 什么是RAG 1. 生成式AI 一種能夠生成各類內容的技術&#xff0c;包括文本、圖像、音頻和合成數據。自2022年底ChatGPT在全球范圍內推廣以來&#xff0c;基于Transformer解碼器結構的大模型已能在短時間內為用戶生成高質量的文本、…

基于DeepSpeed Chat詳解 PPO 算法中的actor_loss_fn及其核心參數

詳解 PPO 算法中的 actor_loss_fn 及其核心參數 1. 引言 在強化學習中&#xff0c;PPO&#xff08;Proximal Policy Optimization&#xff0c;近端策略優化&#xff09;算法是一種經典且高效的策略優化方法。它通過重要性采樣&#xff08;Importance Sampling&#xff09;和策…

D3 基礎1

D3 D3.js (Data-Driven Documents) 是一個基于 JavaScript 的庫&#xff0c;用于生成動態、交互式數據可視化。它通過操作文檔對象模型 (DOM) 來生成數據驅動的圖形。官方網站是 https://d3js.org/ <!DOCTYPE html> <html lang"en"><head><me…

基線檢查:Windows安全基線.【手動 || 自動】

基線定義 基線通常指配置和管理系統的詳細描述&#xff0c;或者說是最低的安全要求&#xff0c;它包括服務和應用程序設置、操作系統組件的配置、權限和權利分配、管理規則等。 基線檢查內容 主要包括賬號配置安全、口令配置安全、授權配置、日志配置、IP通信配置等方面內容&…

Python -- Linux中的Matplotlib圖中無法顯示中文 (中文為方框)

目的 用matplotlib生成的圖中文無法正常顯示 方法 主要原因: 沒找到字體 進入windows系統的C:\Windows\Fonts目錄, 復制自己想要的字體 粘貼到Linux服務器中對應python文件所處的文件夾內 設置字體: 設置好字體文件的路徑在需要對字體設置的地方設置字體 效果 中文正常顯…

快速理解類的加載過程

當程序主動使用某個類時&#xff0c;如果該類還未加載到內存中&#xff0c;則系統會通過如下三個步驟來對該類進行初始化&#xff1a; 1.加載&#xff1a;將class文件字節碼內容加載到內存中&#xff0c;并將這些靜態數據轉換成方法區的運行時數據結構&#xff0c;然后生成一個…

搭建 Elasticsearch 集群:完整教程

本文將詳細介紹如何在 Linux 環境下搭建一個 Elasticsearch 集群&#xff0c;涵蓋環境準備、配置優化、服務啟動等多個環節。 一、環境準備 創建安裝目錄 mkdir /es cd /es解壓 Elasticsearch 安裝包 tar -xzf elasticsearch-7.10.1-linux-x86_64.tar.gz -C /es配置環境變量 編…

寶塔-docker拉取寶塔鏡像,并運行寶塔鏡像

寶塔-拉取寶塔鏡像&#xff0c;并運行鏡像 第1步&#xff1a;查詢 docker search btpanel/baota此docker鏡像由堡塔安全官方發布&#xff0c;鏡像版本為寶塔面板9.2.0正式版和9.0.0_lts 穩定版&#xff0c;鏡像會隨著寶塔面板更新。 目前支持x86_64和arm架構可供下載使用 版本…

使用 Valgrind 檢測 C 程序中的內存問題 -基礎教程

內存泄漏是許多 C 語言程序中的常見問題&#xff0c;它不僅會導致程序性能下降&#xff0c;甚至可能讓系統崩潰。為了檢測和修復這些問題&#xff0c;Valgrind 是一個非常強大的工具&#xff0c;它可以幫助我們分析 C 程序中的內存使用情況&#xff0c;檢測內存泄漏、越界訪問、…

窮舉vs暴搜vs深搜vs回溯vs剪枝專題一>子集

題目&#xff1a; 兩個方法本質就是決策樹的畫法不同 方法一解析&#xff1a; 代碼&#xff1a; class Solution {private List<List<Integer>> ret;//返回結果private List<Integer> path;//記錄路徑&#xff0c;注意返回現場public List<List<Int…

leecode雙指針部分題目

leecode雙指針部分題目 1. 驗證回文串2. 判斷子序列3. 兩數之和 II - 輸入有序數組4. 盛最多水的容器5. 三數之和 1. 驗證回文串 如果在將所有大寫字符轉換為小寫字符、并移除所有非字母數字字符之后&#xff0c;短語正著讀和反著讀都一樣。則可以認為該短語是一個 回文串 。 …

Web 應用如何使用sqlite?使用 sql.js 實現前端 SQLite 數據庫操作

前言 在 Web 應用開發中&#xff0c;前端數據處理的重要性日益增加。為了實現更高效的前端數據管理&#xff0c;特別是在處理結構化數據時&#xff0c;sql.js 提供了一個出色的解決方案。sql.js 是將 SQLite 數據庫編譯為 JavaScript 的庫&#xff0c;允許開發者在瀏覽器環境中…

docker 安裝 mysql8.0容器外無法連接

文章目錄 概要問題描述解決方案其他命令 概要 主要是mysql5.7和mysql8.0的兼容性問題。 排查了很久 其實就是配置文件的一句話的事情 感覺mysql8.0更為嚴謹 這樣可能是考慮杜絕一些漏洞吧 問題描述 在容器內 netstat -an | grep 3306 都不行 在容器外 netstat -an | grep 2…

TCP協議簡單分析和握手揮手過程

TCP介紹 TCP是可靠的傳輸層協議&#xff0c;建立連接之前會經歷3次握手的階段。 確認機制&#xff1a;接受方 收到數據之后會向 發送方 回復ACK重傳機制&#xff1a;發送方 在一定時間內沒有收到 接收方的ACK就會重新發送 握手目的&#xff1a;與端口建立連接 TCP的三次握手 …

VisualStudio vsix插件自動加載

本文介紹如何在Visual Studio擴展中實現PackageRegistration&#xff0c;包括設置UseManagedResourcesOnly為true&#xff0c;允許背景加載&#xff0c;并針對C#、VB、F#項目提供自動裝載&#xff0c;附官方文檔鏈接。增加以下特性即可…… [PackageRegistration(UseManagedRe…

opencv所有常見函數

一、opencv圖像操作 二、opencv圖像的數值運算 三、opencv圖像的放射變換 四、opencv空間域圖像濾波 五、圖像灰度化與直方圖 六、形態學圖像處理 七、閾值處理與邊緣檢測 八、輪廓和模式匹配

【Excel】單元格分列

目錄 分列&#xff08;新手友好&#xff09; 1. 選中需要分列的單元格后&#xff0c;選擇 【數據】選項卡下的【分列】功能。 2. 按照分列向導提示選擇適合的分列方式。 3. 分好就是這個樣子 智能分列&#xff08;進階&#xff09; 高級分列 Tips&#xff1a; 新手推薦基…

【STM32練習】基于STM32的PM2.5環境監測系統

一.項目背景 最近為了完成老師交付的任務&#xff0c;遂重制了一下小項目用STM32做一個小型的環境監測系統。 項目整體示意框圖如下&#xff1a; 二.器件選擇 單片機&#xff08;STM32F103&#xff09;數字溫濕度模塊&#xff08;DHT11&#xff09;液晶顯示模塊&#xff08;0.8…

《開源數據:開啟信息共享與創新的寶藏之門》

《開源數據&#xff1a;開啟信息共享與創新的寶藏之門》 一、開源數據概述&#xff08;一&#xff09;開源數據的定義&#xff08;二&#xff09;開源數據的發展歷程 二、開源數據的優勢&#xff08;一&#xff09;成本效益優勢&#xff08;二&#xff09;靈活性與可定制性&…