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…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...