当前位置: 移动技术网 > IT编程>开发语言>Java > 【学习笔记】xml&反射

【学习笔记】xml&反射

2018年08月13日  | 移动技术网IT编程  | 我要评论

情感趣话健德堂,李姝妍,雪碧真我飞扬 放言真我

 

 

 

 

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

 1.xml定义

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

 

 

2.约束

2.1 dtd约束

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

xml文档声明:

约束文件的元素声明:

约束文件的属性声明:

 

2.2 schema约束

schema定义:

引入方式:

命名空间:

 

 图解:

 

 3.xml解析概述

图解:

 

 

解析方式和解析器:

DOM解析原理和结构模型:

 API:dom4j的使用:

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

示例代码:

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

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网