上節寫到讀取靜態文件,接下來仿一個讀取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功能。