【仿写tomcat】四、解析http请求信息,响应给前端,HttpServletRequest、HttpServletResponse的简单实现

思考

在解析请求之前我们要思考一个问题,我们解析的是其中的哪些内容?

对于最基本的实现,当然是请求类型请求的url以及请求参数,我们可以根据请求的类型作出对应的处理,通过url在我们的mapstore中找到servlet,那么请求的参数我们是不是还没有储存的地方呢?

所以我们要先定义一个类来存储参数

HttpServletRequest

当然你也可以通过接口的形式来规范方法,我在这里进行的是最基本的仿写,就不做复杂的设计了,下面这个类是存储请求信息的类,我们在后续还会进行扩展,因我们还要实现cookie、session等功能

package com.tomcatServer.domain;import java.util.HashMap;
import java.util.Map;/*** http servlet请求** @author ez4sterben* @date 2023/08/15*/
public class HttpServletRequest {private final Map<String,String> params = new HashMap<>();private String requestBody;public String getRequestBody() {return requestBody;}public void setRequestBody(String requestBody) {this.requestBody = requestBody;}public Map<String, String> getParams() {return params;}public String getParam(String paramName){return params.get(paramName);}
}

http请求解析,HttpServletRequest

我们再给服务器发一个带参数的请求看看http信息是什么样子的
http://localhost:8080/test?aaa=aaa
在这里插入图片描述
这个信息的第一行就是请求的类型、url和参数,那么我们直接对这里进行解析就行了

// 解析request param
String url = requestData.split(" ")[1];
String[] urlContent = url.split("\\?");
// ?前的是请求地址
String requestPath = urlContent[0];
// 问号后的是参数
String params = urlContent[1];
// 参数按照=分割
String[] paramsKeyValue = params.split("=");

存入map

// 设置请求参数HttpServletRequest request = new HttpServletRequest();Map<String, String> paramsMap = request.getParams();for (int i = 0; i < paramsKeyValue.length; i += 2) {paramsMap.put(paramsKeyValue[i],paramsKeyValue[i+1]);}

响应类HttpServletResponse

这个类中要注意的是我们要给返回的信息拼上一个头部信息代表着成功编号和信息类型

package com.tomcatServer.domain;import java.io.PrintWriter;/*** http servlet响应** @author ez4sterben* @date 2023/08/15*/
public class HttpServletResponse {private final PrintWriter out;private static final String response;public HttpServletResponse(PrintWriter out) {this.out = out;}static {response = "HTTP/1.1 200 OK\r\n" +"Content-Type: text/plain\r\n" +"\r\n";}/*** 写** @param content 内容*/public void write(String content) {out.println(response + content);}}

代理

既然实现到这里了,自然会想到,执行谁的响应呢?

没错,当然是servlet中的,那就需要我们使用代理来调用其中的方法了

package com.tomcatServer.utils;import com.tomcatServer.annotation.WebServlet;
import com.tomcatServer.domain.HttpServletRequest;
import com.tomcatServer.domain.HttpServletResponse;
import com.tomcatServer.servlet.MapStore;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;/*** servlet工具类** @author tomcatProject.ez4sterben* @date 2023/08/15*/
public class ServletUtil {/*** 是web servlet** @param className 类名* @return {@link Boolean}*/public static Boolean isWebServlet(String className){try {Class<?> aClass = Class.forName(className);WebServlet annotation = aClass.getAnnotation(WebServlet.class);if (annotation == null){return Boolean.FALSE;}} catch (ClassNotFoundException e) {throw new RuntimeException(e);}return Boolean.TRUE;}/*** 初始化servlet** @param className 类名*/public static void initServlet(String className){try {Class<?> aClass = Class.forName(className);String url = aClass.getAnnotation(WebServlet.class).value();if (url.startsWith("/")) {MapStore.servletMap.put(url,aClass);}else {MapStore.servletMap.put("/" + url,aClass);}} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}/*** 调用get方法** @param url     url* @param request*/public static void invokeGet(String url, HttpServletRequest request, HttpServletResponse response){Class<?> aClass = MapStore.servletMap.get(url);try {Method doGet = aClass.getDeclaredMethod("doGet", HttpServletRequest.class, HttpServletResponse.class);Object instance = aClass.newInstance();doGet.invoke(instance, request, response);} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {throw new RuntimeException(e);}}/*** 调用后** @param url      url* @param request  请求* @param response 响应*/public static void invokePost(String url, HttpServletRequest request, HttpServletResponse response){Class<?> aClass = MapStore.servletMap.get(url);try {Method doPost = aClass.getDeclaredMethod("doPost", HttpServletRequest.class, HttpServletResponse.class);Object instance = aClass.newInstance();doPost.invoke(instance, request, response);} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {throw new RuntimeException(e);}}
}

HttpServlet规范

接下来定义一个抽象类来规范servlet类

package com.tomcatServer.domain;import java.io.IOException;/*** http servlet** @author ez4sterben* @date 2023/08/15*/
public abstract class HttpServlet {/*** 做得到** @param request  请求* @param response 响应* @throws IOException ioexception*/public abstract void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException;/*** 做帖子** @param request  请求* @param response 响应* @throws IOException ioexception*/public abstract void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException;}

然后在项目中创建一个测试的servlet类
在这里插入图片描述

package tomcatProject.com.ez4sterben.servlet;import com.tomcatServer.annotation.WebServlet;
import com.tomcatServer.domain.HttpServlet;
import com.tomcatServer.domain.HttpServletRequest;
import com.tomcatServer.domain.HttpServletResponse;/*** 登录servlet** @author tomcatProject.ez4sterben* @date 2023/08/15*/
@WebServlet("/test")
public class TestServlet extends HttpServlet {@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse response) {response.write(request.getParam("aaa"));}@Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response) {}
}

请求测试

package com.tomcatServer.socket;import com.tomcatServer.domain.HttpServletRequest;
import com.tomcatServer.domain.HttpServletResponse;
import com.tomcatServer.utils.ScanUtil;
import com.tomcatServer.utils.ServletUtil;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;/*** 套接字存储** @author ez4sterben* @date 2023/08/15*/
public class SocketStore {private static ServerSocket socket;public static void connect(Integer port) throws IOException {socket = new ServerSocket(port);}public static void close() throws IOException {socket.close();}public static ServerSocket getSocket() {return socket;}/*** 处理请求** @throws IOException ioexception*/public static void handleRequest(Socket accept) throws IOException {// 获取输入输出流BufferedReader in = new BufferedReader(new InputStreamReader(accept.getInputStream()));PrintWriter out = new PrintWriter(accept.getOutputStream(), true);// 定义字符串接收Http协议内容String inputLine;StringBuilder requestData = new StringBuilder();// 读取数据while ((inputLine = in.readLine()) != null && !inputLine.isEmpty()) {requestData.append(inputLine).append("\r\n");}System.out.println(requestData);if (!requestData.toString().trim().equals("")){handleGetAndPostReuqest(in, out, String.valueOf(requestData));}// 关闭资源accept.close();}/*** 处理post请求** @param in          在* @param requestData 请求数据* @throws IOException ioexception*/private static void handleGetAndPostReuqest(BufferedReader in,PrintWriter out, String requestData) throws IOException {// 解析request paramString url = requestData.split(" ")[1];String[] urlContent = url.split("\\?");String requestPath = urlContent[0];String params = urlContent[1];String[] paramsKeyValue = params.split("=");// 设置请求参数HttpServletRequest request = new HttpServletRequest();Map<String, String> paramsMap = request.getParams();for (int i = 0; i < paramsKeyValue.length; i += 2) {paramsMap.put(paramsKeyValue[i],paramsKeyValue[i+1]);}if (requestData.contains("GET")){// 设置响应内容HttpServletResponse response = new HttpServletResponse(out);ServletUtil.invokeGet(requestPath,request,response);}}}

访问http://localhost:8080/test?aaa=123
因为servlet中的操作是返回参数,所以结果应该为123

response.write(request.getParam("aaa"));

在这里插入图片描述
下一篇将会实现对html页面的解析

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

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

相关文章

【数据结构OJ题】合并两个有序链表

原题链接&#xff1a;https://leetcode.cn/problems/merge-two-sorted-lists/description/ 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 可以先创建一个空链表&#xff0c;然后依次从两个有序链表中选取最小的进行尾插操作。&#xff08;有点类似双…

基于docker搭建pytest自动化测试环境(docker+pytest+jenkins+allure)

pytest搭建自动化测试环境&#xff08;dockerpytestjenkinsallure&#xff09; 这里我以ubuntu18为例 如果有docker环境&#xff0c;可以直接拉取我打包好的镜像docker pull ziyigun/jenkins:v1.0 1 搭建Docker 1.1 安装docker # 配置docker安装环境 sudo apt-get install ap…

Android Studio实现解析HTML获取图片URL将图片保存到本地

目录 效果activity_main.xmlMainActivityImageItemImageAdapter 效果 项目本来是要做成图片保存到手机然后读取数据后瀑布流展示&#xff0c;但是有问题&#xff0c;目前只能做到保存到手机 activity_main.xml <?xml version"1.0" encoding"utf-8"?…

C++写文件,直接写入结构体

C写文件&#xff0c;直接写入结构体 以前写文件都是写入字符串或者二进制再或者就是一些配置文件&#xff0c;今天介绍一下直接写入结构体&#xff0c;可以在软件参数较多的时候直接进行读写&#xff0c;直接将整个结构体写入和读取&#xff0c;看代码&#xff1a; #include&…

文本图片怎么转Excel?分享一些好用的方法

在处理数据时&#xff0c;Excel 是一个非常强大的工具&#xff0c;但有时候需要将文本和图片转换为 Excel 格式&#xff0c;这可能会让人感到困惑。在本文中&#xff0c;我们将介绍一些好用的方法&#xff0c;以便您能够轻松地将文本和图片转换成 Excel 格式。 将文本图片为Exc…

vue3 videojs实现播放器,动态更改src

一、背景 vue3下载第三方插件videojs&#xff0c;达到播放器的效果&#xff0c;并且点击事件能够动态更改播放器的src。实现思路&#xff1a; 场景一&#xff1a;只有一个播放器&#xff0c;当点击事件&#xff0c;直接赋值&#xff0c;动态更改封装好的组件的src参数&#xff…

线程|线程的使用、四种实现方式

1.线程的实现方式 1.用户级线程 开销小&#xff0c;用户空间就可以创建多个。缺点是&#xff1a;内核无法感知用户级多个线程的存在&#xff0c;把其当作只有一个线程&#xff0c;所以只会提供一个处理器。 2.内核级线程 相对于用户级开销稍微大一点&#xff0c;可以利用多…

无涯教程-Perl - setgrent函数

描述 此功能将枚举设置(或重置)到组条目集的开头。该函数应在第一次调用getgrent之前调用。 语法 以下是此函数的简单语法- setgrent返回值 此函数不返回任何值。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perl -wwhile( ($name,$passwd,$gid,$members)getgrent…

c语言每日一练(9)

前言&#xff1a;每日一练系列&#xff0c;每一期都包含5道选择题&#xff0c;2道编程题&#xff0c;博主会尽可能详细地进行讲解&#xff0c;令初学者也能听的清晰。每日一练系列会持续更新&#xff0c;暑假时三天之内必有一更&#xff0c;到了开学之后&#xff0c;将看学业情…

QT的设计器介绍

设计器介绍 Qt制作 UI 界面&#xff0c;一般可以通过UI制作工具QtDesigner和纯代码编写两种方式来实现。纯代码实现暂时在这里不阐述了在后续布局章节详细说明&#xff0c;QtDesigner已经继承到开发环境中&#xff0c;在工程中直接双击ui文件就可以直接在QtDesigner设计器中打…

unity发布WebGL遇到的坑(持续更新)

1、unity默认字体在网页中不会显示 解决方法&#xff1a;自己新导入一个字体&#xff0c;使用导入的字体 2、之前打过包并运行过&#xff0c;后面又在unity中进行了修改&#xff0c;重新打包&#xff0c;运行发现还是修改之前的效果&#xff0c;虽然是新包&#xff0c; 解决方…

Windows上使用dump文件调试

dump文件 dump文件记录当前程序运行某一时刻的信息&#xff0c;包括内存&#xff0c;线程&#xff0c;线程栈&#xff0c;变量等等&#xff0c;相当于调试程序时运行到某个断点上&#xff0c;把程序运行的信息记录下来。可以通过Windbg打开dump&#xff0c;查看程序运行的变量…

在IDEA中创建properties配置文件

第一步&#xff1a;在 src路径下找到resources文件 第二步&#xff1a;右击选择新建Resource Bundle配置文件 第三步&#xff1a;为Resource Bundle配置文件命名 完成创建

第十课:Qt 字符编码和中文乱码相关问题

功能描述&#xff1a;最全的 Qt 字符编码相关知识以及中文乱码的原因与解决办法 一、字符编码种类 ASCII 码 美国人对信息交流的编码&#xff0c;包括 26 个字母&#xff08;大小写&#xff09;、数字和标点符号等&#xff0c;用一个字节&#xff08;8 位&#xff09;表示这些…

vue-组件库-storybook:理解storybook、实践

一、理解 storybook Storybook是一个开源的工具&#xff0c;可以帮助前端开发者更好地构建、测试和展示组件。 具体来说&#xff0c;Storybook可以做以下几件事情&#xff1a; 1、为每个组件提供一个独立的页面&#xff0c;可以快速展示或调试组件。 2、管理多个组件&#x…

vue利用 sortable 完成表格拖拽

先讲一下vue2&#xff0c;使用sortable完成表格拖拽【不只是表格&#xff0c;div也可以实现&#xff0c;但我项目中是表格拖拽】 github地址 安装 npm install sortablejs --save使用 &#xff08;我的项目中是拖拽一个小按钮移动&#xff0c;而不是整行&#xff09; <te…

VMware虚拟机Ubuntu无法连接网络的解决方法

一、解决办法 网络适配器设置 终端依次执行下面命令即可 sudo nmcli networking off sudo nmcli networking onsudo service network-manager start #或者 sudo service NetworkManager start成功出现这个图标&#xff0c;即代表网络连接成功。

单元测试到底是什么?应该怎么做?

一、什么是单元测试&#xff1f; 单元测试&#xff08;unit testing&#xff09;&#xff0c;是指对软件中的最小可测试单元进行检查和验证。至于“单元”的大小或范围&#xff0c;并没有一个明确的标准&#xff0c;“单元”可以是一个函数、方法、类、功能模块或者子系统。 …

滴滴Ceph分布式存储系统优化之锁优化

摘自&#xff1a;https://mp.weixin.qq.com/s/oWujGOLLGItu1Bv5AuO0-A 2020-09-02 21:45 0.引言 Ceph是国际知名的开源分布式存储系统&#xff0c;在工业界和学术界都有着重要的影响。Ceph的架构和算法设计发表在国际系统领域顶级会议OSDI、SOSP、SC等上。Ceph社区得到Red Hat…

指针、数组、sizeof、strlen相关知识与练习题目

目录 前提回顾&#x1f50d;&#xff1a; 关于一维数组&#x1f92e;&#xff1a; 关于二维数组&#x1f600;&#xff1a; sizeof与strlen&#x1f415;&#xff1a; sizeof&#x1f3c0;&#xff1a; strlen&#x1f413;&#xff1a; 相关练习&#x1f4da;&#xff1a…