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.mzph.cn/web/63148.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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;然后生成一个…

宝塔-docker拉取宝塔镜像,并运行宝塔镜像

宝塔-拉取宝塔镜像&#xff0c;并运行镜像 第1步&#xff1a;查询 docker search btpanel/baota此docker镜像由堡塔安全官方发布&#xff0c;镜像版本为宝塔面板9.2.0正式版和9.0.0_lts 稳定版&#xff0c;镜像会随着宝塔面板更新。 目前支持x86_64和arm架构可供下载使用 版本…

穷举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;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 …

TCP协议简单分析和握手挥手过程

TCP介绍 TCP是可靠的传输层协议&#xff0c;建立连接之前会经历3次握手的阶段。 确认机制&#xff1a;接受方 收到数据之后会向 发送方 回复ACK重传机制&#xff1a;发送方 在一定时间内没有收到 接收方的ACK就会重新发送 握手目的&#xff1a;与端口建立连接 TCP的三次握手 …

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…

ReactPress最佳实践—搭建导航网站实战

Github项目地址&#xff1a;https://github.com/fecommunity/easy-blog 欢迎Star。 近期&#xff0c;阮一峰在科技爱好者周刊第 325 期中推荐了一款开源工具——ReactPress&#xff0c;ReactPress一个基于 Next.js 的博客和 CMS 系统&#xff0c;可查看 demo站点。&#xff08;…

2024,大模型杀进“决赛圈”

Henry Chesbrough在著作《通过技术创新盈利势在必行》中&#xff0c;曾提出过一个创新的“漏斗模型”。开放式创新一开始鼓励百花齐放&#xff0c;但最终只有10%的技术能够通过这个漏斗&#xff0c;成功抵达目标市场target market&#xff0c;进入到商业化与产业化的下一个阶段…

STM8单片机学习笔记·GPIO的片上外设寄存器

目录 前言 IC基本定义 三极管基础知识 单片机引脚电路作用 STM8GPIO工作模式 GPIO外设寄存器 寄存器含义用法 CR1&#xff1a;Control Register 1 CR2&#xff1a;Control Register 2 ODR&#xff1a;Output Data Register IDR&#xff1a;Input Data Register 赋值…

【CSS in Depth 2 精译_081】 13.1:CSS 渐变效果(下)——CSS 径向渐变(13.1.3)+ CSS 锥形渐变(13.1.4)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 13 章 渐变、阴影与混合模式】 ✔️ 13.1 渐变 ✔️ 13.1.1 使用多个颜色节点&#xff08;上&#xff09;13.1.2 颜色插值方法&#xff08;中&#xff09;13.1.3 径…

ubuntu 用 ss-tproxy的最终网络结构

1、包含了AD广告域名筛选 2、Ss-tproxy 国内国外地址分类 3、chinadns-ng解析 4、透明网关 更多细节看之前博客 ubuntu 用ss-TPROXY实现透明代理&#xff0c;基于TPROXY的透明TCP/UDP代理,在 Linux 2.6.28 后进入官方内核。ubuntu 用 ss-tproxy的内置 DNS 前挂上 AdGuardHome…

BUUCTF Pwn [HarekazeCTF2019]baby_rop2 题解

下载 得到两个文件 checksec 64位 拖入IDA64 查看main函数 看到给了个libc说明这题是ret2libc题 这里的打印函数是printf 所以利用printf函数的plt输出真实地址got 但printf的got好像不行 所以换成了read的got 因为这是64位程序 所以用寄存器传参&#xff1b;又因为printf得…

语音识别失败 chrome下获取浏览器录音功能,因为安全性问题,需要在localhost或127.0.0.1或https下才能获取权限

环境&#xff1a; Win10专业版 谷歌浏览器 版本 131.0.6778.140&#xff08;正式版本&#xff09; &#xff08;64 位&#xff09; 问题描述&#xff1a; 局域网web语音识别出现识别失败 chrome控制台出现下获取浏览器录音功能&#xff0c;因为安全性问题&#xff0c;需要在…

【一本通】输入两个不同的数,通过指针对两个数进行相加和相乘

【一本通】输入两个不同的数&#xff0c;通过指针对两个数进行相加和相乘 C语言代码C代码Java代码 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 输入两个不同的数&#xff0c;通过指针对两个数进行相加和相乘&#xff0c;并输出。 输入 …

X.game解析柚子币提升速效双向利好和年中历史新低原因

柚子币最新消息&#xff0c;币安宣布将于2024年9月25日21:00左右暂停柚子币网络上的代币存取业务&#xff0c;以全力支持即将到来的柚子币网络升级和硬分叉&#xff0c;这一消息为柚子币的未来发展增添了新的期待和变数。 除了速度的提升&#xff0c;Spring1.0还带来了诸多技术…