11_XML & 反射

作者: AndroidCat | 来源:发表于2017-06-06 22:57 被阅读0次
    目标
    • 使用反射模拟servlet执行
    XML
    • 在servlet中,为了灵活实现不同的路径执行不同的资源,我们需要使用xml进行配置
    • 为了限定XML的内容,我们需要使用xml的约束(DTD约束或schema约束)
    • 为了获得xml的内容,需要使用dom4j进行操作
    XML简介
    • xml:可扩展标记语言
    • xml使用的是1.0版本,因为1.1发布了基本没人用(不向下兼容),所以一直都是用1.0版本
    • xml一开始作数据传输,后来数据传输json应用更广泛,现在xml多用于配置文件
    • xml区分大小写,需要有根元素
    • xml属性值必须要有引号
    XML语法
    • 文档声明
      • <?xml version="1.0" encoding="utf-8"?>
    DTD约束
    • Document Type Definition
    • 开发中我们很少自己写DTD文档,都是根据(框架)给定的DTD文件,自己写配置文件(借助工具来实现)
    • DTD文件:
    <?xml version="1.0" encoding="UTF-8"?>
    <!--
        模拟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>
    
    • 通过工具生成的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更加强大,是DTD的替代

    • schema本身也是xml文档,但scheam的扩展名为xsd

    • schema功能更加强大,数据类型更加完善

    • schema支持命名空间

    • schema文档

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 
        模拟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 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解析的方式
      1. DOM:整个xml文档加载到内存,解析成一个document对象
        • 优点:元素与元素之间保留结构关系,能够进行增删改查操作
        • 缺点:xml文件过大会导致内存溢出
      2. SAX:逐行解析xml文件
        • 优点:解析速度快,可以处理大文件
        • 缺点:不能进行增删改查操作
      3. PULL:Android内置的解析方式,类似于SAX解析
    • 使用dom4j解析xml文件
      • 需要使用dom4j就需要导入相应的jar包
      • dom4j的核心类是SaxReader,读取xml文件后获得Document对象,通过Document获取根元素后进行操作
      • SaxReader:
        • read(...):加载xml文档
      • Document:
        • getRootElement():获取根元素
      • Element:
        • elements(...):获取自定名称的所有元素
        • element(...):获取指定名称的第一个元素
        • getName():获取当前元素的元素名
        • attribeValue():获取指定属性的属性值
        • elementText(...):获取指定元素的问本值
        • getText():获取当前元素的文本内容
    public void testReadWebXML() {
        try {
            // 1.获取解析器
            SAXReader saxReader = new SAXReader();
            // 2.获得document文档对象
            Document doc = saxReader.read("src/cn/itheima/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 element : childElements) {
                //6.判断元素名称为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();
        }
    }
    
    反射
    • 通过接口来解耦
    • 获得Class对象
      1. Class.forName("已知类的完整路径名");
      2. 已知类.class
      3. 已知对象.getClass()
    • 使用默认的构造方法
      • newInstance()
    • Constructor对象
      • Constructor对象是构造方法的描述对象
      • 获取构造方法对象:
        • Constructor<T> getConstructor(Class<T> ...parameterTypes),可变参数用于确定参数列表
        • Constructor<T> getDeclaredConstructor(Class<T> ...parameterTypes)
        • newInstance(Object...initargs):可变参数用于确定实际参数列表
    • Method对象
      • Method对象是普通方法的描述对象
      • 获取方法:
        • Method getMethod(String name,Class<T>...params)
        • Method getDelcaredMethod(String name,Class<T>...params)
        • Ojbect invoke(Object obj,Object...args)
    • Filre对象
      • 字段描述对象
      • 获得方法:
        • File getFile(String name)
        • File getDeclaredFile(String name)
      • 操作:
        • Object get(Object obj)
        • void set(Object obj,Object...value)
    public class TestMyServlet2 {
        //8.创建一个map集合
        private HashMap<String, String> data = new HashMap<String,String>();
        
        @Before
        public void testReadWEBXml(){
            try {
                //1.创建解析器对象
                SAXReader saxReader = new SAXReader();
                //2.使用解析器加载web.xml文件得到document对象
                Document document = saxReader.read("src/cn/itheima/web/servlet1/web.xml");
                //3.获取根元素节点
                Element rootElement = document.getRootElement();
                //4.获取子节点(servlet和servlet-mapping)
                List<Element> childElements = rootElement.elements();
                //5.遍历
                for (Element element : childElements) {
                    //6.判断元素的名称为servlet的元素节点
                    if("servlet".equals(element.getName())){
                        //7.分别获取servlet元素节点的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.判断元素的名称为servlet-mapping的元素节点
                    if("servlet-mapping".equals(element.getName())){
                        //10.分别获取servlet元素节点的servlet-name和servlet-class的值
                        String servletName = element.element("servlet-name").getText();
                        String urlPattern = element.element("url-pattern").getText();
                        //11.将servletName作为key来获取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.模拟在浏览器输入一个url
                String url1 = "/myServlet2";
                //2.将urlPattern作为key来获取servletClass
                String className = data.get(url1);
                //3.通过servletClass获取字节码文件
                Class clazz = Class.forName(className);
                //4.通过字节码文件创建实例对象
                Object obj = clazz.newInstance();
                //5.通过字节码文件获取方法(两个参数:第一个是方法名称;第二个参数是方法的参数)
                Method method = clazz.getMethod("service", null);
                //6.调用invoke方法执行实例对象里面的方法(前面写的方法init)【两个参数:第一个是调用方法的实例对象,第二个是方法的实参】
                method.invoke(obj, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    

    相关文章

      网友评论

        本文标题:11_XML & 反射

        本文链接:https://www.haomeiwen.com/subject/vfnnfxtx.html