三.手写迷你版Tomcat-minicat3.0

2023-05-16

minicat 1.0我们实现了返回固定的字符串"Hello minicat"。
minicat 2.0封装Request和Response对象,返回html静态资源文件。
minicat 3.0需求:
请求servlet动态资源
思路分析:
想实现servlet动态资源请求,就需要将Servlet初始化在容器中(Map)。
如何初始化呢?

  • 将配置信息配置在web.xml中
  • 使用dom4j解析web.xml内容
  • 使用反射机制将servlet初始化在Map中

配置web.xml

配置web.xml之前,需要先自定义一个DemoServlet,需要有常见的doGet和doPost方法。
进一步想平时写Servlet都需要继承HttpServlet抽象类,所以先自己定义一个HttpServlet抽象类,以便后续做容器初始化。
先定义Servlet接口

public interface Servlet {

    void init() throws Exception;

    void destroy() throws Exception;

    void service(Request request,Response response) throws Exception;
}

HttpServlet实现Servlet

public abstract class HttpServlet implements Servlet {

    public abstract void doGet(Request request,Response response);
    public abstract void doPost(Request request,Response response);

    @Override
    public void service(Request request, Response response) throws Exception {
        if ("GET".equalsIgnoreCase(request.getMethod())) {
            doGet(request,response);
        }else{
            doPost(request,response);
        }
    }
}

接下来就是常规的DemoServlet编写了

public class DemoServlet extends HttpServlet{
    @Override
    public void doGet(Request request, Response response) {
        String content = "<h1>get request</h1>";
        try {
            response.output(HttpProtocolUtil.getHttpHeader200(content.getBytes().length)+content);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void doPost(Request request, Response response) {
        String content = "<h1>post request</h1>";
        try {
            response.output(HttpProtocolUtil.getHttpHeader200(content.getBytes().length)+content);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void init() throws Exception {

    }

    @Override
    public void destroy() throws Exception {

    }
}

DemoServlet准备完成后,就可以配置web.xml了

<?xml version="1.0" encoding="UTF-8" ?>
<web-app>
    <servlet>
        <servlet-name>demo</servlet-name>
        <servlet-class>server.DemoServlet</servlet-class>
    </servlet>


    <servlet-mapping>
        <servlet-name>demo</servlet-name>
        <url-pattern>/demo</url-pattern>
    </servlet-mapping>
</web-app>

使用dom4j解析web.xml

web.xml已经配置完成,解析来就需要对它进行解析,也就是初始化的过程,所以需要放在上一篇的start()方法中初始化。

public void start() throws Exception {
        // 加载解析相关配置,web.xml
        loadServlet();
		
		// 后面内容暂时省略....
}

/**
  * 加载解析web.xml,初始化servlet
  */
 private void loadServlet() {
     // 将web.xml配置文件读取到input流中
     InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
     SAXReader saxReader = new SAXReader();
     try {
         // 转换成Document对象
         Document document = saxReader.read(resourceAsStream);
         // 获取根对象
         Element rootElement = document.getRootElement();

         // 通过dom4j解析web.xml中的内容,放入到Map中
         List<Element> selectNodes = rootElement.selectNodes("//servlet");
         for (Element element : selectNodes) {
             // <servlet-name>demo</servlet-name>
             Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
             String servletName = servletnameElement.getStringValue();
             // <servlet-class>server.DemoServlet</servlet-class>
             Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
             String servletClass = servletclassElement.getStringValue();


             // 根据servlet-name的值找到url-pattern
             Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
             // /demo
             String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
             // 使用反射初始化servlet加载到map中
             //servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClas).newInstance());
         }
     } catch (DocumentException | ClassNotFoundException e) {
         e.printStackTrace();
     } catch (IllegalAccessException e) {
         e.printStackTrace();
     } catch (InstantiationException e) {
         e.printStackTrace();
     }
 }

使用反射机制将servlet初始化在Map中

眼尖的同学估计看到了,这一步骤其实就是在loadServlet()方法中实现的
在这里插入图片描述
添加map容器

private Map<String,HttpServlet> servletMap = new HashMap<String,HttpServlet>();

// 伪代码
private void loadServlet() {
// doSomething...
servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).newInstance());
// doSomething...
}

演示效果

已经初始化map容器了,那就需要在start方法中引用,start方法完整代码如下

/**
     * minicat启动需要初始化展开的一些操作
     */
    public void start() throws Exception {
        // 加载解析相关配置,web.xml
        loadServlet();

        // 监听端口
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("---->>>minicat start on port:"+port);

        //minicat 1.0 返回固定字符串
//        while (true) {
//            String data = "Hello minicat!";
//            Socket socket = serverSocket.accept();
//            // 有了socket,接收到请求,获取输出流
//            OutputStream outputStream = socket.getOutputStream();
//            String responseText = HttpProtocolUtil.getHttpHeader200(data.getBytes().length)+data;
//            outputStream.write(responseText.getBytes());
//            socket.close();
//        }

        // minicat 2.0 返回静态资源html
//        while (true) {
//            Socket socket = serverSocket.accept();
//            // 获取输入流
//            InputStream inputStream = socket.getInputStream();
//
//            //封装Request和Response
//            Request request = new Request(inputStream);
//            Response response = new Response(socket.getOutputStream());
//
//            response.outputHtml(request.getUrl());
//            socket.close();
//
//        }

        // minicat 3.0 返回动态资源servlet
        while (true) {
            Socket socket = serverSocket.accept();
            // 获取输入流
            InputStream inputStream = socket.getInputStream();

            //封装Request和Response
            Request request = new Request(inputStream);
            Response response = new Response(socket.getOutputStream());

            // 静态资源处理
            if(servletMap.get(request.getUrl()) == null) {
                response.outputHtml(request.getUrl());
            }else{
                // 动态资源servlet请求
                HttpServlet httpServlet = servletMap.get(request.getUrl());
                httpServlet.service(request,response);
            }
            socket.close();

        }
    }

效果演示
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

三.手写迷你版Tomcat-minicat3.0 的相关文章

随机推荐

  • 位、字节、char、int(32位系统) 之间的关系

    一 概念 xff1a 位 xff08 bit xff09 xff1a 计算机中最小的数据单位 每一位的状态只能是0或1 字节 xff08 byte xff09 xff1a 存储空间的基本计量单位 xff0c 8 个二进制位构成1个字节 1
  • C语言中的那些宏

    DATE 进行预处理的日期 xff08 Mmm dd yyyy 形式的字符串文字 xff09 FILE 代表当前源代码文件名的字符串文字 LINE 代表当前源代码中的行号的整数常量 TIME 源文件编译时间 xff0c 格式微 hh xff
  • 任务栈简单入门

    最近又把两本进阶书看了一遍 xff0c 但总感觉好记性不如烂笔头 xff0c 所以还是决定通过博客记录一下 xff0c 我们将分两篇来全面深入地记录Activity 启动模式与任务栈的内容 android任务栈简单了解 1 android任
  • VS2010里函数枚举

    一 cout函数 说明 xff1a 调用该函数必须申明头文件 include lt iostream gt 同时声明后面必须使用 using namespace std 正确书写为 xff1a include lt iostream gt
  • I_O—标准 I_O 实验

    一 测试标准 I O 一次可以同时打开多少个文件 1 实验思路 xff1a 利用循环同时打开文件 xff0c 直到不能打开 2 代码如下 xff1a 二 fgetc 和 fputc 实现拷贝文件并输出文件行数 1 实验思路 xff1a 打开
  • Source Insight 配色方案

    Source Insight 对于程序员来说应该不陌生 xff0c 当然一个个性化的编程界面也会让自己赏析悦目 xff0c 下面就将个人的界面设置分享一下 xff1a 一 背景色设置 1 选择 Options Preferences 2 选
  • Linux 网络——交换机不能用两根网线相连

    同一个局域网所有的交换机之间可以用网线串联起来 xff0c 但绝对不能使任意 gt 61 2个交换机形成环路 xff0c 否则局域网内将形成广播风暴 xff0c 所用局域网内的用户都将不能上网 例如局域网内的交换机可以使用如下相连 xff1
  • GDB 知识点——基础操作

    Linux C 中的 GDB 调试使用 xff1a 1 GDB 的主要功能 xff1a 1 启动被调试程序 2 让被调试的程序在指定的位置停住 3 当程序被停住时 xff0c 可以检查程序状态 xff08 如变量的值 xff09 2 检查
  • 员工管理系统(C 语言)——项目说明

    项目名称 xff1a 员工管理系统 项目目的 xff1a 1 实现简单的公司对员工信息的管理 2 通过项目锻炼实现逻辑转换为代码的能力 3 利用函数封装实现项目过程中的逻辑过程以及需求功能的实现 4 学会数据库的操作以及网络通信 5 强化代
  • 员工管理系统(C 语言)——客户端解析

    源码下载地址 xff1a https download csdn net download wenfei11471 10477504 客户端功能 xff1a 1 运行时先测试是否能连通服务器 xff08 不畅通如下图所示 xff09 xff
  • 员工管理系统(C 语言)——服务器解析

    源码下载地址 xff1a https download csdn net download wenfei11471 10477504 服务器功能 xff1a 1 运行时主界面 xff08 服务器启动后 xff0c 只有管理员下线 xff0c
  • 排序——选择排序、冒泡排序和快速排序比较

    一 选择排序思路 xff1a 1 以 int 类型为例 2 拿第一个数与后面数相比较 xff0c 如果比后面的数大则交换 3 拿第二个数与后面的数比较 xff0c 如果比后面的数大则交换 4 直到比较到倒数第二个数 xff0c 最后一个数不
  • C 语言中 const 与指针的结合使用

    请区分一下几种指针的区别 1 const int p 2 int const p 3 int const p 4 const int const p 5 const int const p 解析 xff1a 1 const int p 中
  • Ubuntu16.04上安装百度网盘后打不开

    现在百度网盘推出了Linux版本 xff0c 也有Ubuntu下安装的deb文件 xff0c 但是我在Ubuntu上安装后却打不开 xff0c 报错 baidunetdisk crashed with SIGABRT in gnu cxx
  • C/C++的“文件包含”处理时头文件被重复包含的问题探究及解决方法(用最简单的例子进行说明)

    这篇博文是博文https blog csdn net wenhao ir article details 125668051的配套博文 头文件被重复包含是下面这样的现象 xff1a A文件里包含了C文件 xff0c B文件里也包含了C文件
  • BIN,BCD,ASCII码分别对应的Hex(16进制)数

    BIN BCD ASCII码分别对应的Hex xff08 16进制 xff09 数 以十进制的 56 为例 BIN 码 对应二进制数为 0011 1000对应Hex数据为 0x38BIN码就是二进制数 xff1b 压缩BCD 码 对应二进制
  • .LDS 文件详解

    最近在研究uboot xff0c 红色部分为我加上的注解 转载地址 xff1a http blog chinaunix net space php uid 61 23373524 amp do 61 blog amp cuid 61 232
  • 13 select的优化一

    1 上个例子中 xff0c select通过for循环轮询client套接字 xff0c 轮询的范围比较大 xff0c 有优化的地方 2 优化代码 xff1a 通过数组存储client的套接字 xff0c 达到少轮询的效果 xff0c 可以
  • 二.手写迷你版Tomcat-minicat2.0

    minicat 1 0我们实现了返回固定的字符串 34 Hello minicat 34 minicat 2 0需求 xff1a 封装Request和Response对象 xff0c 返回html静态资源文件 封装Request对象 想要封
  • 三.手写迷你版Tomcat-minicat3.0

    minicat 1 0我们实现了返回固定的字符串 34 Hello minicat 34 minicat 2 0封装Request和Response对象 xff0c 返回html静态资源文件 minicat 3 0需求 xff1a 请求se