为灵活实现不同路径执行不同的资源,需要使用XML进行配置。
XML 意为可扩展的标记语言,标签可以由用户自定义。通常进行配置文件,不是HTML的替代者而是补充。
XML文档声明必须为<?xml开头,以?>结束 ,0行0列开始,只有三个属性 versioin 版本 encoding 编码
为限定XML的内容,使用XML约束 常见 :DTD Schema
一、DTD约束
通常不会自己写DTD文档,需要根据提供的DTD约束编写对应的XML文档。常见框架使用DTD约束的有Struts2、Hibernate等
例根据如下dtd约束编写XML文档
<?xml version="1.0" encoding="UTF-8"?>
<!--
传智播客DTD教学实例文档。
模拟servlet2.3规范,如果开发人员需要在xml使用当前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>
二、Schema约束
常用框架使用的有Spring等,后缀为xsd,DTD的替代者,数据类型更完善,支持名称命名空间。
命名空间:处理元素和属性的名称冲突。
<?xml version="1.0" encoding="UTF-8"?>
<!--
传智播客Schema教学实例文档。
模拟servlet2.5规范,如果开发人员需要在xml使用当前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>
XML解析,获取XML的内容。IO可以做但繁琐。比较常见的解析有 DOM SAX PULL(理论解析方法)
DOM:要求解析器把整个XML文档装载到内存,解析成Document对象
优点 元素与元素之间保留结构关系,可以进行增删改查操作。 缺点 当XML文档过大可能出现内存溢出
SAX:逐行扫描,边扫描边解析,速度更快,更有效。优点 处理快可以处理大文件 缺点 只能读 逐行后释放资源。
PULL 安卓内置的XML解析方式类似SAX。
解析器
使用dom4j 常用解析开发包,hibernate底层采用。必须导入jar包。必须使用核心类SaxReader加载xml文档获取Document,再获得文档根元素。
public class TestDom4j {
@Test
public void testReadWebXML() {
try {
// 1、获得解析器
SAXReader saxReader = new SAXReader();
// 2、获得document文档对象
Document doc = saxReader.read("src/XML_Schema/web.XML");
//3、获取根元素
Element rootElement = doc.getRootElement();
//System.out.println(rootElement.getName()); 获取根元素的名称
//System.out.println(rootElement.attributeValue("version"));获取根元素的属性值
//4、获取根元素下的子元素
List<Element> childElements = rootElement.elements();
//5、遍历子元素
for(Element i:childElements)
{
//找到与字符串相同的子元素 获取其中的text
if("servlet".equals(i.getName())) {
Element servletName = i.element("servlet-name");
Element servletClass = i.element("servlet-class");
System.out.println(servletName.getText());
System.out.println(servletClass.getText());
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
利用反射模拟servlet的运行
为模拟服务器端程序,且可以同时存在多个类似程序。提供一个Myservlet接口,接口中有三个方法。编写两个实现类1和2
public class MyServletImpl implements MyServlet {
@Override
public void init() {
System.out.println("1号111");
}
@Override
public void service() {
System.out.println("1号222");
}
@Override
public void destory() {
System.out.println("1号333");
}
}
此时为程序的可扩展性,防止硬编码,通过反射加载字符串指定类,并创建实例。通过解析XML文档获取类全名和url,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>Servlet1</servlet-name>
<servlet-class>servlet.MyServletImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet1</servlet-name>
<url-pattern>/myServlet1</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Servlet2</servlet-name>
<servlet-class>servlet.MyServletImpl2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Servlet2</servlet-name>
<url-pattern>/myServlet2</url-pattern>
</servlet-mapping>
</web-app>
在执行测试程序前 解析XML文件 将解析结果放在map 格式为路径=实现类。servlet标签中存着类全名,servlet-mapping存着url。解析方法和实现方法如下
public class Test2 {
/*使用反射模拟servlet的运行
* XML配置文件中实现类的类全名和url 但分属于不同的标签中
*/
private HashMap<String,String> data= new HashMap<String,String>(); //存储url,类全名
@Before
public void getMethod(){
try {
//从XML文件中解析类全名存入一个map中
SAXReader saxReader = new SAXReader ();
Document read = saxReader.read("src/XML_Schema/web.XML");
Element rootElement = read.getRootElement();
List<Element> elements = rootElement.elements();
//servlet标签中存着类全名,servlet-mapping中存着url
for(Element i:elements)
{
if("servlet".equals(i.getName()))
{
//先将名字,类全名添加进data
data.put(i.element("servlet-name").getText(), i.element("servlet-class").getText());
}
if("servlet-mapping".equals(i.getName()))
{
//获取类全名
String servletClass = data.get(i.element("servlet-name").getText());
data.remove(i.element("servlet-name").getText());//移除之前添加的名字,类全名
data.put(i.element("url-pattern").getText(),servletClass);//添加url,类全名
}
}
//System.out.println(data);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testMethod(){
try {
String urll = "/myServlet1";
String clazz = data.get(urll);
Class<?> forName = Class.forName(clazz);
MyServlet servlet = (MyServlet) forName.newInstance();
servlet.init();
servlet.service();
servlet.destory();
} catch (Exception e) {
e.printStackTrace();
}
}
}