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

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 = "

get request

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

post request

"
; 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了


<web-app>
    <servlet>
        <servlet-name>demoservlet-name>
        <servlet-class>server.DemoServletservlet-class>
    servlet>


    <servlet-mapping>
        <servlet-name>demoservlet-name>
        <url-pattern>/demourl-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) {
             // demo
             Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
             String servletName = servletnameElement.getStringValue();
             // server.DemoServlet
             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()方法中实现的
三.手写迷你版Tomcat-minicat3.0_第1张图片
添加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();

        }
    }

效果演示
三.手写迷你版Tomcat-minicat3.0_第2张图片

你可能感兴趣的:(手写框架,tomcat)