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"?>
- versioin:指定XML文件版本。必須屬性,因為我們不會選擇1.1,只會選擇1.0;
- encoding:指定當前文件的編碼。可選屬性,預設值是utf-8;
注意事項:
- 文件宣告必須為
<?xml開頭,以?>
結束; - 文件宣告必須從文件的0行0列位置開始;
- 文件宣告只有2個屬性:
組成部分:元素
元素 element
<bean></bean>
注意事項:
- 元素是XML文件中最重要的組成部分,
- 普通元素的結構開始標籤、元素體、結束標籤組成。例如:
<hello>大家好</hello>
- 元素體:元素體可以是元素,也可以是文字,例如:
<b><a>你好</a></b>
- 空元素:空元素只有開始標籤,而沒有結束標籤,但元素必須自己閉合,例如:
<c/>
- 元素命名:
- 區分大小寫
- 不能使用空格,不能使用冒號
:
- 不建議以XML、xml、Xml開頭
格式化良好的XML文件,必須只有一個根元素。
組成部分:屬性
屬性 attribute
<bean id="" className="">
注意事項:
- 屬性是元素的一部分,它必須出現在元素的開始標籤中
- 屬性的定義格式:屬性名=屬性值,其中屬性值必須使用單引或雙引
- 一個元素可以有0~N個屬性,但一個元素中不能出現同名屬性
- 屬性名不能使用空格、冒號等特殊字元,且必須以字母開頭
組成部分:註釋
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);
}
}
}
}