DIY-Tomcat part 3 实现对动态资源的请求
实现ServletRequest
package connector;import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;/*
GET /index.html HTTP/1.1Host: localhost:8888Connection: keep-aliveCache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
*/public class Request implements ServletRequest {private static final int BUFFER_SIZE = 1024;private InputStream input;private String uri;public Request(InputStream input) {this.input = input;}public String getRequestURI() {return uri;}public void parse() {int length = 0;byte[] buffer = new byte[BUFFER_SIZE];try {length = input.read(buffer);} catch (IOException e) {e.printStackTrace();}StringBuilder request = new StringBuilder();for (int j=0; j<length; j++) {request.append((char)buffer[j]);}uri = parseUri(request.toString());}private String parseUri(String s) {int index1, index2;index1 = s.indexOf(' ');if (index1 != -1) {index2 = s.indexOf(' ', index1 + 1);if (index2 > index1) {return s.substring(index1 + 1, index2);}}return "";}@Overridepublic Object getAttribute(String s) {return null;}@Overridepublic Enumeration getAttributeNames() {return null;}@Overridepublic String getCharacterEncoding() {return null;}@Overridepublic void setCharacterEncoding(String s) throws UnsupportedEncodingException {}@Overridepublic int getContentLength() {return 0;}@Overridepublic String getContentType() {return null;}@Overridepublic ServletInputStream getInputStream() throws IOException {return null;}@Overridepublic String getParameter(String s) {return null;}@Overridepublic Enumeration getParameterNames() {return null;}@Overridepublic String[] getParameterValues(String s) {return new String[0];}@Overridepublic Map getParameterMap() {return null;}@Overridepublic String getProtocol() {return null;}@Overridepublic String getScheme() {return null;}@Overridepublic String getServerName() {return null;}@Overridepublic int getServerPort() {return 0;}@Overridepublic BufferedReader getReader() throws IOException {return null;}@Overridepublic String getRemoteAddr() {return null;}@Overridepublic String getRemoteHost() {return null;}@Overridepublic void setAttribute(String s, Object o) {}@Overridepublic void removeAttribute(String s) {}@Overridepublic Locale getLocale() {return null;}@Overridepublic Enumeration getLocales() {return null;}@Overridepublic boolean isSecure() {return false;}@Overridepublic RequestDispatcher getRequestDispatcher(String s) {return null;}@Overridepublic String getRealPath(String s) {return null;}
}
- 主要是为了实现ServletRequest 接口
实现ServletResponse
package connector;import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import java.io.*;
import java.util.Locale;/*
HTTP/1.1 200 OK*/
public class Response implements ServletResponse {private static final int BUFFER_SIZE = 1024;Request request;OutputStream output;public Response(OutputStream output) {this.output = output;}public void setRequest(Request request) {this.request = request;}public void sendStaticResource() throws IOException {File file = new File(ConnectorUtils.WEB_ROOT, request.getRequestURI());try {write(file, HttpStatus.SC_OK);} catch (IOException e) {write(new File(ConnectorUtils.WEB_ROOT, "404.html"), HttpStatus.SC_NOT_FOUND);}}private void write(File resource, HttpStatus status) throws IOException {try (FileInputStream fis = new FileInputStream(resource)) {output.write(ConnectorUtils.renderStatus(status).getBytes());byte[] buffer = new byte[BUFFER_SIZE];int length = 0;while ((length = fis.read(buffer, 0, BUFFER_SIZE)) != -1) {output.write(buffer, 0, length);}}}@Overridepublic String getCharacterEncoding() {return null;}@Overridepublic ServletOutputStream getOutputStream() throws IOException {return null;}@Overridepublic PrintWriter getWriter() throws IOException {PrintWriter writer = new PrintWriter(output, true);return writer;}@Overridepublic void setContentLength(int i) {}@Overridepublic void setContentType(String s) {}@Overridepublic void setBufferSize(int i) {}@Overridepublic int getBufferSize() {return 0;}@Overridepublic void flushBuffer() throws IOException {}@Overridepublic void resetBuffer() {}@Overridepublic boolean isCommitted() {return false;}@Overridepublic void reset() {}@Overridepublic void setLocale(Locale locale) {}@Overridepublic Locale getLocale() {return null;}
}
- 也是主要为了实现ServletRequest 接口
- 实现getWriter()方法
实现Servlet
import connector.ConnectorUtils;
import connector.HttpStatus;
import connector.Request;import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;public class TimeServlet implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {PrintWriter out = servletResponse.getWriter();out.println(ConnectorUtils.renderStatus(HttpStatus.SC_OK));out.println("What time is it now?");out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));}@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {}
}
- service实时返回当前时间的具体值
实现ServletProcessor
package processor;import connector.*;import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;public class ServletProcessor {URLClassLoader getServletLoader() throws MalformedURLException {File webroot = new File(ConnectorUtils.WEB_ROOT);URL webrootUrl = webroot.toURI().toURL();return new URLClassLoader(new URL[]{webrootUrl});}Servlet getServlet(URLClassLoader loader, Request request) throws ClassNotFoundException, IllegalAccessException, InstantiationException {/*/servlet/TimeServlet*/String uri = request.getRequestURI();String servletName = uri.substring(uri.lastIndexOf("/") + 1);Class servletClass = loader.loadClass(servletName);Servlet servlet = (Servlet) servletClass.newInstance();return servlet;}public void process(Request request, Response response) throws IOException {//加载loader, 以获得具体servlet的上级目录URLClassLoader loader = getServletLoader();//通过request中的uri和loader中的上级目录加载对应的具体servlet类处理请求Servlet servlet = getServlet(loader, request);//用加载的servlet类处理请求servlet.service(request, response);
}
主要方法功能解释:
- Class servletClass = loader.loadClass(servletName);
loader会从webrootUrl的路径下尝试加载名字为servletName的类,这是实现请求动态资源的关键 - 用loader和request加载具体的servlet,再用该servlet处理请求,输出内容
改进Connector
改进Connector使其能够处理来自客户端对动态资源的访问请求
if (request.getRequestURI().startsWith("/servlet/")) {ServletProcessor processor = new ServletProcessor();processor.process(request, response);} else {StaticProcessor processor = new StaticProcessor();processor.process(request, response);}
- 如果请求是以/servlet/开头的,代表是对动态资源的请求,则将该请求交由ServletProcessor处理
- 如果不是以/servlet/开头的,代表是对静态资源的请求,则交由StaticProcessor处理
测试
IDE客户端请求测试
public static void main(String[] args)throws Exception{Socket socket = new Socket("localhost", 8888);OutputStream output = socket.getOutputStream();output.write("GET /servlet/TimeServlet HTTP/1.1".getBytes());socket.shutdownOutput();InputStream input = socket.getInputStream();byte[] buffer = new byte[2048];int length = input.read(buffer);StringBuilder response = new StringBuilder();for (int j=0; j<length; j++) {response.append((char)buffer[j]);}System.out.println(response.toString());socket.shutdownInput();socket.close();}
web浏览器测试

上述两种测试方法均能返回正确结果
相关文章:
DIY-Tomcat part 3 实现对动态资源的请求
实现ServletRequest package connector;import javax.servlet.RequestDispatcher; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.i…...
3.10 内核 BUG_ON() at xfs_vm_writepage() -> page_buffers()
目录 前言 问题分析 page buffers创建 page buffers丢失 Write-Protect Dirty Page w/o Buffers 问题解决 前言 这个问题发生在3.10.0-514.el7上,并且在RHEL的知识库中快速找到了对应的案例以及解决方案,但是,理解问题如何发生和解决…...
CrystalDiskInfo:硬盘健康监测工具简介和下载
原论坛给你更好的阅读体验:CrystalDiskInfo:硬盘健康监测工具简介和下载 | 波波论坛 引言 在日常使用电脑时,硬盘的健康状态对于系统的稳定性和数据的安全性至关重要。硬盘出现故障可能会导致数据丢失,严重时甚至会使整个系统无…...
Flink cdc同步增量数据timestamp字段相差八小时(分析|解决)不是粘贴复制的!
问题 我使用flink cdc同步mysql到mysql遇到了timestamp字段缺少八小时的问题。很少无语,flink ,cdc,debezium时区都设置了,没有任何效果! 分析 问题出现在mysql binlog身上!!! 因为默认mysql会使用UTC来…...
【docker】9. 镜像操作与实战
镜像操作案例 查找镜像 docker search busybox下载镜像 docker pull busybox:1.36.0查看镜像及列表存储位置 rootLAPTOP-H2EI4I6A:~# docker images busybox REPOSITORY TAG IMAGE ID CREATED SIZE busybox latest 517b897a6a83 2 months a…...
js-显示转换(强制转换)与隐式转换,==与===区别
1.显示转换(强制转换)与隐式转换 1.1显示转换 常见的JavaScript强制转换示例。 (1) 一元加号、一元减号- 值是布尔值,true将被转换为1,false将被转换为0。 let a "123"; let b a; // b的值为123,类型为Nu…...
【通俗理解】步长和学习率在神经网络中是一回事吗?
【通俗理解】步长和学习率在神经网络中是一回事吗? 【核心结论】 步长(Step Size)和学习率(Learning Rate, LR)在神经网络中并不是同一个概念,但它们都关乎模型训练过程中的参数更新。 【通俗解释&#x…...
【PTA】【数据库】【SQL命令】编程题2
数据库SQL命令测试题2 测试题目录 10-1 查询“李琳”老师所授课程的课程名称10-2 查询成绩比所有课程的平均成绩高的学生的学号及成绩10-3 创建带表达式的视图StuView10-4 从视图PerView中查询数据10-5 查询工资高于在“HR”部门工作的所有员工的工资的员工信息10-6 查询选修的…...
Spring Boot林业产品推荐系统:用户指南
摘 要 网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信息的宣传和管理就很关键。因此林业产品销售信…...
【Conda 】Conda 配置文件详解:优化你的包管理与环境设置
目录 引言一、什么是 .condarc 文件?二、.condarc 文件的详细解析与优化2.1 SSL 验证2.2 设置 Conda 下载源2.3 设置环境和包存储路径2.4 代理服务器设置2.5 连接超时设置2.6 显示频道 URL2.7 包版本与构建选择2.8 环境依赖性管理2.9 禁用默认包版本2.10 Conda 配置…...
win10中使用ffmpeg的filter滤镜
1 给视频加文字水印 1.1 添加播放时间 ffmpeg -i input.mp4 -vf "drawtextfontfileC\\:/Windows/fonts/consola.ttf:fontsize30:fontcolorwhite:timecode00\:00\:00\:00:rate25:textTCR\::boxcolor0x000000AA:box1:x20:y20" -y output.mp4 在视频的x20:y20位置添加t…...
设计模式 外观模式 门面模式
结构性模式-外观模式 门面模式 适用场景:如果你需要一个指向复杂子系统的直接接口, 且该接口的功能有限, 则可以使用外观模式。 不用关心后面的查询具体操作 /*** 聚合查询接口*/ RestController RequestMapping("/search") Slf…...
Prophet时间序列算法总结及python实现案例
目录 一、prophet理论总结二、python导入模块方式三、python实现案例3.1帮助信息3.2 案例 四、参考学习 一、prophet理论总结 prophet模型是facebook开源的一个时间序列预测算法。[1][2],该算法主要为处理具有周期性、趋势变化以及缺失值和异常值的时间序列数据而设…...
远程调用 rpc 、 open feign
在学习黑马 springcloud 视频的时候,看到 open feign 使用, 就是 http 封装。 spring框架三部曲,导入依赖,加配置,使用api。...
Redis的几种持久化方式
Redis 提供了两种主要的持久化方式,它们分别是: 1. RDB(Redis Database Snapshotting) RDB 是 Redis 的一种数据持久化方式,它会在指定的时间间隔内对 Redis 中的数据进行快照并保存到硬盘上。 特点: 触…...
论文笔记(五十九)A survey of robot manipulation in contact
A survey of robot manipulation in contact 文章概括摘要1. 引言解释柔顺性控制的概念:应用实例: 2. 需要接触操控的任务2.1 环境塑造2.2 工件对齐2.3 关节运动2.4 双臂接触操控 3. 接触操控中的控制3.1 力控制3.2 阻抗控制3.3 顺应控制 4. 接触操控中的…...
c#控制台程序26-30
26.寻找并输出11至999之间的数m,它满足m,m2和m3均为回文数。所谓回文数是指其各位数字左右对称的整数,例如121,676,94249等。满足上述条件的数如m11,m2121,m31331皆为回文数。请编制函数实现此功能,如果是回文数&#…...
环形链表系列导学
问题描述 给定一个单链表,可能存在一个环。我们的目标是找到环的入口节点,即从这个节点开始,链表进入循环。如果没有环,则返回 null。 将链表问题转化为数学问题 状态序列与循环 我们可以将链表节点视为状态,每个节点的 next 指针代表状态转移函数 f f f。从头节点开始,我…...
IDEA2024创建一个spingboot项目
以下是创建一个基本的 Spring Boot 项目的步骤和示例: 初始化一个springboot工程其实有许多方法,笔者这里挑了一个最快捷的方式搭建一个项目。我们直接通过官方平台(start.spring.io)进行配置,然后下载压缩包就可以获取…...
Nginx:ssl
目录 部署ssl前提 nginx部署ssl证书 部署ssl部署建议 部署ssl前提 网站有域名根据域名申请到ssl证书,并下载证书部署到nginx中 部署了ssl证书后,访问的流量是加密的。 nginx部署ssl证书 #80端口跳转到443 server {listen 80;return 302 https://1…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
C/C++ 中附加包含目录、附加库目录与附加依赖项详解
在 C/C 编程的编译和链接过程中,附加包含目录、附加库目录和附加依赖项是三个至关重要的设置,它们相互配合,确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中,这些概念容易让人混淆,但深入理解它们的作用和联…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...
API网关Kong的鉴权与限流:高并发场景下的核心实践
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中,API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关,Kong凭借其插件化架构…...
