欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【学习笔记】xml&反射

程序员文章站 2022-07-02 13:45:08
为了灵活实现不同路径执行不同的资源,我们需要使用xml进行配置;为了限定xml内容,需要使用xml约束(dtd或schema);为了获取xml内容,需要使用dom4j进行解析。 1.xml定义 xml全称是Extensible Markup Language,意思是可扩展的标记语言。xml语法和ht ......

 

 

 

【学习笔记】xml&反射

 

为了灵活实现不同路径执行不同的资源,我们需要使用xml进行配置;为了限定xml内容,需要使用xml约束(dtd或schema);为了获取xml内容,需要使用dom4j进行解析。

 1.xml定义

xml全称是Extensible Markup Language,意思是可扩展的标记语言。xml语法和html相似,但html的元素是固定的,xml的标签可以自定义。

 

【学习笔记】xml&反射

 

2.约束

2.1 dtd约束

DTD(Document Type Definition):文档类型定义,用于约束xml文档。规定xml文档中元素的名称,子元素的名称和顺序,元素属性等。

xml文档声明:

【学习笔记】xml&反射

约束文件的元素声明:

【学习笔记】xml&反射

【学习笔记】xml&反射

约束文件的属性声明:

【学习笔记】xml&反射

【学习笔记】xml&反射

 

2.2 schema约束

schema定义:

【学习笔记】xml&反射

引入方式:

【学习笔记】xml&反射

命名空间:

【学习笔记】xml&反射

 【学习笔记】xml&反射

 图解:

【学习笔记】xml&反射

 

 3.xml解析概述

图解:

【学习笔记】xml&反射

 

 

解析方式和解析器:

【学习笔记】xml&反射

【学习笔记】xml&反射

DOM解析原理和结构模型:

【学习笔记】xml&反射

【学习笔记】xml&反射

 API:dom4j的使用:

如果要使用dom4j,必须导入jar包。dom4j必须使用核心类SaxReader加载xml文档获取Document,通过Document对象获得文档的根元素,然后就可以操作了。

【学习笔记】xml&反射

示例代码:

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();
        }
    }
}

 

 4.反射

反射概述:

1、什么是反射技术?

动态获取指定类以及类中的内容(成员),并运行其内容。

应用程序已经运行,无法在其中进行new对象的建立,就无法使用对象。

这时可以根据配置文件的类全名去找对应的字节码文件,并加载进内存,并创建该类对象实例。这就需要使用反射技术完成

2、获取class对象的三种方式

获取Class对象的方式一:

通过对象具备的getClass方法(源于Object类的方法)。有点不方便,需要用到该类,并创建该类的对象,再调用getClass方法完成。

Person p = new Person();//创建Peron对象

Class clazz = p.getClass();//通过object继承来的方法(getClass)获取Person对应的字节码文件对象

获取Class对象的方式二:

       每一个类型都具备一个class静态属性,通过该属性即可获取该类的字节码文件对象。比第一种简单了一些,仅用一个静态属性就搞定了。但是,还是有一点不方便,还必须要使用到该类。

Class clazz = Person.class;

获取Class对象方式三:

static Class forName(className)方法:

        * 相对方便的多,不需要直接使用具体的类,只要知道该类的名字即可。

        * 而名字完全可以作为参数进行传递 ,这样就可以提高扩展性。

        * 为了动态获取一个类,第三种方式最为常用。

    Class clazz = Class.forName("className");//必须类全名

创建Person对象的方式

以前:1,先加载cn.itcast.bean.Person类进内存。

   2,将该类封装成Class对象。

         3,根据Class对象,用new操作符创建cn.itcast.bean.Person对象。

      4,调用构造函数对该对象进行初始化。

Person p = new Person();

通过方式三:(此外还可以使用构造,构造可以指定参数---如String.class)

String className = "Person";

//第一步,根据名称获取其对应的字节码文件对象

       1,通过forName()根据指定的类名称去查找对应的字节码文件,并加载进内存。

       2,并将该字节码文件封装成了Class对象。

       3,直接通过newIntstance方法,完成该对象的创建。

       4,newInstance方法调用就是该类中的空参数构造函数完成对象的初始化。

Class clazz = Class.forName(className);

//第二步,通过Class的方法完成该指定类的对象创建。

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&反射
<?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>
引用的xml约束
<?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&反射

【学习笔记】xml&反射
<?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 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();
    }
}