爲了靈活實現不一樣路徑執行不一樣的資源,咱們須要使用xml進行配置;爲了限定xml內容,須要使用xml約束(dtd或schema);爲了獲取xml內容,須要使用dom4j進行解析。html
1.xml定義
xml全稱是Extensible Markup Language,意思是可擴展的標記語言。xml語法和html類似,但html的元素是固定的,xml的標籤能夠自定義。java
2.xml約束
2.1 DTD約束
DTD(Document Type Definition):文檔類型定義,用於約束xml文檔,規定xml文檔中元素的名稱,子元素的名稱和順序,元素屬性等。web
2.2 schema約束
schema是新的xml文檔約束,比DTD強大不少,是DTD的替代者。schema自己也是xml文檔,但擴展名是sxd。
schema支持命名空間,用於處理元素和屬性的名稱衝突問題。編程
約束引入能夠是本地引入SYSTEM和網絡引入PUBLICapi
3.xml解析
常見的xml解析方式有三種:瀏覽器
解析器:就是根據不一樣的解析方式提供不一樣的具體實現。網絡
(1)DOM:要求解析器把整個xml文檔裝載到內存,並解析成一個Document對象
優勢:元素之間保留結構關係,能夠進行增刪改查操做
缺點:xml文檔過大時可能出現內存溢出。app
(2)SAX:是一種高速,高效率的方法。它逐行掃描文檔,一邊掃描一邊解析,並以事件驅動的方式進行具體解析,每執行一行,就觸發對應的事件。解析器SaxReader對象。
優勢:速度快,能夠處理大文件
缺點:只能讀,讀完一行後將釋放資源。dom
(3)PULL:Android內置的xml解析方式,相似SAXjvm
常見的解析開發包:
JAXP:sun公司提供支持DOM和SAX開發包
JDOM:dom4j的兄弟
jsoup:一種處理html特定解析開發包
dom4j:經常使用的解析開發包
4.SAX解析之解析包dom4j的使用
若是要使用dom4j,必須導入jar包。dom4j必須使用核心類SaxReader加載xml文檔獲取Document,經過Document對象得到文檔的根元素(web-app),而後就能夠操做了。示例代碼:
package com.xing.xml; import java.util.List; //dom4j的使用 import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.junit.jupiter.api.Test; public class test { @Test public void test001() { try { //1.獲取Document SAXReader saxReader=new SAXReader(); Document document; document = saxReader.read("src/com/xing/xml/web.xml"); //2.得到根元素 Element rootElement=document.getRootElement(); System.out.println("根元素:"+rootElement); System.out.println("根元素的version屬性:"+rootElement.attributeValue("version"));//獲取version屬性 //3.得到根元素的子標籤,Servlet,Servlet-Mapping List<Element> AllChildElements = rootElement.elements(); System.out.println("根元素的全部子標籤:"+AllChildElements); //遍歷全部子標籤 for (Element childElement : AllChildElements) { //4.處理servlet,並獲取子標籤的內容如servlet-name if("servlet".equals(childElement.getName())) { //方式一:得到元素對象,而後獲取文本 System.out.println("方式一獲取標籤servlet-name內容:"+childElement.element("servlet-name").getText()); //方式二:獲取元素文本值 System.out.println("方式二獲取標籤servlet-class內容"+childElement.elementText("servlet-class")); } } } catch (DocumentException e) { e.printStackTrace(); } } }
5.反射
a.什麼是反射技術?
動態獲取指定類以及類中的內容,並運行其內容。
應用程序已經運行,沒法在其中進行new對象的創建,就沒法使用對象。這時能夠根據配置文件的類全名去找對應的字節碼文件(類編譯後的.class文件),並加載進內存,並建立該類對象實例。這就須要使用反射技術完成。
b.獲取Class對象的三種方式
tips:類對象指類的Class對象,也就是字節碼對象。能夠經過Class.forName()/getclass()/.class來獲取,當jvm加載一個類時就會爲這個類建立一個Class對象;
類的對象,一般就是指經過new這個類或者反射獲得Class對象再調用newInstance()建立的對象,存在內存的堆中,也叫類的實例
方式一:建立該類的對象,再調用getClass方法完成。
Person p = new Person();
Class clazz = p.getClass();//經過object繼承來的方法(getClass)獲取Person對應的字節碼文件對象
方式二:每個類都具有一個class靜態屬性,經過該屬性便可獲取該類的字節碼文件對象。但仍是有一點不方便,還必需要使用到該類。
Class clazz = Person.class;
獲取Class對象方式三: Class.forName(className)方法:
相對方便,不須要直接使用具體的類,只要知道該類的名字便可。而名字徹底能夠做爲參數進行傳遞 ,這樣就能夠提升擴展性。所以爲了動態獲取一個類,第三種方式最爲經常使用。
Class clazz = Class.forName("className");//必須類全名
c.建立類的對象的方式
之前:先加載Person類進內存,將該類封裝成Class對象。根據Class對象,用new操做符建立Person對象,調用構造函數對該對象進行初始化。Person p = new Person();
經過上面的方式三:
(反射的關鍵)
根據名稱獲取其對應的字節碼文件對象:
1.根據指定的類名稱,經過forName()去查找對應的字節碼文件,並加載進內存.
2.將該字節碼文件封裝成Class對象(類對象)。
3.直接經過newIntstance方法,完成該對象的建立(類的對象)。
如:
String className = "Person";
Class clazz = Class.forName(className);
Object object = clazz.newInstance();
反射代碼示例:
package com.xing.testMap; public interface MyServlet { public void testMyServlet(); }
package com.xing.testMap; public class MyServletImpl implements MyServlet{ @Override public void testMyServlet() { System.out.println("hello,test"); } }
package com.xing.testMap; import org.junit.Test; /** * 若是直接使用new MyServletImpl(),這種編程方式稱之爲硬編碼,即代碼寫死了 * 爲了程序後期的可擴展性,使用反射較爲合適 * @author Xing * */ public class test{ @Test public void test() throws Exception { //1.Class.forName()返回指定接口或類的對象。(實現類) //2.newInstance()經過class對象建立類的實例對象,至關於new xxx Class clazz=Class.forName("com.xing.testMap.MyServletImpl"); MyServlet myservlet=(MyServlet) clazz.newInstance();//須要強轉 //執行 myservlet.testMyServlet(); } }
以上程序使用反射能夠建立對象的實例,但使用的是全限定類名,程序仍然是寫死的,接下來咱們將經過讀取xml文件的類名(servlet-class)來優化Class.forName("com.xing.testMap.MyServletImpl")
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app SYSTEM "web-app_2_3.dtd"> <web-app version="4.0"> <servlet> <servlet-name>helloMyservlet</servlet-name> <servlet-class>com.xing.testMapAndXml.MyServletImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>helloMyservlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
package com.xing.testMapAndXml; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.junit.Test; //MyServlet.java,MyServletImpl.java和上面的同樣 public class test { @Test public void test() { try { //加載xml文件 SAXReader saxReader = new SAXReader(); Document document = saxReader.read("src/com/xing/testMapAndXml/web.xml"); //獲取第一個子標籤servlet Element element = document.getRootElement().element("servlet"); String servletElement = element.elementText("servlet-class");//讀取xml文件裏的類名 MyServlet myserlet=(MyServlet) Class.forName(servletElement).newInstance(); myserlet.testMyServlet(); } catch (Exception e) { e.printStackTrace(); } } }
模擬瀏覽器路徑:
上面咱們已經解析了xml文件,不過得到的內容是固定的,咱們但願若是用戶訪問的路徑是/hello,將執行MyServlet程序,若是訪問/hello2,將執行MyServlet2程序。
代碼示例(接口和實現類省略了):讀取xml文件後,把url-pattern和servlet-class組成鍵值對,調用時使用不一樣的key獲取不一樣的類全名來建立對象,執行對象的方法。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://www.example.org/web-app_2_5" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/web-app_2_5 web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>helloMyservlet</servlet-name> <servlet-class>com.xing.testXmlAndBrowser.MyServletImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>helloMyservlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet> <servlet-name>helloMyservlet2</servlet-name> <servlet-class>com.xing.testXmlAndBrowser.MyServletImpl2</servlet-class> </servlet> <servlet-mapping> <servlet-name>helloMyservlet2</servlet-name> <url-pattern>/hello2</url-pattern> </servlet-mapping> </web-app>
package com.xing.testXmlAndBrowser; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.junit.Before; import org.junit.Test; public class test { //key:請求路徑,value:實現類 private Map<String, String> data=new HashMap<String,String>(); @Before public void getMap() { try { SAXReader saxReader = new SAXReader(); Document document = saxReader.read("src/com/xing/testXmlAndBrowser/web.xml"); //得到全部子元素 List<Element> AllChildElements = document.getRootElement().elements(); //遍歷全部子元素,1.解析到servlet,將其子標籤servlet-name,servlet-class存放在Map中. //2.解析到servlet-mapping,得到子標籤servlet-name,url-pattern,從Map中得到1的內容,組合成url=class鍵值對 for (Element childElement : AllChildElements){ if("servlet".equals(childElement.getName())) { String servletName = childElement.elementText("servlet-name"); String servletClass = childElement.elementText("servlet-class"); data.put(servletName,servletClass); } //若是是servlet-mapping,得到其內容,組成鍵值對存放於Map中 if("servlet-mapping".equals(childElement.getName())) { String servletName=childElement.elementText("servlet-name"); String urlPattern=childElement.elementText("url-pattern"); //得到servlet-name以前存放在Map中的servlet-class值.與urlPattern組成鍵值對 String servletClass = data.get(servletName); data.put(urlPattern,servletClass); //將以前存放的數據刪除.Map(urlPattern,classImpl) data.remove(servletName); } } // System.out.println(data); } catch (Exception e) { e.printStackTrace(); } } @Test public void test() throws Exception { String key = "/hello"; String key2 = "/hello2"; MyServlet myServlet = (MyServlet) Class.forName(data.get(key)).newInstance(); MyServlet2 myServlet2 = (MyServlet2) Class.forName(data.get(key2)).newInstance(); myServlet.testMyServlet(); myServlet2.testMyServlet2(); } }