目標(biāo)
- 使用反射模擬servlet執(zhí)行
XML
- 在servlet中,為了靈活實(shí)現(xiàn)不同的路徑執(zhí)行不同的資源,我們需要使用xml進(jìn)行配置
- 為了限定XML的內(nèi)容,我們需要使用xml的約束(DTD約束或schema約束)
- 為了獲得xml的內(nèi)容,需要使用dom4j進(jìn)行操作
XML簡(jiǎn)介
- xml:可擴(kuò)展標(biāo)記語(yǔ)言
- xml使用的是1.0版本,因?yàn)?.1發(fā)布了基本沒(méi)人用(不向下兼容),所以一直都是用1.0版本
- xml一開(kāi)始作數(shù)據(jù)傳輸,后來(lái)數(shù)據(jù)傳輸json應(yīng)用更廣泛,現(xiàn)在xml多用于配置文件
- xml區(qū)分大小寫(xiě),需要有根元素
- xml屬性值必須要有引號(hào)
XML語(yǔ)法
- 文檔聲明
- <?xml version="1.0" encoding="utf-8"?>
DTD約束
- Document Type Definition
- 開(kāi)發(fā)中我們很少自己寫(xiě)DTD文檔,都是根據(jù)(框架)給定的DTD文件,自己寫(xiě)配置文件(借助工具來(lái)實(shí)現(xiàn))
- DTD文件:
<?xml version="1.0" encoding="UTF-8"?>
<!--
模擬servlet2.3規(guī)范,如果開(kāi)發(fā)人員需要在xml使用當(dāng)前DTD約束,必須包括DOCTYPE搏嗡。
格式如下:
<!DOCTYPE web-app SYSTEM "web-app_2_3.dtd">
-->
<!ELEMENT web-app (servlet*,servlet-mapping* , welcome-file-list?) >
<!ELEMENT servlet (servlet-name,description?,(servlet-class|jsp-file))>
<!ELEMENT servlet-mapping (servlet-name,url-pattern+) >
<!ELEMENT servlet-name (#PCDATA)>
<!ELEMENT servlet-class (#PCDATA)>
<!ELEMENT url-pattern (#PCDATA)>
<!ELEMENT description (#PCDATA)>
<!ELEMENT jsp-file (#PCDATA)>
<!ELEMENT welcome-file-list (welcome-file+)>
<!ELEMENT welcome-file (#PCDATA)>
<!ATTLIST web-app version CDATA #IMPLIED>
- 通過(guò)工具生成的xml文檔
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app SYSTEM "web-app_2_3.dtd">
<web-app version="1.0">
<servlet>
<servlet-name></servlet-name>
<servlet-class></servlet-class>
</servlet>
<servlet-mapping>
<servlet-name></servlet-name>
<url-pattern></url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file></welcome-file>
</welcome-file-list>
</web-app>
shema約束
scheam是新的xml文檔約束
schema比DTD更加強(qiáng)大,是DTD的替代
schema本身也是xml文檔,但scheam的擴(kuò)展名為xsd
schema功能更加強(qiáng)大,數(shù)據(jù)類(lèi)型更加完善
schema支持命名空間
schema文檔
<?xml version="1.0" encoding="UTF-8"?>
<!--
模擬servlet2.5規(guī)范,如果開(kāi)發(fā)人員需要在xml使用當(dāng)前Schema約束螃概,必須包括指定命名空間。
格式如下:
<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">
-->
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/web-app_2_5"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.example.org/web-app_2_5"
elementFormDefault="qualified">
<xsd:element name="web-app">
<xsd:complexType>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="servlet">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="servlet-name"></xsd:element>
<xsd:element name="servlet-class"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="servlet-mapping">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="servlet-name"></xsd:element>
<xsd:element name="url-pattern" maxOccurs="unbounded"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="welcome-file-list">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="welcome-file" maxOccurs="unbounded"></xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
<xsd:attribute name="version" type="double" use="optional"></xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
- 根據(jù)約束生成的xml
<?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>helloServlet</servlet-name>
<servlet-class>xxxxxxxxxx</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
xml解析
- html解析的方式
- DOM:整個(gè)xml文檔加載到內(nèi)存,解析成一個(gè)document對(duì)象
- 優(yōu)點(diǎn):元素與元素之間保留結(jié)構(gòu)關(guān)系,能夠進(jìn)行增刪改查操作
- 缺點(diǎn):xml文件過(guò)大會(huì)導(dǎo)致內(nèi)存溢出
- SAX:逐行解析xml文件
- 優(yōu)點(diǎn):解析速度快,可以處理大文件
- 缺點(diǎn):不能進(jìn)行增刪改查操作
- PULL:Android內(nèi)置的解析方式,類(lèi)似于SAX解析
- DOM:整個(gè)xml文檔加載到內(nèi)存,解析成一個(gè)document對(duì)象
- 使用dom4j解析xml文件
- 需要使用dom4j就需要導(dǎo)入相應(yīng)的jar包
- dom4j的核心類(lèi)是SaxReader,讀取xml文件后獲得Document對(duì)象,通過(guò)Document獲取根元素后進(jìn)行操作
- SaxReader:
- read(...):加載xml文檔
- Document:
- getRootElement():獲取根元素
- Element:
- elements(...):獲取自定名稱(chēng)的所有元素
- element(...):獲取指定名稱(chēng)的第一個(gè)元素
- getName():獲取當(dāng)前元素的元素名
- attribeValue():獲取指定屬性的屬性值
- elementText(...):獲取指定元素的問(wèn)本值
- getText():獲取當(dāng)前元素的文本內(nèi)容
public void testReadWebXML() {
try {
// 1.獲取解析器
SAXReader saxReader = new SAXReader();
// 2.獲得document文檔對(duì)象
Document doc = saxReader.read("src/cn/itheima/xml/schema/web.xml");
// 3.獲取根元素
Element rootElement = doc.getRootElement();
// System.out.println(rootElement.getName());//獲取根元素的名稱(chēng)
// System.out.println(rootElement.attributeValue("version"));//獲取根元素中的屬性值
// 4.獲取根元素下的子元素
List<Element> childElements = rootElement.elements();
// 5.遍歷子元素
for (Element element : childElements) {
//6.判斷元素名稱(chēng)為servlet的元素
if ("servlet".equals(element.getName())) {
//7.獲取servlet-name元素
Element servletName = element.element("servlet-name");
//8.獲取servlet-class元素
Element servletClass = element.element("servlet-class");
System.out.println(servletName.getText());
System.out.println(servletClass.getText());
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
反射
- 通過(guò)接口來(lái)解耦
- 獲得Class對(duì)象
- Class.forName("已知類(lèi)的完整路徑名");
- 已知類(lèi).class
- 已知對(duì)象.getClass()
- 使用默認(rèn)的構(gòu)造方法
- newInstance()
- Constructor對(duì)象
- Constructor對(duì)象是構(gòu)造方法的描述對(duì)象
- 獲取構(gòu)造方法對(duì)象:
- Constructor<T> getConstructor(Class<T> ...parameterTypes),可變參數(shù)用于確定參數(shù)列表
- Constructor<T> getDeclaredConstructor(Class<T> ...parameterTypes)
- newInstance(Object...initargs):可變參數(shù)用于確定實(shí)際參數(shù)列表
- Method對(duì)象
- Method對(duì)象是普通方法的描述對(duì)象
- 獲取方法:
- Method getMethod(String name,Class<T>...params)
- Method getDelcaredMethod(String name,Class<T>...params)
- Ojbect invoke(Object obj,Object...args)
- Filre對(duì)象
- 字段描述對(duì)象
- 獲得方法:
- File getFile(String name)
- File getDeclaredFile(String name)
- 操作:
- Object get(Object obj)
- void set(Object obj,Object...value)
public class TestMyServlet2 {
//8.創(chuàng)建一個(gè)map集合
private HashMap<String, String> data = new HashMap<String,String>();
@Before
public void testReadWEBXml(){
try {
//1.創(chuàng)建解析器對(duì)象
SAXReader saxReader = new SAXReader();
//2.使用解析器加載web.xml文件得到document對(duì)象
Document document = saxReader.read("src/cn/itheima/web/servlet1/web.xml");
//3.獲取根元素節(jié)點(diǎn)
Element rootElement = document.getRootElement();
//4.獲取子節(jié)點(diǎn)(servlet和servlet-mapping)
List<Element> childElements = rootElement.elements();
//5.遍歷
for (Element element : childElements) {
//6.判斷元素的名稱(chēng)為servlet的元素節(jié)點(diǎn)
if("servlet".equals(element.getName())){
//7.分別獲取servlet元素節(jié)點(diǎn)的servlet-name和servlet-class的值
String servletName = element.element("servlet-name").getText();
String servletClass = element.element("servlet-class").getText();
/*System.out.println(servletName);
System.out.println(servletClass);*/
data.put(servletName, servletClass);
}
//9.判斷元素的名稱(chēng)為servlet-mapping的元素節(jié)點(diǎn)
if("servlet-mapping".equals(element.getName())){
//10.分別獲取servlet元素節(jié)點(diǎn)的servlet-name和servlet-class的值
String servletName = element.element("servlet-name").getText();
String urlPattern = element.element("url-pattern").getText();
//11.將servletName作為key來(lái)獲取servletClass的值
String servletClass = data.get(servletName);
//12.將url-pattern作為key,servletClass作為value存到map中去
data.put(urlPattern, servletClass);
//13.移除servletName
data.remove(servletName);
}
}
//System.out.println(data);
} catch (DocumentException e) {
e.printStackTrace();
}
}
@Test
public void testMyServlet(){
try {
//1.模擬在瀏覽器輸入一個(gè)url
String url1 = "/myServlet2";
//2.將urlPattern作為key來(lái)獲取servletClass
String className = data.get(url1);
//3.通過(guò)servletClass獲取字節(jié)碼文件
Class clazz = Class.forName(className);
//4.通過(guò)字節(jié)碼文件創(chuàng)建實(shí)例對(duì)象
Object obj = clazz.newInstance();
//5.通過(guò)字節(jié)碼文件獲取方法(兩個(gè)參數(shù):第一個(gè)是方法名稱(chēng)鸽疾;第二個(gè)參數(shù)是方法的參數(shù))
Method method = clazz.getMethod("service", null);
//6.調(diào)用invoke方法執(zhí)行實(shí)例對(duì)象里面的方法(前面寫(xiě)的方法init)【兩個(gè)參數(shù):第一個(gè)是調(diào)用方法的實(shí)例對(duì)象吊洼,第二個(gè)是方法的實(shí)參】
method.invoke(obj, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}