1. 程式人生 > 實用技巧 >JavaSE第25篇:列舉、XML

JavaSE第25篇:列舉、XML

核心概述:在以後的專案開發中,在專案中和業務狀態相關的標識我們一般使用列舉來管理,並且在開發中我們會使用框架+配置檔案提高程式的開發效率和靈活性,其中我們使用xml用作配置檔案,本篇我們將列舉、XML

目錄

第一章:列舉

核心概述:在以後的專案開發中,在專案中和業務狀態相關的標識我們一般使用列舉來管理,並且在開發中我們會使用框架+配置檔案提高程式的開發效率和靈活性,其中我們使用xml用作配置檔案,本篇我們將列舉、XML

1.1-概述(瞭解)

列舉是JDK1.5新增的引用資料型別,和類,介面是一個級別的,定義列舉的關鍵字為enum

java.lang.Enum類,是所有列舉的父類。

列舉的本質就是一個類的多個物件。

1.2-列舉的定義和使用(重要)

定義

格式:public enmu 列舉名{}

  • 列舉中的常量名字大寫,多個常量之間逗號分開,最後一個常量可以寫分號,也可以不寫。每一個常量,都表示這個類的物件。修飾符為public static final
  • 列舉中有預設的無引數的private修飾的構造方法,如果手寫構造方法,也必須是私有修飾的。而且構造方法必須寫在常量的後面,這時最後一個常量就必須要寫分號。

示例

示例1:(常用)

public enum  Color {
    //列舉的靜態常量
    RED,GREEN,YELLOW
}

示例2:(瞭解)

public enum Color{
	//列舉靜態常量,直接為變數color賦值
	RED("紅色"),GREEN("綠色"),YELLOW("黃色");
	private String color;
	private Color(String color){
		this.color = color ;
	}
    //省略get/set
}

使用列舉

由於列舉的常量為靜態修飾可以直接列舉名.呼叫

public static void main(String[] args){
    Color color = Color.GREEN;
    System.out.println(color);
    System.out.println(color.getName());
}

第二章:XML

2.1-概述(瞭解)

什麼是XML

XML :可擴充套件標記語言(EXtensibleMarkupLanguage

XML 它是一種標記語言,很類似 HTML,HTML檔案也是XML文件,標籤都是自定義的。 如:<user></user> 或 <student></student>

W3C在1998年2月釋出1.0版本,2004年2月又釋出1.1版本,單因為1.1版本不能向下相容1.0版本,所以1.1沒有人用。同時,在2004年2月W3C又釋出了1.0版本的第三版。我們要學習的還是1.0版本

XML與HTML的差異

  • xml標籤都是自定義的,html標籤是預定義。
  • xml的語法嚴格,html語法鬆散。
  • xml是儲存資料的,html是展示資料。

XML的作用

XML是儲存資料的。示例如下:

<?xml version="1.0" encoding="UTF-8"?>
<persons>
	<person id="p001">
		<name>張三</name>
	</person>
	<person id="p002">
		<name>李四</name>
	</person>
</persons>

類似於Java程式碼,示例如下:

class Person{
	String id;
	String name;
}

public void test(){
	HashSet<Person> persons = new HashSet<Person>();
	persons.add( new Person("p001","張三") );
	persons.add( new Person("p002","李四") );
}

XML可作用配置檔案。示例如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean className="com.it.bean.User">
		<property name="username" value="jack"></property>
	</bean>
</beans>

類似於Java程式碼,示例如下:

class User{
	private String username;
	private String pws;
	//補全set\get方法
}
class Test{
    public static void main(String[] args){
        Class clazz = Class.forName("com.it.bean.User");
        Object obj = clazz.newInstance();
        Method method = clazz.getMethod("setUsername",String.class);
        method.invoke(obj,"jack");
    }
}

2.2-XML的組成(重點)

組成部分:文件宣告

XML文件宣告格式:

<?xml version="1.0" encoding="UTF-8"?>
  1. versioin:指定XML文件版本。必須屬性,因為我們不會選擇1.1,只會選擇1.0;
  2. encoding:指定當前文件的編碼。可選屬性,預設值是utf-8;

注意事項:

  1. 文件宣告必須為<?xml開頭,以?>結束;
  2. 文件宣告必須從文件的0行0列位置開始;
  3. 文件宣告只有2個屬性:

組成部分:元素

元素 element

<bean></bean>

注意事項:

  1. 元素是XML文件中最重要的組成部分,
  2. 普通元素的結構開始標籤、元素體、結束標籤組成。例如:<hello>大家好</hello>
  3. 元素體:元素體可以是元素,也可以是文字,例如:<b><a>你好</a></b>
  4. 空元素:空元素只有開始標籤,而沒有結束標籤,但元素必須自己閉合,例如:<c/>
  5. 元素命名:
    • 區分大小寫
    • 不能使用空格,不能使用冒號:
    • 不建議以XML、xml、Xml開頭

格式化良好的XML文件,必須只有一個根元素。

組成部分:屬性

屬性 attribute

<bean id="" className="">

注意事項:

  1. 屬性是元素的一部分,它必須出現在元素的開始標籤中
  2. 屬性的定義格式:屬性名=屬性值,其中屬性值必須使用單引或雙引
  3. 一個元素可以有0~N個屬性,但一個元素中不能出現同名屬性
  4. 屬性名不能使用空格、冒號等特殊字元,且必須以字母開頭

組成部分:註釋

XML的註釋,以“<!--”開始,以“-->”結束。註釋內容會被XML解析器忽略!

組成部分:轉義字元

因為很多符號已經被XML文件結構所使用,所以在元素體或屬性值中想使用這些符號就必須使用轉義字元,例如:<”、“>”、“”、“”、“&

2.3-XML約束(瞭解)

2.3.1-什麼是XML約束

在XML技術裡,可以編寫一個文件來約束一個XML文件的書寫規範,這稱之為XML約束。
常見的xml約束:DTD、Schema

2.3.2-DTD約束

什麼是DTD

DTD(Document Type Definition),文件型別定義,用來約束XML文件。規定XML文件中元素的名稱,子元素的名稱及順序,元素的屬性等。

重點要求

開發中,我們很少自己編寫DTD約束文件,通常情況我們都是通過框架提供的DTD約束文件,編寫對應的XML文件。常見框架使用DTD約束有:SpringMVC、MyBatis等。

通過提供的DTD“bean.dtd”編寫XML。bean.dtd約束如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--
	DTD文件。
	模擬spring規範,如果開發人員需要在xml使用當前DTD約束,必須包括DOCTYPE。
	格式如下:
	<!DOCTYPE beans SYSTEM "bean.dtd">
-->
<!--約束xml中必須有一個根元素beans,beans元素內部可以巢狀bean元素和import元素,*表示可有可無-->
<!ELEMENT beans (bean*,import*) >
<!--bean元素中可有propert元素-->
<!ELEMENT bean (property*)>
<!--propert元素內部可以設定文字-->
<!ELEMENT property (#PCDATA)>
<!--import元素內部可以設定文字-->
<!ELEMENT import (#PCDATA)>
<!--bean元素必須有id和calssName屬性,且屬性值是文字-->
<!ATTLIST bean id CDATA #REQUIRED
			   className CDATA #REQUIRED
>
<!--property元素必須有name和value屬性,且屬性值是文字-->
<!ATTLIST property name CDATA #REQUIRED
				   value CDATA #REQUIRED
>
<!--import必須以文字方式匯入-->
<!ATTLIST import resource CDATA #REQUIRED>

案例實現

自定義xml實現符合上述bean.dtd約束

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans SYSTEM "bean.dtd">
<beans>
	<bean id="" className=""></bean>
	
	<bean id="" className="">
		<property name="" value=""></property>
		<property name="" value=""></property>
	</bean>
	
	<import resource=""></import>
	<import resource=""></import>

</beans>

2.3.3- Schema約束

什麼是Schema

  • Schema是新的XML文件約束;
  • Schema要比DTD強大很多,是DTD 替代者;
  • Schema本身也是XML文件,但Schema文件的副檔名為xsd,而不是xml;
  • Schema 功能更強大,資料型別更完善;
  • Schema 支援名稱空間;

重點要求

與DTD一樣,要求可以通過schema約束文件編寫xml文件。常見框架使用schema的有:Spring等

通過提供“bean-schema.xsd”編寫xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
	Schema例項文件。
	模擬spring規範,如果開發人員需要在xml使用當前Schema約束,必須包括指定名稱空間。
	格式如下:
	<beans xmlns="http://www.penglei666.com/bean"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.penglei666.com/bean bean-schema.xsd"
	>
-->
<schema xmlns="http://www.w3.org/2001/XMLSchema"
		targetNamespace="http://www.penglei666.com/bean"
		xmlns:xsd="http://www.w3.org/2001/XMLSchema"
		xmlns:tns="http://www.penglei666.com/bean"
		elementFormDefault="qualified">
	<!-- 宣告根標籤 -->
	<element name="beans">
		<complexType>
			<choice minOccurs="0" maxOccurs="unbounded">
				<element name="bean">
					<complexType>
						<sequence minOccurs="0" maxOccurs="unbounded">
							<element name="property">
								<complexType>
									<attribute name="name" use="required"></attribute>
									<attribute name="value" use="required"></attribute>
								</complexType>
							</element>
						</sequence>
						<attribute name="id" use="required"></attribute>
						<attribute name="className" use="required"></attribute>
					</complexType>
				</element>
				<element name="import">
					<complexType>
						<attribute name="resource" use="required"></attribute>
					</complexType>
				</element>
			</choice>
		</complexType>
	</element>
</schema>

案例實現

自定義xml符合Schema約束

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.penglei666.com/bean"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.penglei666.com/bean bean-schema.xsd"
>
	<bean id="" className=""></bean>
	<bean id="" className="">
		<property name="" value=""/>
		<property name="" value=""/>
	</bean>
	
	<import resource=""/>
	<import resource=""/>
</beans>

2.3.4-名稱空間

什麼是名稱空間

如果一個XML文件中使用多個Schema檔案,而這些Schema檔案中定義了相同名稱的元素時就會出現名字衝突。這就像一個Java檔案中使用了import java.util.和import java.sql.時,在使用Date類時,那麼就不明確Date是哪個包下的Date了。

總之名稱空間就是用來處理元素和屬性的名稱衝突問題,與Java中的包是同一用途。如果每個元素和屬性都有自己的名稱空間,那麼就不會出現名字衝突問題,就像是每個類都有自己所在的包一樣,那麼類名就不會出現衝突。

約束文件和xml關係

當W3C提出Schema約束規範時,就提供“官方約束文件”。我們通過官方文件,必須“自定義schema 約束文件”,開發中“自定義文件”由框架編寫者提供。我們提供“自定義文件”限定,編寫出自己的xml文件。

宣告名稱空間

預設名稱空間:<xxx xmlns=””>,使用<標籤>
顯式名稱空間:<xxx xmlns:別名=””>,使用<別名:標籤>

2.4-XML解析(重點)

2.4.1-什麼是XML解析

當將資料儲存在XML後,我們就希望通過程式獲得XML的內容。如果我們使用Java基礎所學習的IO知識是可以完成的,不過你需要非常繁瑣的操作才可以完成,且開發中會遇到不同問題(只讀、讀寫)。人們為不同問題提供不同的解析方式,並提交對應的解析器,方便開發人員操作XML。

2.4.2-常見的解析方式和解析器

開發中比較常見的解析方式有三種,如下:

DOM:要求解析器把整個XML文件裝載到記憶體,並解析成一個Document物件。

優點:元素與元素之間保留結構關係,故可以進行增刪改查操作。
缺點:XML文件過大,可能出現記憶體溢位顯現。

SAX:是一種速度更快,更有效的方法。它逐行掃描文件,一邊掃描一邊解析。並以事件驅動的方式進行具體解析,每執行一行,都將觸發對應的事件。(瞭解)

優點:處理速度快,可以處理大檔案
缺點:只能讀,逐行後將釋放資源。

PULL:Android內建的XML解析方式

類似SAX。(瞭解)

解析器:就是根據不同的解析方式提供的具體實現。有的解析器操作過於繁瑣,為了方便開發人員,有提供易於操作的解析開發包。

2.4.3-dom解析原理和結構模型

XML DOM 將整個XML文件載入到記憶體,生成一個DOM樹,並獲得一個Document物件,通過Document物件就可以對DOM進行操作。

DOM中的核心概念就是節點,在XML文件中的元素、屬性、文字等,在DOM中都是節點!

2.4.4-API使用

DOM4J是一個Java的XML API,具有效能優異、功能強大和極其易使用的特點,它的效能超過sun公司官方的dom技術,如今可以看到越來越多的Java軟體都在使用DOM4J來讀寫XML。

如果想要使用DOM4J,需要引入支援xpath的jar包 dom4j-1.6.1.jar

jar包下載連結:https://pan.baidu.com/s/1nW0gKK81D8UmBxmX3XlLIQ
提取碼:wt60

DOM4J必須使用核心類SaxReader載入xml文件獲得Document,通過Document物件獲得文件的根元素,然後就可以操作了。

SaxReader物件

read(…) 載入執行xml文件

Document物件

getRootElement() 獲得根元素

Element物件

elements(…) 獲得指定名稱的所有子元素。可以不指定名稱
element(…) 獲得指定名稱第一個子元素。可以不指定名稱
getName() 獲得當前元素的元素名
attributeValue(…) 獲得指定屬性名的屬性值
elementText(…) 獲得指定名稱子元素的文字值
getText() 獲得當前元素的文字內容

案例

編寫xml,beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="001" className="cn.it.demo.User">
        <property name="user" value="jacl"></property>
        <property name="user" value="rose"></property>
    </bean>

    <bean id="002" className="cn.it.demo.Admin">
        <property name="user" value="admin"></property>
        <property name="user" value="write"></property>
    </bean>
</beans>

java程式碼解析XML

public static void main(String[] args) throws Exception {
    SAXReader sax = new SAXReader();
    Document document = sax.read("beans.xml");

    Element elemRoot = document.getRootElement();
    List<Element>list = elemRoot.elements();
  
    for(Element element : list){
        String id =element.attributeValue("id");
        String className = element.attributeValue("className");
        System.out.println(id+""+className);

        List<Element>listElem = element.elements();
        for(Element elem : listElem){
            String name = elem.attributeValue("name");
            String value = elem.attributeValue("value");
            System.out.println(name+""+value);
        }
    }

2.5-Xpath解析XML(重點)

概述

  • XPath 是一門在 XML、html 文件中查詢資訊的語言。

  • XPath 是一個 W3C 標準,可通過W3CSchool文件查閱語法

由於DOM4J在解析XML時只能一層一層解析,所以當XML檔案層數過多時使用會很不方便,結合XPATH就可以直接獲取到某個元素

使用dom4j支援xpath具體操作

預設的情況下,dom4j不支援xpath,如果想要在dom4j裡面使用xpath,需要引入支援xpath的jar包 jaxen-1.1.6.jar

在dom4j裡面提供了兩個方法,用來支援xpath,擴充套件的API如下

List<Node> selectNodes("xpath表示式"),用來獲取多個節點
Node selectSingleNode("xpath表示式"),用來獲取一個節點

xpath表示式常用查詢形式

第一種:

/AAA/DDD/BBB: 表示一層一層的,AAA下面 DDD下面的BBB

第二種:

//BBB: 表示和這個名稱相同,表示只要名稱是BBB 都得到

第三種:

/*: 所有元素

第四種:

BBB[1]:表示第一個BBB元素
BBB[last()]:表示最後一個BBB元素

第五種:

//BBB[@id]: 表示只要BBB元素上面有id屬性 都得到

第六種:

//BBB[@id='b1'] 表示元素名稱是BBB,在BBB上面有id屬性,並且id的屬性值是b1

案例

編寫xml,student.xml

<?xml version="1.0" encoding="UTF-8" ?>
<students>
	<student number="stu_0001">
		<name id="it">
			<xing>張</xing>
			<ming>三</ming>
		</name>
		<age>18</age>
		<sex>male</sex>
	</student>
	<student number="stu_0002">
		<name>jack</name>
		<age>18</age>
		<sex>female</sex>
	</student>
</students>

Xpath解析

public static void main(String[] args) throws Exception {
        SAXReader saxReader=new SAXReader();
        String path = Demo4jXpath.class.getClassLoader().getResource("student.xml").getFile();
        File file = new File(path);
        Document document=saxReader.read(file);

        //4.結合xpath語法查詢
        //4.1查詢所有student標籤
        List<Node> nodes = document.selectNodes("//student");
        for (Node node : nodes) {
            System.out.println(node);
        }

        System.out.println("--------------------");

        //4.2查詢所有student標籤下的name標籤
       nodes = document.selectNodes("//student/name");
        for (Node node : nodes) {
            System.out.println(node);
        }

        System.out.println("--------------------");

        //4.3查詢student標籤下帶有id屬性的name標籤
        nodes = document.selectNodes("//student/name[@id]");
        for (Node node : nodes) {
            System.out.println(node);
        }
        System.out.println("--------------------");
        //4.4查詢student標籤下帶有id屬性的name標籤 並且id屬性值為itcast

        nodes = document.selectNodes("//student/name[@id='itcast']");
        for (Node node : nodes) {
            System.out.println(node);
        }
    }

第三章:綜合案例

3.1-B/S服務改進

網路程式設計中的BS伺服器案例中存在一個問題,我們在程式中將埠號寫死,如果要更換埠號只能修改原始碼。這樣程式的維護性非常的差。

解決辦法:將埠號寫在配置檔案(xml)中進行讀取,需要更換埠號可以直接修改配置檔案。

在src目錄下建立檔案server.xml:

<?xml version="1.0" encoding="utf-8"?>
<server>
    <port>8000</port>
</server>

讀取xml中的埠號:

public static void main(String[] args)throws Exception{
    SAXReader saxReader = new SAXReader();
    //獲取類的載入器
    ClassLoader classLoader = TCPServer.class.getClassLoader();
    //類載入器中獲取輸入流
    InputStream inputStream = classLoader.getResourceAsStream("server.xml");
    Document document = saxReader.read(inputStream);
    Element rootElement = document.getRootElement();
    //xpath表示式,獲取標籤port
    Node node = rootElement.selectSingleNode("//port");
    //節點物件強轉標籤物件
    Element portElement = (Element)node;
    //獲取埠號,轉成int型別
    int port = Integer.parseInt(portElement.getText());
    ServerSocket server = new ServerSocket(port);
    while(true){
        Socket socket = server.accept();
        //開啟執行緒
    }
}

3.2-DI操作

DI依賴注入,後面框架篇幅解釋。

反射 + XML解析

需求:

讀取xml檔案,建立Person物件併為屬性賦值

person.xml檔案如下:

<?xml version="1.0" encoding="UTF-8" ?>
<persons>
    <person className="com.it.domain.Person">
        <property name="name">李四</property>
        <property name="sex">男</property>
    </person>
</persons>

Person類

package com.it.domain;

import lombok.Data;

@Data
public class Person {
    private String name;
    private String sex;
}

實現

package com.itheima.di;

import com.it.domain.Person;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.List;

/**
 *  <person className="com.it.domain.Person">
         <property name="name">張三</property>
         <property name="address">北京市</property>
    </person>

   要求: DOM4j,讀取xml檔案
   className的屬性值 com.itheima.domain.Person 反射建立該類的物件
   讀取到name="name"  張三  反射呼叫 setName()方法儲存張三
   讀取到 name="address" 反射呼叫setAddress()儲存北京市

 Person person = new Person();
 person.setName("張三");
 person.setAddress("北京市");
 System.out.println(person);
 */
public class DiDemo {
    public static void main(String[] args) throws Exception{
        InputStream inputStream = DiDemo.class.getClassLoader().getResourceAsStream("person.xml");
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read(inputStream);
        //獲取根標籤
        Element rootElement = document.getRootElement();
        //獲取子標籤person
        List<Element> personElements = rootElement.elements();
        if(personElements != null && personElements.size() > 0){
            for(Element personElement : personElements){
               //personElement person標籤物件
                //獲取person標籤的屬性 className的值
                String className = personElement.attributeValue("className");
                //反射,將類加入記憶體
                Class c = Class.forName(className);
                //建立類物件
                Object object = c.newInstance();
                //獲取person標籤的子標籤 property
                List<Element> propertyElements = personElement.elements();
                if(propertyElements != null && propertyElements.size() > 0) {
                    for(Element propertyElement : propertyElements){
                        //propertyElement每個子標籤property
                        //取出property標籤的屬性name和他的標籤體文字
                        String name = propertyElement.attributeValue("name");//name
                        String text = propertyElement.getText();//張三
                        //反射獲取該成員變數的set方法,進行賦值
                        //name setName    address=setAddress
                        String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
                        Method method = c.getMethod(methodName,String.class);
                        method.invoke(object,text);
                    }
                }
                System.out.println(object);
            }
        }
    }
}