手写简易版Tomcat第五天

前言

之前我们实现了MyHttpRequest与MyHttpResponse的部分方法。接下来我们要实现自己的MyServlet部分方法。创建出自己的Servlet并将其通过xml文件配置到我们的服务器中。

实现

我们需要实现MyServlet的三个常用方法

  • init():初始化方法
  • void service(MyHttpRequest request, MyHttpResponse response):区分请求方式并处理请求
  • destroy():销毁方法

添加MyServlet接口方法 

public interface MyServlet {
    void init();

    void service(MyHttpRequest request, MyHttpResponse response);

    void destroy();
}

 实现MyHttpServlet抽象接口类

public abstract class MyHttpServlet implements MyServlet {
    @Override
    public void init() {
        System.out.println(getClass().getName()+"执行了初始化方法");
    }

    @Override
    public void service(MyHttpRequest request, MyHttpResponse response) {
        String method = request.getMethod();
        if (method.equals("GET")){
            doGet(request,response);
        }else {
            doPost(request,response);
        }
    }

    protected abstract void doPost(MyHttpRequest request, MyHttpResponse response);

    protected abstract void doGet(MyHttpRequest request, MyHttpResponse response);

    @Override
    public void destroy() {
        System.out.println(getClass().getName()+"执行了销毁方法");
    }
}

 编写Servlet去继承MyHttpServlet实现doGet与doPost方法

public class MyFirstServlet extends MyHttpServlet {
    @Override
    protected void doPost(MyHttpRequest request, MyHttpResponse response) {
        this.doGet(request,response);
    }

    @Override
    protected void doGet(MyHttpRequest request, MyHttpResponse response) {
        response.write("这是我第一个Servlet");
    }
}
public class MySecondServlet extends MyHttpServlet {
    @Override
    protected void doPost(MyHttpRequest request, MyHttpResponse response) {
        this.doGet(request,response);
    }

    @Override
    protected void doGet(MyHttpRequest request, MyHttpResponse response) {
        response.write("这是我第二个Servlet");
    }
}

 至此,我们实现了我们的Servlet。但是,并不能通过浏览器访问我们的Serlvet。我们需要写一个xml配置文件来配置浏览器的访问路径与Servlet的映射关系

xml文件映射

<?xml version="1.0" encoding="UTF-8"?>
<myXml>
    <myServlet>
        <myServlet-name>first</myServlet-name>
        <myServlet-class>com.zmt.servlet.MyFirstServlet</myServlet-class>
    </myServlet>

    <myServlet>
        <myServlet-name>second</myServlet-name>
        <myServlet-class>com.zmt.servlet.MySecondServlet</myServlet-class>
    </myServlet>

    <myServlet-mapping>
        <myServlet-name>first</myServlet-name>
        <myUrl-pattern>/first</myUrl-pattern>
    </myServlet-mapping>

    <myServlet-mapping>
        <myServlet-name>second</myServlet-name>
        <myUrl-pattern>/second</myUrl-pattern>
    </myServlet-mapping>
</myXml>

 xml文件中,描述了ServletName与ServletClass映射与ServletName与Uri的映射关系。接下来编写一个Handler来实现读取xml文件并保存映射关系。这里我使用的是dom4j的jar包中的SAXReader类来解析xml文件。因此需要添加lib文件夹。

 

 大家可以网上搜索一下这两个jar包放入lib目录下 

编写Handler代码 

public class MyServletHandler {
    //这个map用于存放名字和类的全路径的对应关系
    public static final ConcurrentHashMap<String, String> NAME_CLASS = new ConcurrentHashMap<>();
    //这个map用于存放对外访问路径和名字的关系
    public static final ConcurrentHashMap<String, String> PATTERN_NAME = new ConcurrentHashMap<>();
    //这个map用于存放对外访问路径和MyServlet的关系
    public static final ConcurrentHashMap<String, MyServlet> PATTERN_CLASS = new ConcurrentHashMap<>();

    //初始化方法读取xml文件
    public static void init() {
        SAXReader saxReader = new SAXReader();
        try {
            String path = URLDecoder.decode(Objects.requireNonNull(MyServletHandler.class.getResource("/").getPath()), "utf-8");
            Document document = saxReader.read(new File(path + "/webapp/WEB-INF/web.xml"));
            Element element = document.getRootElement();
            List<Element> myServlets = element.elements("myServlet");
            List<Element> myServletMappers = element.elements("myServlet-mapping");
            for (Element myServlet : myServlets) {
                String name = myServlet.element("myServlet-name").getText();
                String classPath = myServlet.element("myServlet-class").getText();
                NAME_CLASS.put(name, classPath);
            }
            for (Element myServletMapper : myServletMappers) {
                String name = myServletMapper.element("myServlet-name").getText();
                String pattern = myServletMapper.element("myUrl-pattern").getText();
                PATTERN_NAME.put(pattern, name);
            }
        } catch (IOException | DocumentException e) {
            e.printStackTrace();
        }
    }
}

修改线程池代码

    public void execute(Socket socket) {
        executor.execute(()->{
            System.out.println(Thread.currentThread().getName()+"开始处理请求");
            try {
                InputStream inputStream = socket.getInputStream();
                MyHttpRequest myHttpRequest = new MyHttpRequest(inputStream);
                //读取完毕后,进行一个简单响应
                OutputStream outputStream = socket.getOutputStream();
                MyHttpResponse myHttpResponse = new MyHttpResponse(outputStream);
                String uri = myHttpRequest.getUri();
                System.out.println(uri);
                //如果能够根据uri拿到对应的myServlet类
                if (MyServletHandler.PATTERN_CLASS.containsKey(uri)) {
                    MyServlet myServlet = MyServletHandler.PATTERN_CLASS.get(uri);
                    myServlet.service(myHttpRequest,myHttpResponse);
                }else if (MyServletHandler.PATTERN_NAME.containsKey(uri)){//如果还没有初始化MyServlet
                    String name = MyServletHandler.PATTERN_NAME.get(uri);
                    System.out.println(name);
                    String classPath = MyServletHandler.NAME_CLASS.get(name);
                    MyServlet myServlet = (MyServlet) Class.forName(classPath).newInstance();
                    MyServletHandler.PATTERN_CLASS.put(uri,myServlet);
                    myServlet.init();
                    myServlet.service(myHttpRequest,myHttpResponse);
                }else {
                    myHttpResponse.setStatus(404);
                    myHttpResponse.write("没有找到该路径");
                }
                socket.close();
            } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        });
    }

 修改启动类代码

public class MyTomCat {
    public static void main(String[] args) {
        TomCatThreadPool threadPool = new TomCatThreadPool(2);
        try {
            //监听8080端口
            ServerSocket serverSocket = new ServerSocket(8080);
            MyServletHandler.init();
            System.out.println("我的服务器启动成功...");
            //socket没接收到关闭事件之前不退出循环
            while (!serverSocket.isClosed()) {
                //等待连接,该事件会阻塞线程
                Socket socket = serverSocket.accept();
                threadPool.execute(socket);
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("服务器启动失败");
        }
    }
}

启动测试

浏览器访问localhost:8080/first

至此。我们实现了自定义Servlet的应用。

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zmbwcx2003

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值