【手写Tomcat】5.实现自己定义的MyHttpRequest

        在上一次,我们设计了自己的Servlet,现在我们来对具体的Servlet进行实现。

        我们首先来对MyHttpRequest进行实现,这个类就相当于Tomcat里面的HttpServletRequest,我们实现最基本的几个功能。分别是:

  •         getParameter(String name)
  •         getMethod()
  •         getUri()

代码编写 

        我们首先在MyHttpServlet接口里面定义这几个方法。

         然后在MyHttpRequestImpl类里面实现这几个方法,我们首先定义几个成员变量

         写一个构造器,在创建对象时传入一个InputStream流,并使用这个流就行初始化

         这个init方法我们最后实现,我们先实现接口里面的几个方法

 getParameter(String name)

getMethod()

 getUri()

        为了测试方便,我们再写一个toString()方法 


         现在,我们对前面提到的init()方法进行实现,这个方法要对成员属性进行初始化。我们这里仅考虑2种请求方式,一直get,一种post。又因为get和post的http请求不一样,所以我们要分开进行处理。

         我们先来对get请求进行处理,我在前面的http介绍里面说过,get请求的参数在请求行中就有体现。所以我们通过请求行就能得到请求参数,方法,uri。如果对http请求不了解,请参考http请求get和post

         于是,我们就可以定义一个方法来对get请求进行处理

    public void setGetParamsAndUri(String requestLine) {
        //得到最后一个空格索引
        int lastSpace = requestLine.lastIndexOf(" ");
        //通过第一个空格索引和最后一个空格索引就能得到uri和参数
        String s = requestLine.substring(requestLine.indexOf(" ")+1, lastSpace);
        //判断是否含有?
        if (s.contains("?")) {
            //得到第一个?索引
            int firstFlag = s.indexOf("?");
            //?前面的就是uri
            uri = s.substring(0, firstFlag);
            //后面的就是参数
            String params = s.substring(firstFlag + 1);
            //将字符串传给setParams进行初始化
            setParams(params);
        } else {
            //没有?直接赋值
            uri = s;
        }
    }
    public void setParams(String params) {
        //通过&进行分割
        String[] kvs = params.split("&");
        for (String kv : kvs) {
            //通过=进行分割
            String[] keyVal = kv.split("=");
            //如果keyVal是正确写法就将参数和值存入HashMap中进行保存
            if (keyVal.length == 2) {
                String key = keyVal[0];
                String value = keyVal[1];
                parameters.put(key, value);
            }
        }
    }

        下面我们再对post进行处理,post的请求和get不同,请求行中没有参数,参数在请求体中。我们写一个方法来对post进行处理

    public void setPostParamsAndUri(String requestLine, StringBuilder sb) {
        try {
            //得到uri
            uri = requestLine.substring(requestLine.indexOf(" ") + 1, requestLine.lastIndexOf(" "));
            //URLDecoder是对游览器的请求进行解码
            //传入的sb就是请求头+请求体
            //我们通过寻找最后一个换行符就能得到请求体
            String params = URLDecoder.decode(sb.substring(sb.lastIndexOf("\n")+1), "utf-8");
            //和get一样传入参数字符串,然后对参数进行初始化
            setParams(params);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

        下面,我们来编写我们的init方法

    public void init() {
        try {
            //定义一个字节数组
            byte[] bytes = new byte[1024];
            int len = 0;
            //定义一个StringBuilder来对http请求进行存储
            StringBuilder sb = new StringBuilder();
            //读取内容
            while ((len = inputStream.read(bytes)) != -1) {
                sb.append(new String(bytes, 0, len));
                if (len != bytes.length) break;
            }
            //获得请求行并进行解码
            String requestLine = URLDecoder.decode(sb.substring(0, sb.indexOf("\r")), "utf-8");
            requestLine = URLDecoder.decode(requestLine, "utf-8");
            //得到请求行第一个空格位置
            int firstSpace = requestLine.indexOf(" ");
            //得到请求方法
            method = requestLine.substring(0, firstSpace);
            //通过方法调用不同方法
            if ("GET".equals(method)) {
                setGetParamsAndUri(requestLine);
            } else if ("POST".equals(method)) {
                setPostParamsAndUri(requestLine, sb);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

        上面,我们就已经把基本的3个方法实现了,当然,肯定还有不完善的地方,如字符串处理,对其他请求方法的处理,异常参数处理等。但是我们写这个的主要目的是为了对tomcat的运行机制有更深的认识,不需要太过于关注细节,所以,上面这样写就行了。下面给出这个类的完整代码

import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;

public class MyHttpRequestImpl implements MyHttpRequest {

    //定义成员属性
    private String method;
    private String uri;
    private Map<String, String> parameters = new HashMap<>();
    private InputStream inputStream;

    public MyHttpRequestImpl(InputStream inputStream) {
        this.inputStream = inputStream;
        //对成员属性进行初始化
        init();
    }

    public void init() {
        try {
            //定义一个字节数组
            byte[] bytes = new byte[1024];
            int len = 0;
            //定义一个StringBuilder来对http请求进行存储
            StringBuilder sb = new StringBuilder();
            //读取内容
            while ((len = inputStream.read(bytes)) != -1) {
                sb.append(new String(bytes, 0, len));
                if (len != bytes.length) break;
            }
            //获得请求行并进行解码
            String requestLine = URLDecoder.decode(sb.substring(0, sb.indexOf("\r")), "utf-8");
            requestLine = URLDecoder.decode(requestLine, "utf-8");
            //得到请求行第一个空格位置
            int firstSpace = requestLine.indexOf(" ");
            //得到请求方法
            method = requestLine.substring(0, firstSpace);
            //通过方法调用不同方法
            if ("GET".equals(method)) {
                setGetParamsAndUri(requestLine);
            } else if ("POST".equals(method)) {
                setPostParamsAndUri(requestLine, sb);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setGetParamsAndUri(String requestLine) {
        //得到最后一个空格索引
        int lastSpace = requestLine.lastIndexOf(" ");
        //通过第一个空格索引和最后一个空格索引就能得到uri和参数
        String s = requestLine.substring(requestLine.indexOf(" ")+1, lastSpace);
        //判断是否含有?
        if (s.contains("?")) {
            //得到第一个?索引
            int firstFlag = s.indexOf("?");
            //?前面的就是uri
            uri = s.substring(0, firstFlag);
            //后面的就是参数
            String params = s.substring(firstFlag + 1);
            //将字符串传给setParams进行初始化
            setParams(params);
        } else {
            //没有?直接赋值
            uri = s;
        }
    }

    public void setPostParamsAndUri(String requestLine, StringBuilder sb) {
        try {
            //得到uri
            uri = requestLine.substring(requestLine.indexOf(" ") + 1, requestLine.lastIndexOf(" "));
            //URLDecoder是对游览器的请求进行解码
            //传入的sb就是请求头+请求体
            //我们通过寻找最后一个换行符就能得到请求体
            String params = URLDecoder.decode(sb.substring(sb.lastIndexOf("\n")+1), "utf-8");
            //和get一样传入参数字符串,然后对参数进行初始化
            setParams(params);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setParams(String params) {
        //通过&进行分割
        String[] kvs = params.split("&");
        for (String kv : kvs) {
            //通过=进行分割
            String[] keyVal = kv.split("=");
            //如果keyVal是正确写法就将参数和值存入HashMap中进行保存
            if (keyVal.length == 2) {
                String key = keyVal[0];
                String value = keyVal[1];
                parameters.put(key, value);
            }
        }
    }

    @Override
    public String getParameter(String name) {
        if (parameters.containsKey(name)) {
            return parameters.get(name);
        }
        return "";
    }

    @Override
    public String getMethod() {
        return method;
    }

    @Override
    public String getUri() {
        return uri;
    }

    @Override
    public String toString() {
        return "MyHttpRequestImpl{" +
                "method='" + method + '\'' +
                ", uri='" + uri + '\'' +
                ", parameters=" + parameters +
                '}';
    }
}

代码测试

        我创建了一个测试类来测试刚刚写的代码,测试类非常简单,代码如下

import com.clucky.myTomcat.myHttp.MyHttpRequest;
import com.clucky.myTomcat.myHttp.MyHttpRequestImpl;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Test {

    public static void main(String[] args) {
        try {
            //得到ServerSocket,在8080端口进行监听
            ServerSocket serverSocket = new ServerSocket(8080);
            System.out.println("---------服务器启动成功----------");
            while (!serverSocket.isClosed()) {
                //等待连接
                Socket socket = serverSocket.accept();
                System.out.println("连接成功.....");
                //得到输入流
                InputStream inputStream = socket.getInputStream();
                MyHttpRequest myHttpRequest = new MyHttpRequestImpl(inputStream);
                System.out.println(myHttpRequest);
                //写回数据
                socket.getOutputStream().write("HTTP/1.1 200\r\n\r\nhello".getBytes());
                System.out.println("断开连接.....");
                //关闭流
                inputStream.close();
                socket.close();
            }
        } catch (IOException e) {
            System.out.println("服务器启动失败");
        }
    }
}

        我们再来创建一个表单来对post进行测试,代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<form action="http://localhost:8080/login" method="post">
    username:<input type="text" name="username"/><br/>
    password:<input type="password" name="password"/><br/>
    <input type="submit">
</form>
</body>
</html>

  测试GET请求

        首先我们运行测试类,在游览器输入http://localhost:8080/people?name=zs&age=18,然后查看控制台输出。输入如下

        成功获取到所有参数,说明GET请求没有问题。


测试POST请求 

        首先运行测试类,然后打开html文件,账号密码随便输入,点击提交后查看控制台输出

        获取到的用户名和密码与我们输入一样,说明POST请求也没有问题。


        现在,我们已经实现了我们自己定义的MyHttpServlet,在下一篇文章,我们来实现我们自己定义的MyHttpResponse!!!

         

猜你喜欢

转载自blog.csdn.net/m0_51545690/article/details/123251395