基礎加強02
-
- 1.xml
-
- 1.1概述【了解】
- 1.2标簽的規則【應用】
- 1.3文法規則【應用】
- 1.4xml解析【應用】
- 1.5DTD限制【了解】
- 1.6schema限制【了解】
- 1.7伺服器改進【應用】
- 2.枚舉
-
- 2.1概述【了解】
- 2.2定義格式【應用】
- 2.3枚舉的特點【了解】
- 2.4枚舉的方法【應用】
- 3.注解
-
- 3.1概述【了解】
- 3.2自定義注解【了解】
- 3.3元注解【了解】
- 3.4改寫伺服器【了解】
1.xml
1.1概述【了解】
-
網際網路聯盟(W3C)
網際網路聯盟(W3C)建立于1994年,又稱W3C理事會。1994年10月在麻省理工學院計算機科學實驗室成立。
建立者: Tim Berners-Lee (蒂姆·伯納斯·李)。
是Web技術領域最具權威和影響力的國際中立性技術标準機構。
到目前為止,W3C已釋出了200多項影響深遠的Web技術标準及實施指南,
- 如廣為業界采用的超文本标記語言HTML(标準通用标記語言下的一個應用)、
- 可擴充标記語言XML(标準通用标記語言下的一個子集)
- 以及幫助殘障人士有效獲得Web資訊的無障礙指南(WCAG)等
-
xml概述
XML的全稱為(EXtensible Markup Language),是一種可擴充的标記語言
标記語言: 通過标簽來描述資料的一門語言(标簽有時我們也将其稱之為元素)
可擴充:标簽的名字是可以自定義的,XML檔案是由很多标簽組成的,而标簽名是可以自定義的
- 作用
- 用于進行存儲資料和傳輸資料
- 作為軟體的配置檔案
- 作為配置檔案的優勢
- 可讀性好
- 可維護性高
1.2标簽的規則【應用】
- 标簽由一對尖括号和合法辨別符組成
- 标簽必須成對出現
<student> </student> 前邊的是開始标簽,後邊的是結束标簽
- 特殊的标簽可以不成對,但是必須有結束标記
- 标簽中可以定義屬性,屬性和标簽名空格隔開,屬性值必須用引号引起來
- 标簽需要正确的嵌套
這是正确的: <student id="1"> <name>張三</name> </student> 這是錯誤的: <student id="1"><name>張三</student></name>
1.3文法規則【應用】
- 文法規則
- XML檔案的字尾名為:xml
-
文檔聲明必須是第一行第一列
<?xml version="1.0" encoding="UTF-8" standalone="yes”?>
version:該屬性是必須存在的
encoding:該屬性不是必須的
打開目前xml檔案的時候應該是使用什麼字元編碼表(一般取值都是UTF-8)
standalone: 該屬性不是必須的,描述XML檔案是否依賴其他的xml檔案,取值為yes/no
- 必須存在一個根标簽,有且隻能有一個
- XML檔案中可以定義注釋資訊
- XML檔案中可以存在以下特殊字元
< < 小于 > > 大于 & & 和号 ' ' 單引号 " " 引号
-
XML檔案中可以存在CDATA區
<![CDATA[ …内容… ]]>
- 示例代碼
<?xml version="1.0" encoding="UTF-8" ?> <!--注釋的内容--> <!--本xml檔案用來描述多個學生資訊--> <students> <!--第一個學生資訊--> <student id="1"> <name>張三</name> <age>23</age> <info>學生< >>>>>>>>>>>的資訊</info> <message> <![CDATA[内容 <<<<<< >>>>>> ]]]></message> </student> <!--第二個學生資訊--> <student id="2"> <name>李四</name> <age>24</age> </student> </students>
1.4xml解析【應用】
-
概述
xml解析就是從xml中擷取到資料
-
常見的解析思想
DOM(Document Object Model)文檔對象模型:就是把文檔的各個組成部分看做成對應的對象。
會把xml檔案全部加載到記憶體,在記憶體中形成一個樹形結構,再擷取對應的值
- 常見的解析工具
- JAXP: SUN公司提供的一套XML的解析的API
- JDOM: 開源組織提供了一套XML的解析的API-jdom
- DOM4J: 開源組織提供了一套XML的解析的API-dom4j,全稱:Dom For Java
- pull: 主要應用在Android手機端解析XML
- 解析的準備工作
-
我們可以通過網站:https://dom4j.github.io/ 去下載下傳dom4j
今天的資料中已經提供,我們不用再單獨下載下傳了,直接使用即可
- 将提供好的dom4j-1.6.1.zip解壓,找到裡面的dom4j-1.6.1.jar
- 在idea中目前子產品下建立一個libs檔案夾,将jar包複制到檔案夾中
- 選中jar包 -> 右鍵 -> 選擇add as library即可
-
- 需求
- 解析提供好的xml檔案
- 将解析到的資料封裝到學生對象中
- 并将學生對象存儲到ArrayList集合中
- 周遊集合
- 代碼實作
<?xml version="1.0" encoding="UTF-8" ?> <!--注釋的内容--> <!--本xml檔案用來描述多個學生資訊--> <students> <!--第一個學生資訊--> <student id="1"> <name>張三</name> <age>23</age> </student> <!--第二個學生資訊--> <student id="2"> <name>李四</name> <age>24</age> </student> </students> // 上邊是已經準備好的student.xml檔案 public class Student { private String id; private String name; private int age; public Student() { } public Student(String id, String name, int age) { this.id = id; this.name = name; this.age = age; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", age=" + age + '}'; } } /** * 利用dom4j解析xml檔案 */ public class XmlParse { public static void main(String[] args) throws DocumentException { //1.擷取一個解析器對象 SAXReader saxReader = new SAXReader(); //2.利用解析器把xml檔案加載到記憶體中,并傳回一個文檔對象 Document document = saxReader.read(new File("myxml\\xml\\student.xml")); //3.擷取到根标簽 Element rootElement = document.getRootElement(); //4.通過根标簽來擷取student标簽 //elements():可以擷取調用者所有的子标簽.會把這些子标簽放到一個集合中傳回. //elements("标簽名"):可以擷取調用者所有的指定的子标簽,會把這些子标簽放到一個集合中并傳回 //List list = rootElement.elements(); List<Element> studentElements = rootElement.elements("student"); //System.out.println(list.size()); //用來裝學生對象 ArrayList<Student> list = new ArrayList<>(); //5.周遊集合,得到每一個student标簽 for (Element element : studentElements) { //element依次表示每一個student标簽 //擷取id這個屬性 Attribute attribute = element.attribute("id"); //擷取id的屬性值 String id = attribute.getValue(); //擷取name标簽 //element("标簽名"):擷取調用者指定的子标簽 Element nameElement = element.element("name"); //擷取這個标簽的标簽體内容 String name = nameElement.getText(); //擷取age标簽 Element ageElement = element.element("age"); //擷取age标簽的标簽體内容 String age = ageElement.getText(); // System.out.println(id); // System.out.println(name); // System.out.println(age); Student s = new Student(id,name,Integer.parseInt(age)); list.add(s); } //周遊操作 for (Student student : list) { System.out.println(student); } } }
1.5DTD限制【了解】
-
什麼是限制
用來限定xml檔案中可使用的标簽以及屬性
- 限制的分類
- DTD
- schema
- 編寫DTD限制
- 步驟
- 建立一個檔案,這個檔案的字尾名為.dtd
-
看xml檔案中使用了哪些元素
<!ELEMENT> 可以定義元素
-
判斷元素是簡單元素還是複雜元素
簡單元素:沒有子元素。
複雜元素:有子元素的元素;
- 代碼實作
<!ELEMENT persons (person)> <!ELEMENT person (name,age)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)>
- 步驟
- 引入DTD限制
- 引入DTD限制的三種方法
- 引入本地dtd
- 在xml檔案内部引入
- 引入網絡dtd
- 代碼實作
- 引入本地DTD限制
// 這是persondtd.dtd檔案中的内容,已經提前寫好 <!ELEMENT persons (person)> <!ELEMENT person (name,age)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> // 在person1.xml檔案中引入persondtd.dtd限制 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE persons SYSTEM 'persondtd.dtd'> <persons> <person> <name>張三</name> <age>23</age> </person> </persons>
- 在xml檔案内部引入
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE persons [ <!ELEMENT persons (person)> <!ELEMENT person (name,age)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> ]> <persons> <person> <name>張三</name> <age>23</age> </person> </persons>
- 引入網絡dtd
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE persons PUBLIC "dtd檔案的名稱" "dtd文檔的URL"> <persons> <person> <name>張三</name> <age>23</age> </person> </persons>
- 引入本地DTD限制
- 引入DTD限制的三種方法
- DTD文法
-
定義元素
定義一個元素的格式為:<!ELEMENT 元素名 元素類型>
簡單元素:
EMPTY: 表示标簽體為空
ANY: 表示标簽體可以為空也可以不為空
PCDATA: 表示該元素的内容部分為字元串
複雜元素:
直接寫子元素名稱. 多個子元素可以使用",“或者”|"隔開;
","表示定義子元素的順序 ; “|”: 表示子元素隻能出現任意一個
"?"零次或一次, "+"一次或多次, "*"零次或多次;如果不寫則表示出現一次
-
定義屬性
格式
定義一個屬性的格式為:<!ATTLIST 元素名稱 屬性名稱 屬性的類型 屬性的限制>
屬性的類型:
CDATA類型:普通的字元串
屬性的限制:
// #REQUIRED: 必須的
// #IMPLIED: 屬性不是必需的
// #FIXED value:屬性值是固定的
- 代碼實作
<!ELEMENT persons (person+)> <!ELEMENT person (name,age)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ATTLIST person id CDATA #REQUIRED> <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE persons SYSTEM 'persondtd.dtd'> <persons> <person id="001"> <name>張三</name> <age>23</age> </person> <person id = "002"> <name>張三</name> <age>23</age> </person> </persons> ```
-
1.6schema限制【了解】
- schema和dtd的差別
- schema限制檔案也是一個xml檔案,符合xml的文法,這個檔案的字尾名.xsd
- 一個xml中可以引用多個schema限制檔案,多個schema使用名稱空間區分(名稱空間類似于java包名)
- dtd裡面元素類型的取值比較單一常見的是PCDATA類型,但是在schema裡面可以支援很多個資料類型
- schema 文法更加的複雜
- 編寫schema限制
-
步驟
1,建立一個檔案,這個檔案的字尾名為.xsd。
2,定義文檔聲明
3,schema檔案的根标簽為:
4,在中定義屬性:
xmlns=http://www.w3.org/2001/XMLSchema
5,在中定義屬性 :
targetNamespace =唯一的url位址,指定目前這個schema檔案的名稱空間。
6,在中定義屬性 :
elementFormDefault="qualified“,表示目前schema檔案是一個品質良好的檔案。
7,通過element定義元素
8,判斷目前元素是簡單元素還是複雜元素
- 代碼實作
<?xml version="1.0" encoding="UTF-8" ?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itheima.cn/javase" elementFormDefault="qualified" > <!--定義persons複雜元素--> <element name="persons"> <complexType> <sequence> <!--定義person複雜元素--> <element name = "person"> <complexType> <sequence> <!--定義name和age簡單元素--> <element name = "name" type = "string"></element> <element name = "age" type = "string"></element> </sequence> </complexType> </element> </sequence> </complexType> </element> </schema>
-
- 引入schema限制
-
步驟
1,在根标簽上定義屬性xmlns=“http://www.w3.org/2001/XMLSchema-instance”
2,通過xmlns引入限制檔案的名稱空間
3,給某一個xmlns屬性添加一個辨別,用于區分不同的名稱空間
格式為: xmlns:辨別=“名稱空間位址” ,辨別可以是任意的,但是一般取值都是xsi
4,通過xsi:schemaLocation指定名稱空間所對應的限制檔案路徑
格式為:xsi:schemaLocation = "名稱空間url 檔案路徑“
- 代碼實作
<?xml version="1.0" encoding="UTF-8" ?> <persons xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.itheima.cn/javase" xsi:schemaLocation="http://www.itheima.cn/javase person.xsd" > <person> <name>張三</name> <age>23</age> </person> </persons> ```
-
- schema限制定義屬性
- 代碼示例
<?xml version="1.0" encoding="UTF-8" ?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.itheima.cn/javase" elementFormDefault="qualified" > <!--定義persons複雜元素--> <element name="persons"> <complexType> <sequence> <!--定義person複雜元素--> <element name = "person"> <complexType> <sequence> <!--定義name和age簡單元素--> <element name = "name" type = "string"></element> <element name = "age" type = "string"></element> </sequence> <!--定義屬性,required( 必須的)/optional( 可選的)--> <attribute name="id" type="string" use="required"></attribute> </complexType> </element> </sequence> </complexType> </element> </schema> <?xml version="1.0" encoding="UTF-8" ?> <persons xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.itheima.cn/javase" xsi:schemaLocation="http://www.itheima.cn/javase person.xsd" > <person id="001"> <name>張三</name> <age>23</age> </person> </persons> ```
- 代碼示例
1.7伺服器改進【應用】
- 準備xml檔案
- 在目前子產品下的webapp目錄下建立一個檔案夾,名字叫WEB-INF
- 建立一個xml檔案,名字叫web.xml
- 将資料中的web.xml檔案中引入限制的代碼複制到建立的web.xml檔案中
- 将要解析的資料配置到xml檔案中
-
需求
把uri和servlet資訊放到一個concurrentHashMap集合當中
當浏覽器請求一個動态資源時,我們會擷取uri對應的servlet來處理目前業務
- 實作步驟
- 導入dom4j的jar包
- 定義一個XmlParseServletConfig類實作ParseServletConfig接口
- 在parse方法裡面就可以解析xml檔案了
- 代碼實作
// web.xml配置檔案中配置的資訊 <?xml version="1.0" encoding="UTF-8" ?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!--在以後需要配置servlet的時候,就直接在這裡配置就可以了--> <servlet> <servlet-name>LoginServlet</servlet-name> <servlet-class>com.itheima.myservlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginServlet</servlet-name> <url-pattern>/servlet/loginservlet</url-pattern> </servlet-mapping> </web-app> // 定義一個XmlParseServletConfig類實作ParseServletConfig接口 public class XMLParseServletConfig implements ParseServletConfig { //定義web.xml檔案的路徑 private static final String WEB_XML_PATH = "http-dynamic-server/webapp/WEB-INF/web.xml"; //在parse方法裡面就可以解析xml檔案了 @Override public void parse() { try { //1.建立一個解析器對象(注意:如果解析器對象等不能使用,請檢查一下jar包是否導入) SAXReader saxReader = new SAXReader(); //2.利用解析器把xml檔案讀取到記憶體中 Document document = saxReader.read(new File(WEB_XML_PATH)); //3.擷取根節點元素對象 Element rootElement = document.getRootElement(); //建立一個Map集合,用來存儲servlet的配置資訊 HashMap<String,String> servletInfoHashMap = new HashMap<>(); //4.擷取根元素對象下所有的servlet元素的對象 List<Element> servletInfos = rootElement.elements("servlet"); //5.周遊集合,依次擷取到每一個servlet标簽對象 for (Element servletInfo : servletInfos) { //servletInfo依次表示每一個servlet标簽對象 //擷取到servlet下的servlet-name元素對象,并且擷取标簽體内容 String servletName = servletInfo.element("servlet-name").getText(); //擷取到servlet下的servlet-class元素對象,并且擷取标簽體内容 String servletClass = servletInfo.element("servlet-class").getText(); servletInfoHashMap.put(servletName,servletClass); } //--------------------servlet-mapping-------------------------------------- //擷取到所有的servlet-mapping标簽 List<Element> servletMappingInfos = rootElement.elements("servlet-mapping"); //周遊集合依次得到每一個servlet-mapping标簽 for (Element servletMappingInfo : servletMappingInfos) { //servletMappingInfo依次表示每一個servlet-mapping标簽 //擷取servlet-mapping标簽标簽中的servlet-name标簽的标簽體内容 String servletName = servletMappingInfo.element("servlet-name").getText(); //擷取servlet-mapping标簽标簽中的url-pattern标簽的标簽體内容 String urlPattern = servletMappingInfo.element("url-pattern").getText(); //通過servletName來擷取到servlet的全類名 String servletClassName = servletInfoHashMap.get(servletName); //通過反射來建立這個servlet對象 Class clazz = Class.forName(servletClassName); //擷取該類所實作的所有的接口資訊,得到的是一個數組 Class[] interfaces = clazz.getInterfaces(); //定義一個boolean類型的變量 boolean flag = false; //周遊數組 for (Class clazzInfo : interfaces) { //判斷目前所周遊的接口的位元組碼對象是否和HttpServlet的位元組碼檔案對象相同 if(clazzInfo == HttpServlet.class){ //如果相同,就需要更改flag值.結束循環 flag = true; break; } } if(flag){ //true就表示目前的類已經實作了HttpServlet接口 HttpServlet httpServlet = (HttpServlet) clazz.newInstance(); //4.将uri和httpServlet添加到map集合中 ServletConcurrentHashMap.map.put(urlPattern,httpServlet); }else{ //false就表示目前的類還沒有實作HttpServlet接口 throw new NotImplementsHttpServletException(clazz.getName() + "Not Implements HttpServlet"); } } } catch (NotImplementsHttpServletException e) { e.printStackTrace(); }catch (Exception e) { e.printStackTrace(); } } } public class LoaderResourceRunnable implements Runnable { @Override public void run() { // //執行parse方法 // ParseServletConfig parseServletConfig = new PropertiesParseServletConfig(); // parseServletConfig.parse(); ParseServletConfig parseServletConfig = new XMLParseServletConfig(); parseServletConfig.parse(); } }
2.枚舉
2.1概述【了解】
為了間接的表示一些固定的值,Java就給我們提供了枚舉
是指将變量的值一一列出來,變量的值隻限于列舉出來的值的範圍内
2.2定義格式【應用】
- 格式
public enum s { 枚舉項1,枚舉項2,枚舉項3; } 注意: 定義枚舉類要用關鍵字enum
- 示例代碼
// 定義一個枚舉類,用來表示春,夏,秋,冬這四個固定值 public enum Season { SPRING,SUMMER,AUTUMN,WINTER; }
2.3枚舉的特點【了解】
- 特點
- 所有枚舉類都是Enum的子類
- 我們可以通過"枚舉類名.枚舉項名稱"去通路指定的枚舉項
- 每一個枚舉項其實就是該枚舉的一個對象
- 枚舉也是一個類,也可以去定義成員變量
- 枚舉類的第一行上必須是枚舉項,最後一個枚舉項後的分号是可以省略的,但是如果枚舉類有其他的東西,這個分号就不能省略。建議不要省略
-
枚舉類可以有構造器,但必須是private的,它預設的也是private的。
枚舉項的用法比較特殊:枚舉("");
- 枚舉類也可以有抽象方法,但是枚舉項必須重寫該方法
- 示例代碼
public enum Season { SPRING("春"){ //如果枚舉類中有抽象方法 //那麼在枚舉項中必須要全部重寫 @Override public void show() { System.out.println(this.name); } }, SUMMER("夏"){ @Override public void show() { System.out.println(this.name); } }, AUTUMN("秋"){ @Override public void show() { System.out.println(this.name); } }, WINTER("冬"){ @Override public void show() { System.out.println(this.name); } }; public String name; //空參構造 //private Season(){} //有參構造 private Season(String name){ this.name = name; } //抽象方法 public abstract void show(); } public class EnumDemo { public static void main(String[] args) { /* 1.所有枚舉類都是Enum的子類 2.我們可以通過"枚舉類名.枚舉項名稱"去通路指定的枚舉項 3.每一個枚舉項其實就是該枚舉的一個對象 4.枚舉也是一個類,也可以去定義成員變量 5.枚舉類的第一行上必須是枚舉項,最後一個枚舉項後的分号是可以省略的, 但是如果枚舉類有其他的東西,這個分号就不能省略。建議不要省略 6.枚舉類可以有構造器,但必須是private的,它預設的也是private的。 枚舉項的用法比較特殊:枚舉(""); 7.枚舉類也可以有抽象方法,但是枚舉項必須重寫該方法 */ //第二個特點的示範 //我們可以通過"枚舉類名.枚舉項名稱"去通路指定的枚舉項 System.out.println(Season.SPRING); System.out.println(Season.SUMMER); System.out.println(Season.AUTUMN); System.out.println(Season.WINTER); //第三個特點的示範 //每一個枚舉項其實就是該枚舉的一個對象 Season spring = Season.SPRING; } }
2.4枚舉的方法【應用】
- 方法介紹
方法名 說明 String name() 擷取枚舉項的名稱 int ordinal() 傳回枚舉項在枚舉類中的索引值 int compareTo(E o) 比較兩個枚舉項,傳回的是索引值的內插補點 String toString() 傳回枚舉常量的名稱 static T valueOf(Class type,String name) 擷取指定枚舉類中的指定名稱的枚舉值 values() 獲得所有的枚舉項 - 示例代碼
public enum Season { SPRING,SUMMER,AUTUMN,WINTER; } public class EnumDemo { public static void main(String[] args) { // String name() 擷取枚舉項的名稱 String name = Season.SPRING.name(); System.out.println(name); System.out.println("-----------------------------"); // int ordinal() 傳回枚舉項在枚舉類中的索引值 int index1 = Season.SPRING.ordinal(); int index2 = Season.SUMMER.ordinal(); int index3 = Season.AUTUMN.ordinal(); int index4 = Season.WINTER.ordinal(); System.out.println(index1); System.out.println(index2); System.out.println(index3); System.out.println(index4); System.out.println("-----------------------------"); // int compareTo(E o) 比較兩個枚舉項,傳回的是索引值的內插補點 int result = Season.SPRING.compareTo(Season.WINTER); System.out.println(result);//-3 System.out.println("-----------------------------"); // String toString() 傳回枚舉常量的名稱 String s = Season.SPRING.toString(); System.out.println(s); System.out.println("-----------------------------"); // static <T> T valueOf(Class<T> type,String name) // 擷取指定枚舉類中的指定名稱的枚舉值 Season spring = Enum.valueOf(Season.class, "SPRING"); System.out.println(spring); System.out.println(Season.SPRING == spring); System.out.println("-----------------------------"); // values() 獲得所有的枚舉項 Season[] values = Season.values(); for (Season value : values) { System.out.println(value); } } }
3.注解
3.1概述【了解】
-
概述
對我們的程式進行标注和解釋
- 注解和注釋的差別
- 注釋: 給程式員看的
- 注解: 給編譯器看的
-
使用注解進行配置配置的優勢
代碼更加簡潔,友善
3.2自定義注解【了解】
-
格式
public @interface 注解名稱 {
public 屬性類型 屬性名() default 預設值 ;
}
- 屬性類型
- 基本資料類型
- String
- Class
- 注解
- 枚舉
- 以上類型的一維數組
- 代碼示範
public @interface Anno2 { } public enum Season { SPRING,SUMMER,AUTUMN,WINTER; } public @interface Anno1 { //定義一個基本類型的屬性 int a () default 23; //定義一個String類型的屬性 public String name() default "itheima"; //定義一個Class類型的屬性 public Class clazz() default Anno2.class; //定義一個注解類型的屬性 public Anno2 anno() default @Anno2; //定義一個枚舉類型的屬性 public Season season() default Season.SPRING; //以上類型的一維數組 //int數組 public int[] arr() default {1,2,3,4,5}; //枚舉數組 public Season[] seasons() default {Season.SPRING,Season.SUMMER}; //value。後期我們在使用注解的時候,如果我們隻需要給注解的value屬性指派。 //那麼value就可以省略 public String value(); } //在使用注解的時候如果注解裡面的屬性沒有指定預設值。 //那麼我們就需要手動給出注解屬性的設定值。 //@Anno1(name = "itheima") @Anno1("abc") public class AnnoDemo { }
-
注意
如果隻有一個屬性需要指派,并且屬性的名稱是value,則value可以省略,直接定義值即可
- 自定義注解案例
-
需求
自定義一個注解@Test,用于指定類的方法上,如果某一個類的方法上使用了該注解,就執行該方法
- 實作步驟
- 自定義一個注解Test,并在類中的某幾個方法上加上注解
- 在測試類中,擷取注解所在的類的Class對象
- 擷取類中所有的方法對象
- 周遊每一個方法對象,判斷是否有對應的注解
- 代碼實作
//表示Test這個注解的存活時間 @Retention(value = RetentionPolicy.RUNTIME) public @interface Test { } public class UseTest { //沒有使用Test注解 public void show(){ System.out.println("UseTest....show...."); } //使用Test注解 @Test public void method(){ System.out.println("UseTest....method...."); } //沒有使用Test注解 @Test public void function(){ System.out.println("UseTest....function...."); } } public class AnnoDemo { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException { //1.通過反射擷取UseTest類的位元組碼檔案對象 Class clazz = Class.forName("com.itheima.myanno3.UseTest"); //建立對象 UseTest useTest = (UseTest) clazz.newInstance(); //2.通過反射擷取這個類裡面所有的方法對象 Method[] methods = clazz.getDeclaredMethods(); //3.周遊數組,得到每一個方法對象 for (Method method : methods) { //method依次表示每一個方法對象。 //isAnnotationPresent(Class<? extends Annotation> annotationClass) //判斷目前方法上是否有指定的注解。 //參數:注解的位元組碼檔案對象 //傳回值:布爾結果。 true 存在 false 不存在 if(method.isAnnotationPresent(Test.class)){ method.invoke(useTest); } } } }
-
3.3元注解【了解】
-
概述
元注解就是描述注解的注解
- 元注解介紹
元注解名 說明 @Target 指定了注解能在哪裡使用 @Retention 可以了解為保留時間(生命周期) @Inherited 表示修飾的自定義注解可以被子類繼承 @Documented 表示該自定義注解,會出現在API文檔裡面。 - 示例代碼
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD}) //指定注解使用的位置(成員變量,類,方法) @Retention(RetentionPolicy.RUNTIME) //指定該注解的存活時間 //@Inherited //指定該注解可以被繼承 public @interface Anno { } @Anno public class Person { } public class Student extends Person { public void show(){ System.out.println("student.......show.........."); } } public class StudentDemo { public static void main(String[] args) throws ClassNotFoundException { //擷取到Student類的位元組碼檔案對象 Class clazz = Class.forName("com.itheima.myanno4.Student"); //擷取注解。 boolean result = clazz.isAnnotationPresent(Anno.class); System.out.println(result); } }
3.4改寫伺服器【了解】
-
需求
目前項目中Servlet和url對應關系,是配置在xml檔案中的,将其改為在Servlet類上通過注解配置實作
- 實作步驟
- 定義一個注解(@WebServlet),注解内有一個屬性urlPatterns
- 在servlet類上去使用該注解,來指定目前Servlet的通路路徑
- 建立一個注解解析類(AnnoParseServletConfig),該類實作ParseServletConfig接口
- 實作parse方法
- 代碼實作
@Target(ElementType.TYPE) //指定該注解可以使用在類上 @Retention(RetentionPolicy.RUNTIME)//指定該注解的存活時間 --- 為運作期 public @interface WebServlet { //讓使用者去指定某一個Servlet在進行通路的時候所對應的請求uri public String urlPatterns(); } // 這裡隻給出了LoginServlet的配置,其他Servlet同理 @WebServlet(urlPatterns = "/servlet/loginservlet") public class LoginServlet implements HttpServlet{ @Override public void service(HttpRequest httpRequest, HttpResponse httpResponse) { //處理 System.out.println("LoginServlet處理了登入請求"); //響應 httpResponse.setContentTpye("text/html;charset=UTF-8"); httpResponse.write("登入成功"); } } public class AnnoParseServletConfig implements ParseServletConfig { //定義一個servlet路徑所對應的常量 public static final String SERVLET_PATH = "http-dynamic-server\\src\\com\\itheima\\myservlet"; //定義包名 public static final String SERVLET_PACKAGE_NAME = "com.itheima.myservlet."; @Override public void parse() { //擷取類名 // 1.獲得servlet所在檔案夾的路徑,并封裝成File對象 File file = new File(SERVLET_PATH); // 2.調用listFiles方法,擷取檔案夾下所有的File對象 File[] servletFiles = file.listFiles(); // 3.周遊數組,擷取每一個File對象 for (File servletFile : servletFiles) { // 4.擷取File對象的名字(字尾名) String servletFileName = servletFile.getName().replace(".java", ""); // 5.根據包名 + 類名 得到每一個類的全類名 String servletFullName = SERVLET_PACKAGE_NAME + servletFileName; try { // 6.通過全類名擷取位元組碼檔案對象 Class servletClazz = Class.forName(servletFullName); // 7.判斷該類是否有WebServlet注解 if(servletClazz.isAnnotationPresent(WebServlet.class)){ // 8.判斷該Servlet類是否實作HttpServlet接口 //擷取該類所實作的所有的接口資訊,得到的是一個數組 Class[] interfaces = servletClazz.getInterfaces(); //定義一個boolean類型的變量 boolean flag = false; //周遊數組 for (Class clazzInfo : interfaces) { //判斷目前所周遊的接口的位元組碼對象是否和HttpServlet的位元組碼檔案對象相同 if(clazzInfo == HttpServlet.class){ //如果相同,就需要更改flag值.結束循環 flag = true; break; } } if(flag){ // 9.如果滿足,則擷取注解中的urlPattrens的值, WebServlet annotation = (WebServlet) servletClazz.getAnnotation(WebServlet.class); String uri = annotation.urlPatterns(); // 10.建立目前Servlet類對象存入值位置 HttpServlet httpServlet = (HttpServlet) servletClazz.newInstance(); // 11.存入集合的鍵位置 ServletConcurrentHashMap.map.put(uri,httpServlet); // }else{ // 12.如果不滿足,抛出異常 //false就表示目前的類還沒有實作HttpServlet接口 throw new NotImplementsHttpServletException(servletClazz.getName() + "Not Implements HttpServlet"); } } } catch (NotImplementsHttpServletException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } } public class LoaderResourceRunnable implements Runnable { @Override public void run() { // //執行parse方法 // ParseServletConfig parseServletConfig = new PropertiesParseServletConfig(); // parseServletConfig.parse(); // ParseServletConfig parseServletConfig = new XMLParseServletConfig(); // parseServletConfig.parse(); ParseServletConfig parseServletConfig = new AnnoParseServletConfig(); parseServletConfig.parse(); } }