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

思考

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

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

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

HttpServletRequest

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

java 复制代码
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和参数,那么我们直接对这里进行解析就行了

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

存入map

java 复制代码
// 设置请求参数
        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

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

java 复制代码
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中的,那就需要我们使用代理来调用其中的方法了

java 复制代码
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类

java 复制代码
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类

java 复制代码
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 {

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        response.write(request.getParam("aaa"));
    }

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) {

    }
}

请求测试

java 复制代码
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 param
        String 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

java 复制代码
response.write(request.getParam("aaa"));

下一篇将会实现对html页面的解析

【仿写tomcat】五、响应静态资源(访问html页面)、路由支持以及多线程改进

相关推荐
Wx-bishekaifayuan7 分钟前
django电商易购系统-计算机设计毕业源码61059
java·spring boot·spring·spring cloud·django·sqlite·guava
customer0811 分钟前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
全栈开发圈13 分钟前
新书速览|Java网络爬虫精解与实践
java·开发语言·爬虫
WaaTong15 分钟前
《重学Java设计模式》之 单例模式
java·单例模式·设计模式
面试鸭18 分钟前
离谱!买个人信息买到网安公司头上???
java·开发语言·职场和发展
沈询-阿里1 小时前
java-智能识别车牌号_基于spring ai和开源国产大模型_qwen vl
java·开发语言
AaVictory.1 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
LuckyLay2 小时前
Spring学习笔记_27——@EnableLoadTimeWeaving
java·spring boot·spring
向阳12182 小时前
Dubbo负载均衡
java·运维·负载均衡·dubbo