手寫簡單版Tomcat(二)——XML解析配置

上節寫到讀取靜態文件,接下來仿一個讀取web.xml配置文件的功能。

首先,讀取XML我參考的是這篇文章:https://www.cnblogs.com/hongwz/p/5514786.html

但是這篇文章裏的讀取XML是遠遠不夠的,內容中的讀取XML方法是讀取寫死固定的XML,而且只能讀取到第一、二層節點,web.xml中可不遠遠不止一兩層,於是得重新寫個可以讀取不限深度的XML的方法。

第一次修改的XML方法如下:

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class XmlUtil {

    /*
    *   用Map封裝XML實體
    *   一個標準的XML節點有3個參數:節點名String,參數名List<Map<String,Object>>,子節點List<Map>
    *
    *
    * */

    public static Object read(String path) throws Exception {
        //SAXReader就是一個管道,用一個流的方式,把xml文件讀出來
        SAXReader reader = new SAXReader();
        File file = new File(path);
        Map result = new HashMap();
        Document document = reader.read(file);
        Element root = document.getRootElement();
        List<Element> childElements = root.elements();
        result.put("firstElement", root.getName());
        result.put("Attribute", root.attributes());
        for (Element child : childElements) {

            //未知屬性名情況下

            List<Attribute> attributeList = child.attributes();

            for (Attribute attr : attributeList) {

                System.out.println(attr.getName() + ": " + attr.getValue());

            }


            //未知子元素名情況下

            List<Element> elementList = child.elements();

            for (Element ele : elementList) {

                System.out.println(ele.getName() + ": " + ele.getText());

            }

            System.out.println();

            //這行是爲了格式化美觀而存在

            System.out.println();

        }
        return null;
    }

}

該方法能讀取到 第二層節點的內容

需要注意的是,web.xml是在tomcat啓動的時候讀取的,所以我在監聽8080端口的時候讀取的web.xml,web.xml文件我規定放在resource目錄下

root就是第一層節點,也就是<web></web> 

root.elements是讀取<web></web>的子節點

然後對<web></web>的子節點和屬性進行循環輸出,最終輸出成

xml從結構上還是比較簡單的,

但是上面的這個方法只能讀取到第二層節點<title></title>,<author></author>,如果在title節點中再加個子節點,那麼就讀取不到了,

如圖,確實讀取不到,

OK,那麼接下來就是對xml的讀取方法進行修改,讓他可以無限深度的讀取xml。

 我們先不要那麼快就敲代碼,先分析下XML結構

就像上面說的一樣,XML結構上比較簡單,

就只有節點、屬性、內容這三個東西

是滴。。。。。。

============================================================這是分隔符,代表有重大改變

剛剛突然想到,貌似我不用一下子讀取全部的節點,只需要讀取到第一個就行了,用到了再讀取他的子節點,所以就不用改成無限深度的讀取xml,只要改成返回第一個節點的方法就行了。

所以代碼改成如下:

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class XmlUtil {

    /*
    *   用Map封裝XML實體
    *   一個標準的XML節點有3個參數:節點名String,參數名List<Map<String,Object>>,子節點List<Map>
    * */

    public static Object read(String path) throws Exception {
        //SAXReader就是一個管道,用一個流的方式,把xml文件讀出來
        SAXReader reader = new SAXReader();
        File file = new File(path);
        Document document = reader.read(file);
        Element root = document.getRootElement();
        return root;

    }

}

讀取到了第一個節點,然後再寫一個方法解析,因爲只是簡單版tomcat,所以web.xml中的內容就不做太多解析

web.xml中的配置我是參照以下博客改的:

https://www.cnblogs.com/hxsyl/p/3435412.html

https://www.cnblogs.com/vanl/p/5737656.html

https://www.cnblogs.com/hafiz/p/5715523.html

下面是摘抄上面鏈接的一些原文,作爲對web.xml的一些介紹:

xml必須有且只有一個根節點,大小寫敏感,標籤不嵌套,必須配對。

web.xml是不是必須的呢?不是的,只要你不用到裏面的配置信息就好了,不過在大型web工程下使用該文件是很方便的,若是沒有也會很複雜。

那麼web.xml能做的所有事情都有那些?其實,web.xml的模式(Schema)文件中定義了多少種標籤元素,web.xml中就可以出現它的模式文件所定義的標籤元素,它就能擁有定義出來的那些功能。web.xml的模式文件是由Sun公司定義的,每個web.xml文件的根元素<web-app>中,都必須標明這個web.xml使用的是哪個模式文件。

在這裏我就只寫幾個主要標籤的解析:

Servlet配置(Servlet放後面寫)

  <servlet>
     <servlet-name>servlet名稱</servlet-name>
     <servlet-class>servlet類全路徑</servlet-class>
     <init-param>
         <param-name>參數名</param-name>
         <param-value>參數值</param-value>
     </init-param>
         <run-as>
             <description>Security role for anonymous access</description>
         <role-name>tomcat</role-name>
     </run-as>
    <load-on-startup>指定當Web應用啓動時,裝載Servlet的次序</load-on-startup>
 </servlet>
 <servlet-mapping>
     <servlet-name>servlet名稱</servlet-name>
     <url-pattern>映射路徑</url-pattern>
 </servlet-mapping>
指定歡迎文件頁配置

  <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
      <welcome-file>index.html</welcome-file>
      <welcome-file>index.htm</welcome-file>
  </welcome-file-list>
配置錯誤頁面

  (1).通過錯誤碼來配置error-page
 <!--配置了當系統發生404錯誤時,跳轉到錯誤處理頁面NotFound.jsp-->
 <error-page>
       <error-code>404</error-code>
       <location>/NotFound.jsp</location>
 </error-page>

編碼過程我就不詳寫了,

最終XML解析類如下:

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class XmlUtil {

    /*
    *   用Map封裝XML實體
    *   一個標準的XML節點有3個參數:節點名String,參數名List<Map<String,Object>>,子節點List<Map>
    * */

    public static Object read(String path) throws Exception {

        //SAXReader就是一個管道,用一個流的方式,把xml文件讀出來
        SAXReader reader = new SAXReader();
        File file = new File(path);
        Document document = reader.read(file);
        Element root = document.getRootElement();
        return root;

    }

    //解析Web.xml   analysis 解析
    public static boolean analysisWeb(){

        File directory = new File("src/main/resources/web.xml");
        try {
            Element root = (Element) read(directory.getAbsolutePath());
            if (!"web-app".equals(root.getName())){
                return false;
            }else{
                List<Element> elements = root.elements();

                for ( Element element : elements ) {

                    //welcome-file-list     歡迎文件頁配置
                    if ("welcome-file-list".equals(element.getName())){
                        List<Element> welcome_file_list = element.elements();
                        if (welcome_file_list.size() > 0){
                            for ( Element welcome_file : welcome_file_list ){
                                if ("welcome-file".equals(welcome_file.getName()))
                                    Response.indexPages.add(welcome_file.getText());
                            }
                        }
                    }

                    //error-page   通過錯誤碼來配置error-page
//                    if ("error-page".equals(elements)){
//                        List<Element> welcome_file_list = element.elements();
//                        if (welcome_file_list.size() > 0){
//                            for ( Element welcome_file : welcome_file_list ){
//                                if ("welcome-file".equals(welcome_file.getName()))
//                                    Response.Index.add(welcome_file.getText());
//                            }
//                        }
//                    }

                }

            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return false;
    }

}

能把歡迎頁讀取出來,那麼錯誤頁也是一樣的,

同時,Response.java我也有做修改:

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class Response {
  public static final int BUFFER_SIZE = 2048;
  //瀏覽器訪問D盤的文件
  private static final String RESOURCE ="src/main/resources";
  private Request request;
  private OutputStream output;
  public static List<String> indexPages = new ArrayList<String>();

  public Response(OutputStream output) {
    this.output = output;
  }
  public void setRequest(Request request) {
    this.request = request;
  }

  public void sendStaticResource() throws IOException {
    byte[] bytes = new byte[BUFFER_SIZE];
    FileInputStream fis = null;
    try {
      //首頁
      if ("/".equals(request.getUrL())){
        if (indexPages.size() > 0) {
          File file = new File(RESOURCE, indexPages.get(0));
          if (null != getFile(file)){
            String retMessage = (String) getFile(file);
            output.write(retMessage.getBytes());
            return;
          }
        }else{
          String retMessage = "<h1> Index not Found</h1>";
          String returnMessage ="HTTP/1.1 404 File Not Found\r\n" +
                  "Content-Type: text/html\r\n" +
                  "Content-Length: "+retMessage.length()+"\r\n" +
                  "\r\n" +
                  retMessage;
          output.write(returnMessage.getBytes());
          return;
        }
      }
      //====================================首頁結束

      //拼接本地目錄和瀏覽器端口號後面的目錄
      File file = new File(RESOURCE, request.getUrL());
      String retMessage = (String) getFile(file);
      if (null != retMessage){
        output.write(retMessage.getBytes());
      }else{
        //文件不存在,返回給瀏覽器響應提示,這裏可以拼接HTML任何元素
        retMessage = "<h1>"+file.getName()+" file or directory not exists</h1>";
        String returnMessage ="HTTP/1.1 404 File Not Found\r\n" +
                "Content-Type: text/html\r\n" +
                "Content-Length: "+retMessage.length()+"\r\n" +
                "\r\n" +
                retMessage;
        output.write(returnMessage.getBytes());
      }
    }
    catch (Exception e) {
      System.out.println(e.toString() );
    }
    finally {
      if (fis!=null)
        fis.close();
    }
  }

  public Object getFile(File file) throws Exception {
    FileInputStream fis = null;
    String retMessage = null;
    //如果文件存在,且不是個目錄
    if (file.exists() && !file.isDirectory()) {
      fis = new FileInputStream(file);
      InputStreamReader reader = new InputStreamReader(fis,"UTF-8"); //最後的"GBK"根據文件屬性而定,如果不行,改成"UTF-8"試試
      BufferedReader br = new BufferedReader(reader);
      String line;
      StringBuilder readLine = new StringBuilder();
      while ((line = br.readLine()) != null) {
        readLine.append(line);
      }
      retMessage = "HTTP/1.1 200 OK\r\n" +
              "Content-Type: text/html;charset=utf-8\r\n" +
              "Content-Length: "+ readLine.toString().getBytes().length +"\r\n" +
              "\r\n" +
              readLine;
    }else {
      return null;
    }
    return retMessage;
  }

}

讀取File的代碼我提取出來了

 這是讀取首頁的代碼

當Url爲 "/" 的時候就是http://localhost:8080/默認的這個網址,也就是首頁

如果是訪問首頁,我就會去拿indexPages這個變量

 這個indexPages是在類啓動的時候加載進來的,

 解析web.xml是如果有    welcome-file    這個標籤我就把這個首頁地址存進indexPages中

這是我的index頁面

最後,啓動服務器,訪問localhost:8080

 返回成功!

第二節xml的讀取就到此告一段落了,

如果有什麼寫的不對的地方,歡迎下方評論指出!

接下來的第三節會解析java文件,一個真正意義上的簡單版tomcat功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章