手写tomcat(Ⅲ)——tomcat动态资源的获取

仿写tomcat的Servlet接口体系

之前写过一篇博客,Tomcat的Servlet-GenericServlet-HttpServlet体系的具体结构,以及Servlet的生命周期
Servlet讲解

想要模仿tomcat获取动态资源,就需要我们自己仿写一个Servlet接口体系

主要包括:注解,相关的接口+子类,搜索包名下的所有servlet的工具类

MyWebServlet注解

我们首先需要定义一个MyWebServlet注解,仿照了WebServlet注解

import java.lang.annotation.*;@Target({ElementType.TYPE})// 作用到类
@Retention(RetentionPolicy.RUNTIME)// 运行阶段
public @interface MyWebServlet {// 定义url变量,并规定默认值为空字符String className() default "";String url() default "";
}

相关的接口+子类

MyServlet接口,定义了Servlet的生命周期

import java.io.IOException;import com.qcby.config.MyServletConfig;// 自定义的servlet接口
public interface MyServlet {void init();MyServletConfig getServletConfig();String getServletInfo();void service(Request request, Response response) throws IOException;void destroy();
}

自定义的MyServletConfig类

/*** 将获取到的url和classPath径封装到该对象当中*/
public class MyServletConfig {private String url;private String classPath;public MyServletConfig(String url, String classPath) {this.url = url;this.classPath = classPath;}public MyServletConfig() {}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getClassPath() {return classPath;}public void setClassPath(String classPath) {this.classPath = classPath;}
}

抽象类MyGenericServlet实现了除service以外的方法

import com.qcby.config.MyServletConfig;public abstract class MyGenericServlet implements MyServlet {@Overridepublic void init() {}@Overridepublic MyServletConfig getServletConfig() {return new MyServletConfig();}@Overridepublic String getServletInfo() {return "";}@Overridepublic void destroy() {}
}

抽象类MyHttpServlet,实现了service方法,并将其分化为doGet,doPost,doDelete等方法

import java.io.IOException;public abstract class MyHttpServlet extends MyGenericServlet {// 重写service方法,将其分化为不同的方法// 抽象类MyHttpServlet没有抽象方法@Overridepublic void service(Request request, Response response) throws IOException {// 判断request的methodType,转发到doGet/doPost当中if ("GET".equals(request.getMethodType())) {myDoGet(request, response);} else if ("POST".equals(request.getMethodType())) {myDoPost(request, response);}}public void myDoGet(MyHttpServletRequest req, MyHttpServletResponse resp) throws IOException {}public void myDoPost(MyHttpServletRequest req, MyHttpServletResponse resp) throws IOException {}}

这里的MyHttpServletRequest还有MyHttpServletResponse,是两个接口


public interface MyHttpServletRequest {
}
public interface MyHttpServletResponse {void write(String context) throws IOException;
}

分别由Request类和Response类实现

public class Request implements MyHttpServletRequest{private String url;private String methodType;public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getMethodType() {return methodType;}public void setMethodType(String methodType) {this.methodType = methodType;}
}
/*** 做数据的返回*/
public class Response implements MyHttpServletResponse {// 获取输出流private OutputStream outputStream;public Response(OutputStream outputStream) {this.outputStream = outputStream;}// 静态资源的输出public void writeHtml(String path) throws Exception {//// 根据路径返回资源路径地址,例如http://localhost:8666/index.htmlString resource = FileUtil.getResoucePath(path);File file = new File(resource);if (file.exists()) {// 静态资源存在!System.out.println("静态资源存在!");FileUtil.writeFile(file, outputStream);} else {System.out.println(path + "对应的该静态资源不存在!");}}// 数据写回public void write(String context) throws IOException {outputStream.write(context.getBytes());outputStream.flush();}
}

加载servlet包下的所有servlet,并将其MyWebServlet注解的url值和对应的servlet类对象组装成一个map(最重要)

上面基本都是照猫画葫芦的仿写,其实该实现的方法完全没实现,跟原本的tomcat相比差的比较多

但是这一部分,还原度比较高,tomcat本身也是扫描包,并且反射获取注解的取值,最后组成HashMap来映射servlet的

SearchClassUtil

/*** 扫描指定包,获取该包下所有的类的全路径信息*/
public class SearchClassUtil {public static List<String> classPaths = new ArrayList<String>();public static List<String> searchClass(){//需要扫描的包名String basePack = "com.qcby.webapp";//将获取到的包名转换为路径String classPath = SearchClassUtil.class.getResource("/").getPath();basePack =  basePack.replace(".", File.separator);String searchPath = classPath + basePack;doPath(new File(searchPath),classPath);//这个时候我们已经得到了指定包下所有的类的绝对路径了。我们现在利用这些绝对路径和java的反射机制得到他们的类对象return classPaths;}/*** 该方法会得到所有的类,将类的绝对路径写入到classPaths中* @param file*/private static void doPath(File file,String classpath) {if (file.isDirectory()) {//文件夹//文件夹我们就递归File[] files = file.listFiles();for (File f1 : files) {doPath(f1,classpath);}} else {//标准文件//标准文件我们就判断是否是class文件if (file.getName().endsWith(".class")) {String path = file.getPath().replace(classpath.replace("/","\\").replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");//如果是class文件我们就放入我们的集合中。classPaths.add(path);}}}public static void main(String[] args) {List<String> classes = SearchClassUtil.searchClass();for (String s: classes) {System.out.println(s);}}
}

tomcat启动类

对静态资源和动态资源做了判断

package com.qcby.tomcatDemo;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URLDecoder;import com.qcby.config.ServletConfigMapping;
import com.qcby.servlet.MyServlet;
import com.qcby.servlet.Request;
import com.qcby.servlet.Response;
import com.qcby.util.ResponseUtil;/*** tomcat启动类*/
public class TomcatStart {private static Request request = new Request();public static void main(String[] args) throws IOException, ClassNotFoundException {System.out.println("socket服务器启动!!!");// 0. 加载servlet类信息ServletConfigMapping.init();// 1. 打开相关通信端口// tomcat:8080,mysql:3306,应用软件独占一个端口的全部信息ServerSocket serverSocket = new ServerSocket(8666);// 线程持续扫描当前网卡xxxx端口(死循环),如果有数据就拿过来,交给端口对应的程序处理// 2. 监听并接收请求数据while (true) {// 一旦发现有数据,就打开socket通信// 这里没有创建新的线程,所以这里是main线程监听数据Socket socket = serverSocket.accept();System.out.println(socket.getInetAddress().getCanonicalHostName() + "进行了连接!");// 第二步监听并接收到了数据,处理数据可以用主线程,但是没必要,创建子线程处理// 每接收一次数据,创建一个子线程Thread t1 = new Thread(() -> {// 处理数据包括两部分:读和写try {dataHandle(socket);} catch (Exception e) {throw new RuntimeException(e);}});t1.start();}}// 处理数据的方法,读+写public static void dataHandle(Socket socket) throws Exception {// 1. 读取请求的数据// 1.1打开输入流对象,读取socket对象中的数据,这里的数据都是0101010的二进制数据InputStream inputStream = socket.getInputStream();requestContext(inputStream);// 数据的输出Response response = new Response(socket.getOutputStream());if ("".equals(request.getUrl())) {response.write(ResponseUtil._404ResponseHeader);} else if (ServletConfigMapping.classMap.get(request.getUrl()) != null) {// 动态web资源dispatch(request, response);} else {// 访问静态资源response.writeHtml(request.getUrl());}}public static void dispatch(Request request, Response response) throws InstantiationException, IllegalAccessException, IOException {Class<MyServlet> servletClass = ServletConfigMapping.classMap.get(request.getUrl());if (servletClass != null) {MyServlet myServlet = servletClass.newInstance();myServlet.service(request, response);}}public static void requestContext(InputStream inputStream) throws IOException {//  1.2 二进制数据的翻译并读取int count = 0;while (count == 0) {// 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。// 下一个调用可能是同一个线程,也可能是另一个线程。// 一次读取或跳过此估计数个字节不会受阻塞,但读取或跳过的字节数可能小于该数。// 可以不受阻塞地从此输入流读取(或跳过)的估计字节数;如果到达输入流末尾,则返回 0count = inputStream.available();}byte[] bytes = new byte[count];inputStream.read(bytes);// 这里用URLDecoder是为了防止路径中出现特殊符号,经过get请求之后会被URLEncode为乱码String context = URLDecoder.decode(new String(bytes, "utf-8"));// Base64.getDecoder().decode(bytes)System.out.println("===context:" + context);if ("".equals(context)) {System.out.println("null request!");request.setUrl("");request.setMethodType("");} else {//根据换行来获取第一行数据String firstLine = context.split("\\n")[0];// 第一行数据的第2个字符串System.out.println("===url:" + firstLine.split("\\s")[1]);request.setUrl(firstLine.split("\\s")[1]);// 第一行数据的第1个字符串System.out.println("===methodType:" + firstLine.split("\\s")[0]);request.setMethodType(firstLine.split("\\s")[0]);}}
}

webapp包下有两个servlet
在这里插入图片描述

@MyWebServlet(url = "/first")
public class FirstServlet extends MyHttpServlet {@Overridepublic void myDoGet(MyHttpServletRequest req, MyHttpServletResponse resp) throws IOException {String context = "<h1>这是FirstServlet的myDoGet方法</h1>";resp.write(ResponseUtil.makeResponse(context, ResponseUtil.htmlResponseHeader));}@Overridepublic void myDoPost(MyHttpServletRequest req, MyHttpServletResponse resp) throws IOException {String context = "<h1>这是FirstServlet的myDoPost方法</h1>";resp.write(ResponseUtil.makeResponse(context, ResponseUtil.htmlResponseHeader));}
}
@MyWebServlet(url = "/hello")
public class HelloServlet extends MyHttpServlet {@Overridepublic void myDoGet(MyHttpServletRequest req, MyHttpServletResponse resp) throws IOException {String context = "<h1>这是HelloServlet的myDoGet方法</h1>";resp.write(ResponseUtil.makeResponse(context, ResponseUtil.htmlResponseHeader));}@Overridepublic void myDoPost(MyHttpServletRequest req, MyHttpServletResponse resp) throws IOException {String context = "<h1>这是HelloServlet的myDoPost方法</h1>";resp.write(ResponseUtil.makeResponse(context, ResponseUtil.htmlResponseHeader));}
}

项目下还有一个静态资源index.html
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><p>Hello TomcatDemo!!!</p>
</body>
</html>

我们在浏览器分别测试静态和动态资源的获取

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/332091.html

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

相关文章

软考-下午题-试题二、三

主要是最后一问的不同解答 1、父图子图平衡 1、员工关系是否存在传递依赖&#xff1f;用100字以内的文字说明理由。2019 2、在职员关系模式中&#xff0c;假设每个职员有多名家属成员&#xff0c;那么职员关系模式存在什么问题&#xff1f; 应如何解决&#xff1f;2020 职员关系…

Science 基于尖峰时序编码的模拟神经触觉系统,可实现动态对象分类

快速处理和有效利用手与物体交互过程中产生的动态触觉信号&#xff08;例如触摸和抓握&#xff09;对于触觉探索和灵巧的物体操作至关重要。将电子皮肤&#xff08;e-skins&#xff09;推进到模仿自然触觉的水平&#xff0c;是恢复截肢者和瘫痪患者丧失的功能的可行解决方案&am…

奥维互动地图奥维彩色图源

彩色图源(不足&#xff0c;更精细放大) 等位线3D模式 中科星 谷歌2024(不足没以前高清)

题解:CF1016E Rest In The Shades

题意 平面上有一个点光源 s s s 并以每秒 1 1 1 单位长度的速度从点 ( a , s y ) (a,sy) (a,sy) 移动到点 ( b , s y ) (b,sy) (b,sy)&#xff0c;其中 s y < 0 sy<0 sy<0&#xff1b;在 x x x 轴正方向上有 n n n 不相交、不接触的挡板&#xff0c;第 i i i …

Visual Studio 的调试(一)

最近事儿很多昂&#xff0c;更新速度相较以往慢了许多&#xff0c;备考六月份的四级&#xff0c;还有学校的期末等等&#xff0c;事儿真的太多啦&#xff0c;所以后面的更新速度也会放慢一点&#xff0c;实在是抽不开身啊诸位&#xff0c;相当抱歉&#xff0c;还望诸君见谅 言…

【LLM多模态】多模态LLM在图表处理的应用

note 在真实场景下&#xff0c;我们进行测试&#xff0c;多模态大模型在处理显著文本时表现尚可&#xff0c;但在处理细粒度文本时往往效果并不太好&#xff0c;why? ​具体原因如下&#xff1a; 首先&#xff0c;视觉编码器的分辨率对于多模态大模型的性能影响较大&#x…

树莓派4B 有电但无法启动

试过多个SD卡&#xff0c;反复烧系统镜像都无法启动。接HDMI显示器没有信号输出&#xff0c;上电后PWR红灯长亮&#xff0c;ACT绿灯闪一下就不亮了&#xff0c;GPIO几个电源脚有电&#xff0c;芯片会发热&#xff0c;测量多个TP点电压好像都正常。 ……

Java面试题--JVM大厂篇(1-10)

引言&#xff1a; 在这个信息时代&#xff0c;对于准备进入大厂工作的朋友们来说&#xff0c;对于JVM&#xff08;Java虚拟机&#xff09;的掌握是面试中的一项重要内容。下面是一些精选的JVM面试题&#xff0c;希望对大家能有所帮助。 正文&#xff1a; 1. JVM有哪几种垃圾收…

用Python一键生成PNG图片的PowerPoint幻灯片

在当今的商业环境中,PowerPoint演示是展示和传递信息的常用方式。然而,手动将大量图像插入到幻灯片中往往是一项乏味且耗时的工作。但是,通过Python编程,我们可以轻松自动化这个过程,节省时间和精力。 C:\pythoncode\new\folderTOppt.py 在本文中,我将介绍如何使用Python、wx…

C/C++ vector详解

要想了解STL&#xff0c;就必须会看&#xff1a; cplusplus.comhttps://legacy.cplusplus.com/ 官方内容全都是英文的&#xff0c;可以参考&#xff1a; C/C初始识https://blog.csdn.net/2301_77087344/article/details/138596294?spm1001.2014.3001.5501 vector&#xff…

redisson的使用及LUA脚本实现分布式秒杀

1.redisson实现分布式锁(推荐) redisson官网&#xff1a;Redisson: Easy Redis Java client and Real-Time Data Platform Redisson是一个基于Redis的Java客户端&#xff0c;它不仅提供了对Redis基本操作的支持&#xff0c;而且是一个功能丰富的分布式协调服务客户端。Rediss…

知识分享:隔多久查询一次网贷大数据信用报告比较好?

随着互联网金融的快速发展&#xff0c;越来越多的人开始接触和使用网络贷款。而在这个过程中&#xff0c;网贷大数据信用报告成为了评估借款人信用状况的重要依据。那么&#xff0c;隔多久查询一次网贷大数据信用报告比较好呢?接下来随小易大数据平台小编去看看吧。 首先&…

Pandas 多层索引中的索引和切片操作你学会了吗

1. Series的索引操作 对于Series来说&#xff0c;直接中括号[]与使用 .loc() 完全一样 显式索引 # 导包import numpy as npimport pandas as pd data np.random.randint(0,100,size6) index [ ["1班","1班","1班","2班","…

C++——list的实现以及源码

前言&#xff1a; 最近学习了clist的实现&#xff0c;这让我对迭代器的理解又上升了一个新的高度&#xff0c;注意&#xff1a;代码里的list是放在一个叫zgw的命名空间里边&#xff0c;但是在实现list的代码中没有加namespace&#xff0c;这里给个注意&#xff0c;以后复习时能…

颜色值进制转换

颜色值进制转换 专业的和非专业程序员在编程时都碰到过颜色值的表达式。特别是在编制网页和设计界面时&#xff0c;都要选择颜色。各语言的颜色值表达式就两种&#xff0c;十六进制的颜色值hex$和十进制的RGB格式。现成的调色板颜色表也是这两种格式。写代码时会遇到写颜色值码…

Linux-组管理和权限管理

1 Liunx组的基本介绍&#xff1a; 在Linux中的每个用户必须属于一个组&#xff0c;不能独立于组外。在Linux中每个文件都有所有者、所在组、其他组的概念 所有者所在组其它组改变用户所在的组 2 文件/目录的所有者 一般文件的创建者&#xff0c;谁创建了该文件&#xff0c;就…

垃圾回收机制及算法

文章目录 概要对象存活判断引用计数算法可达性分析算法对象是否存活各种引用 垃圾收集算法分代收集理论复制算法标记清除算法标记-整理算法 概要 垃圾收集&#xff08;Garbage Collection&#xff0c; 下文简称GC&#xff09;&#xff0c;其优缺点如下&#xff1a; 优点&#…

Shell

Linux中shell是Linux内核的一个外层保护工具&#xff0c;负责用户与内核互交。是一直命令行解析器&#xff0c;是指一直应用程序&#xff0c;且提供一个界面 还是一种编程语言. 查看当前系统的Shell 查看有哪些shell&#xff0c;用cat /etc/shells 查看当前系统默认的shell&…

二十八篇:嵌入式系统实战指南:案例研究与未来挑战

嵌入式系统实战指南&#xff1a;案例研究与未来挑战 1. 引言 1.1 嵌入式系统的重要性及其应用广度 在当今快速发展的技术领域中&#xff0c;嵌入式系统扮演着至关重要的角色。这些系统是专门设计的计算机硬件和软件的组合&#xff0c;旨在执行特定任务&#xff0c;如控制、监…

牛马真的沉默了,入职第一天就干活

入职第一天就干活的&#xff0c;就问还有谁&#xff0c;搬来一台N手电脑&#xff0c;第一分钟开机&#xff0c;第二分钟派活&#xff0c;第三分钟干活&#xff0c;巴适。。。。。。 打开代码发现问题不断 读取配置文件居然读取两个配置文件&#xff0c;一个读一点&#xff0c;…