为了灵活实现不一样路径执行不一样的资源,咱们须要使用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(); } }