如何仿写简易tomcat 实现思路+代码详细讲解

这篇具有很好参考价值的文章主要介绍了如何仿写简易tomcat 实现思路+代码详细讲解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

仿写之前,我们要搞清楚都要用到哪些技术

  1. 自定义注解,比如Tomcat使用的是@Servlet,我们可以定义一个自己的@MyServlet
  2. 构造请求体和返回体,比如tomcat使用HttpRequest,我们可以自己定义myHttpRequest
  3. java去遍历一个指定目录,然后获取到.java文件,再获取到带有@MyServlet注解的类
  4. 然后将这个注解里的path和这个类本身映射成map
  5. 通过反射去调用该类的方法(doGet、doPost)
  6. 还需要用到socket来监听消息,并且对监听到的消息进行处理

第一步:自定义注解

@Target(ElementType.TYPE)
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MyServlet {
    String path() default "";
}

第二步:定义HttpRequest以及HttpResponse、

public class MyHttpRequest {
    //定义一个map,用来存放请求体中的参数,key是参数名称,value是参数值
    public Map<String,String> map = new HashMap<>();

    public String getParameter(String key){
        return map.get(key);
    }
}
public class MyHttpResponse {
    public OutputStream outputStream;

    public static final String responsebody = "HTTP/1.1 200+\r\n" + "Content-Type:text/html+\r\n"
            + "\r\n";

    public MyHttpResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }
}

第三步:遍历整个目录,把Java文件放入list中

    private static void func(File file){
        File[] files = file.listFiles();
        String s;
        for (File file1 : files) {
            if (file1.isDirectory()){
                func(file1);
            }
            if (file1.isFile()){
                //取src之后的名字
                s = file1.toString().split("src")[1];
                //去掉src后边的第一个\,得到全类名
                s = s.substring(1);
                //判断是不是以.java结尾的文件
                if (s.length() >=5 && s.substring(s.length() - 5).equals(".java")){
                    //把全类名中的\替换成.
                    s = s.replace('\\','.');
                    //去掉后缀名.java
                    s = s.substring(0,s.length()-5);
                    //把类名加入到list中
                    javaclasses.add(s);
                }

            }
        }
    }

第四步:找出带有Servlet注解的Java文件,并把注解中的path,类对象放入到map中

    public static void getServlet() throws ClassNotFoundException {
        for (int i = 0; i < javaclasses.size(); i++) {
            String path = javaclasses.get(i);
            Class<?> cl = Class.forName(path);
            if (cl.isAnnotationPresent(MyServlet.class)){
                servletMap.put(cl.getAnnotation(MyServlet.class).path(),cl);
            }
        }
    }

第五步:创建socket连接

InetAddress localHost = InetAddress.getLocalHost();
        System.out.println("localhost" + localHost);
        ServerSocket serverSocket = new ServerSocket(8080, 10, localHost);
        System.out.println("等待建立连接");
        Socket server = serverSocket.accept();
        System.out.println("连接已建立");

第六步:定义线程接收报文

        HttpAcceptThread httpAcceptThread = new HttpAcceptThread(server);
        Thread accept = new Thread(httpAcceptThread);
        accept.start();
        accept.join();

HttpAcceptThread类内容如下:

class HttpAcceptThread implements Runnable{
    private Socket socket;
    ArrayList<String> strings = new ArrayList<>();

    public HttpAcceptThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        System.out.println("开始接收http");
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String s;
            while ((s = reader.readLine()).length() != 0){
                try {
                    strings.add(s);
                    System.out.println(s);
                } catch (Exception e){
                    System.out.println("接收Http进程结束");
                    break;
                }
            }
            System.out.println("接收http进程结束");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

第七步:处理httprequest,也就是通过反射去调用doGet和doPost方法

这一步有些复杂,尤其是对url切割时,但我给每一步都加了注释,方便理解

             GET /address1?a=111&b=222

   private static void requestHttp(Socket socket,String http) throws IOException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //GET /address1?a=111&b=222(拿获取到的这个url举例)
        //先通过空格判断是GET还是POST
        String requestStyle = http.split(" ")[0];
        if (requestStyle.equals("GET")){
            //如果是GET,取空格后面部分,即/address1?a=111&b=222
            String httpPathAndParameter = http.split(" ")[1];
            //定义httpPath
            String httpPath;
            //创建httpRequest对象
            MyHttpRequest myHttpRequest = new MyHttpRequest();
            //通过索引位置判断url里边有没有带?
            if (httpPathAndParameter.indexOf("?") != -1){
                //如果有,由于有个/,因此我们要先拿到address1?a=111&b=222这部分
                httpPath = httpPathAndParameter.substring(1);
                //获取问号前面部分,即address1,\\作为转义字符使用
                httpPath = httpPath.split("\\?")[0];
                System.out.println(httpPath);

                //获取问号后面部分的所有参数
                String parameterString = httpPathAndParameter.split("\\?")[1];
                //使用&分开
                String[] parameters = parameterString.split("&");
                for (int i = 0; i < parameters.length; i++) {
                    //把参数及其值仿佛request的map中
                    myHttpRequest.map.put(parameters[i].split("=")[0],parameters[i].split("=")[1]);
                }
            } else {
                //如果不存在?,也就说明不存在参数,我们只需要获取httpPath
                httpPath = httpPathAndParameter.substring(1);
                System.out.println(httpPath);
            }

            //创建HttpResponse对象
            OutputStream outputStream = socket.getOutputStream();
            MyHttpResponse myHttpResponse = new MyHttpResponse(outputStream);

            //反射调用doGet
            Class servletClass = servletMap.get(httpPath);
            Method doGet = servletClass.getMethod("doGet", MyHttpRequest.class, MyHttpResponse.class);
            doGet.invoke(servletClass.newInstance(),myHttpRequest,myHttpResponse);
        } else {
            //如果不是Get请求,也按照同样的步骤,先取出/address1
            String httpPath = http.split(" ")[1];
            //去掉/,只留下address1
            httpPath = httpPath.substring(1);
            System.out.println(httpPath);

            MyHttpRequest myHttpRequest = new MyHttpRequest();
            OutputStream outputStream = socket.getOutputStream();
            MyHttpResponse myHttpResponse = new MyHttpResponse(outputStream);
            //根据httpPath取出类信息
            Class servletClass = servletMap.get(httpPath);
            //获取doPost方法
            Method doPost = servletClass.getMethod("doPost", MyHttpRequest.class, MyHttpResponse.class);
            //调用doPost方法
            doPost.invoke(servletClass.newInstance(),myHttpRequest,myHttpResponse);
        }
    }

最后一步:把上面这些方法整合起来,在主方法中调用,同时定义好全局变量

public class MyTomcat {
    //用于存放Java类的全类名
    public static ArrayList<String> javaclasses = new ArrayList<>();

    //用于存放Servlet的类对象,其中key是Servlet的url,value是servlet的类对象
    public static HashMap<String,Class> servletMap = new HashMap<>();

    public static void main(String[] args) throws ClassNotFoundException, IOException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        String inputPath = "D:\\JavaProject\\practice\\src\\tomcat";
        File file = new File(inputPath);
        //获取.java后缀文件,并获取全类名
        func(file);
        System.out.println(javaclasses);
        //获取带有servlet注解的类对象,并放到map中。
        getServlet();
        System.out.println(servletMap);

        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println("localhost" + localHost);
        ServerSocket serverSocket = new ServerSocket(8080, 10, localHost);

        System.out.println("等待建立连接");
        Socket server = serverSocket.accept();
        System.out.println("连接已建立");

        //定义线程接收http报文
        HttpAcceptThread httpAcceptThread = new HttpAcceptThread(server);
        Thread accept = new Thread(httpAcceptThread);
        accept.start();
        accept.join();

        //处理请求
        requestHttp(server,httpAcceptThread.strings.get(0));
    }

然后就可以进行测试了,在测试类上方加上我们已经定义好的@MyServlet注解

@MyServlet(path = "address1")
public class Servlet1 {

    public void doGet(MyHttpRequest request, MyHttpResponse response) throws IOException {
        System.out.println("address1 GET响应:");
        System.out.println("a=" + request.getParameter("a"));
        System.out.println("\n响应的http如下:");
        String resp = MyHttpResponse.responsebody + "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "    <meta charset=\"utf-8\" />\n" +
                "</head>\n" +
                "<body>\n" +
                " \n" +
                "    <form name=\"my_form\" method=\"POST\">\n" +
                "        <input type=\"button\" value=\"按下\" onclick=\"alert('你按下了按钮')\">\n" +
                "    </form>\n" +
                " \n" +
                "</body>\n" +
                "</html>";
        System.out.println(resp);
        response.outputStream.write(resp.getBytes());
        response.outputStream.flush();
        response.outputStream.close();
    }

    public void doPost(MyHttpRequest request, MyHttpResponse response) throws IOException {
        System.out.println("\n响应的http如下:");
        String resp = MyHttpResponse.responsebody +
                "{\"sorry\":\"we only respond to method GET now\"},\r\n" +
                "";
        System.out.println(resp);
        response.outputStream.write(resp.getBytes());
        response.outputStream.flush();
        response.outputStream.close();
    }
}

然后启动项目

如何仿写简易tomcat 实现思路+代码详细讲解,tomcat,java

 可以看到本机ip地址,然后通过浏览器地址栏访问

如何仿写简易tomcat 实现思路+代码详细讲解,tomcat,java

 这样就实现了一个简单的tomcat文章来源地址https://www.toymoban.com/news/detail-662587.html

到了这里,关于如何仿写简易tomcat 实现思路+代码详细讲解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【仿写tomcat】一、tomcat工作流程

    简介 作者前不久刚仿写了一个简易的tomcat,在此分享给各位,此篇为对tomcat的简介和流程分析,具体仿写内容后续会贴在这里 扫描java文件,获取带有@WebServlet注解的类 tomcat简介 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和

    2024年02月12日
    浏览(28)
  • 【仿写框架之仿写Tomact】一、Tomcat的工作流程

    当涉及到Java Web应用程序的部署和运行,Apache Tomcat无疑是一个备受欢迎的选择。Tomcat作为一个开源的、轻量级的Java Servlet容器和JavaServer Pages (JSP) 容器,扮演着连接用户和应用程序的重要角色。本篇文将向大家阐述Tomcat的执行流程,从启动到请求处理再到关闭,帮助您更好地

    2024年02月12日
    浏览(34)
  • 【数据结构与算法】 - 双向链表 - 详细实现思路及代码

    前几篇文章介绍了怎样去实现单链表、单循环链表, 这篇文章主要介绍 双向链表 以及实现双向链表的步骤,最后提供我自己根据理解实现双向链表的C语言代码 。跟着后面实现思路看下去,应该可以看懂代码,看懂代码后,就对双向链表有了比较抽象的理解了,最后自己再

    2024年02月01日
    浏览(36)
  • 【仿写框架之仿写Tomact】一、详解Tomcat的工作流程

    当涉及到Java Web应用程序的部署和运行,Apache Tomcat无疑是一个备受欢迎的选择。Tomcat作为一个开源的、轻量级的Java Servlet容器和JavaServer Pages (JSP) 容器,扮演着连接用户和应用程序的重要角色。本篇文将向大家阐述Tomcat的执行流程,从启动到请求处理再到关闭,帮助您更好地

    2024年02月12日
    浏览(36)
  • 用C语言实现万年历的代码及思路(详细教程)

    1.当选择1的时候,输入 年 ,打印输入的这一年12月的日历。 2.当选择2的时候,输入 年-月 ,打印输入这一年这一月的日历。 实现效果: 选择1时 选择2时 C语言根据日期判断星期几(使用基姆拉尔森计算公式) 算法如下: 基姆拉尔森计算公式 W= (d+2 m+3 (m+1)/5+y+y/4-y/100+y/400)%

    2024年02月11日
    浏览(42)
  • 【仿写tomcat】三、通过socket读取http请求信息

    这里我们也是创建一个专门管理socket的类 随后在主方法中调用他,让serverSocket监听8080端口,并且一直尝试获取连接信息 接下来在SocketStore中添加处理请求的方法,这里面的主要逻辑就是读取流数据,而且我们知道HTTP协议是一行一行的(看f12就知道了),所以给数据拼上换行

    2024年02月12日
    浏览(40)
  • Linux系统部署Tomcat详细教程(图文讲解)

    前言:本篇博客教大家如何一步一步使用Linux系统去部署自己的Tomcat服务器,每一行代码都是我自己严格执行过的,共分为了8点进行阐述,逻辑清晰! 博主的其他部署教程: 1、Jenkins部署前后端分离项目:Jenkins部署前后端分离项目最全图文教程(手把手教学) 2、Docker部署前

    2024年02月14日
    浏览(43)
  • python实现+leetcode题+合并两个有序列表超详细流程图分析以及代码思路

    给你两个按非递减顺序排列的整数列表nums1和nums2,另有两个整数m和n,分别表示nums1和nums2中的元素数目。请你合并nums2到nums1中,使合并后的数组同样按非递减顺序排列。 注意 :最终,合并后数组不应由函数返回,而是存储在数组nums1中。为了应对这种情况,nums1的初始长度为

    2023年04月09日
    浏览(48)
  • 基于SSM框架简易项目“书籍管理系统”,超详细讲解,附源码

    目录 我有话说: 1 项目简介 2 项目展示 2.1 首先创建数据库和表信息 2.2 预先准备操作 2.3 开始配置项目 2.4 开始web层 3 图片展示 4 附上源码文件(百度网盘): 首先 内容比较多,篇幅比较长,有需要的可以耐心看完. 这个项目最开始是跟着狂神写下来的,附上狂神的详细视频链接及详

    2024年02月05日
    浏览(38)
  • 【仿写tomcat】六、解析xml文件配置端口、线程池核心参数

    上一篇文章中我们用了Excutors创建了线程,这里我们将它改造成包含所有线程池核心参数的形式。 主方法中对多线程操作部分改为使用CompletableFuture执行 现在我们有一个server.xml文件,我想解析其中的端口号以及线程池参数 如果想完成这个功能可以直接使用java本身自带的工具

    2024年02月12日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包