XML 1.什么是XML? XML:extensiable markup language 被称作可扩展标记语言。 XML简单的历史介绍: gml-」sgml-」html-」xml gml(通用

XML
1.什么是XML?
XML:extensiable markup language 被称作可扩展标记语言。
XML简单的历史介绍:
gml->sgml->html->xml
gml(通用标记语言)–在不同的机器进行通信的数据规范
sgml(标准通用标记语言)
html(超文本标记语言)
2.XML的用途
(1)配置文件
例子:Tomcat的web.xml,server.xml……,XML能够非常清晰描述出程序之间的关系。
(2)程序间数据的传输
XML的格式是通用的,能够减少交换数据时的复杂性。
(3)充当小型数据库
如果我们的数据有时候需要人工配置的,那么XML充当小型的数据库是个不错的选择,程序直接读取XML文件显然要比读取数据库要快。

HTML与表妹XML的区别?
XML 不是 HTML 的替代,XML 和 HTML 为不同的目的而设计:
XML 被设计为传输和存储数据,其焦点是数据的内容。
HTML 被设计用来显示数据,其焦点是数据的外观。
HTML 旨在显示信息,而 XML 旨在传输信息。
3.XML的技术架构
XML被设计为“什么都不做”,XML数据或XML文档只用于组织、存储数据,除此之外的数据生成、读取、传送、存取等等操作都与XML本身无关!
于是乎,想要操作XML,就需要用到XML之外的技术了:
为XML定规则:现在一般使用DTD或Schema技术,当然了Schema技术更为先进!
解析XML的数据:一般使用DOM或者SAX技术,各有各的优点
提供样式:XML一般用来存储数据的,但设计者野心很大,也想用来显示数据(但没人用XML来显示数据),就有了XSLT(eXtensiable Stylesheet Language Transformation)可扩展样式转换语言

4.XML语法
4.1.基本语法
(1)xml文档的后缀名 .xml
(2)xml第一行必须定义为文档声明
(3)xml文档中有且仅有一个根标签
(4)属性值必须使用引号(单双都可)引起来
(5)标签必须正确关闭
(6)xml标签名称区分大小写
4.2.快速入门

<?xml version="1.0" encoding="utf-8"?> 张三 18 男 李四 18 女 4.3.组成部分 XML文档形成了一种“树结构”,它从“根部”开始,然后扩展到“枝叶”。 XML主要组成部分有: (1)文档声明 (2)指令 (3)标签 (4)属性 (5)注释 (6)CDATA (7)转义字符

4.3.1.文档声明
(1)格式:<?xml 属性列表 ?>

<?xml version="1.0" encoding="utf-8" standalone="no"?>

version—版本号,必须的属性
encoding–编码方式。告知解析引擎当前文档使用的字符集,默认值ISO-8859-1
standalone–是否独立使用,默认是no。
如果是yes,则表示这个XML文档是独立的,不能引用外部的DTD规范文件(不依赖其他文件);
如果是no,则该XML文档不是独立的,表示可以引用外部的DTD规范文档(依赖其他文件)。
(2)XML声明放在XML的第一行
正确的文档声明格式,属性的位置不能改变!

4.3.2.指令(了解)
处理指令,简称PI(processing instruction)。
处理指令用来指挥解析引擎如何解析XML文档内容。
例如:
在XML文档中可以使用xml-stylesheet指令,通知XML解析引擎,应用css文件显示xml文档内容。

<?xml-stylesheet type="text/css" href="1.css"?>

XML代码:

<?xml version="1.0" encoding="UTF-8" ?> <?xml-stylesheet type="text/css" href="1.css"?> 广州 深圳

CSS代码:
guangzhou{
font-size: 40px;
}

4.3.3.标签
XML中元素和标签指的是同一个东西。
标签中需要值得注意的地方:
XML标签中的出现的空格和换行都会被当做标签内容进行处理
每个XML文档必须有且只有一个根标签
标签必须闭合
大小写敏感
不能交叉嵌套
不能以数字、符号开头
看起来好像有很多需要值得注意的地方,其实只需要记住:XML的语法是规范的!不要随意乱写!
标签命名规则:
名称可以包含字母、数字以及其他的字符
名称不能以数字或者标点符号开始
名称不能以字母 xml(或者 XML、Xml 等等)开始
名称不能包含空格

4.3.4.属性
属性是作为XML元素中的一部分的,命名规范也是和XML元素一样的!
(1)id属性值唯一
(2)属性值使用双引号

<中国 name=“china”></中国>

4.3.5.注释
注释和HTML的注释是一样的

4.3.6.CDATA
在编写XML文件时,有些内容可能不想让解析引擎解析执行,而是当作原始内容处理。遇到此种情况,可以把这些内容放在CDATA区里,对于CDATA区域内的内容,XML解析程序不会处理,而是直接原封不动的输出
语法:

<![CDATA[ ...内容 ]]>

4.3.7.转义字符
对于一些单个字符,若想显示其原始样式,也可以使用转义的形式予以处理。
转义符 符号
< <
> >
& &
" “
' ‘

5.XML文档约束
XML文档约束有两种:DTD和Schema。
5.1.DTD
DTD(Document Type Definition)——文档类型定义
作用:是定义XML文档的合法构建模块。
注:DTD就是个约束,用来约束XML的书写规范。
5.1.1.在XML中加入DTD声明
(1)内部声明: 即在XML文档中直接写约束。

(2)外部声明: 即引用外部DTD文件。

注:DTD约束外部文件的扩展名是.dtd。
5.1.2.DTD语法
(1)元素定义语法(即DTD对元素的限制)
基本语法:

<!ELEMENT 元素名称 元素类型>
		元素类型:
			EMPTY				表示该元素为空元素
			(#PCDATA)			表示只有PCDATA的元素,不做延伸,放具体的数据	
			(e1,e2,e3……)		表示该元素下带有子元素,分别是e1,e2,注意顺序
			ANY					表示没有任何内容的元素
			(元素名)			表示只出现一次的元素

元素限制:
, 顺序
| 或
* 0次或多次
+ 1次或多次
? 0次或1次

(2)属性定义语法(即DTD对属性的限制)
基本语法:
<!ATTLIST 元素名称 属性名称1 属性类型 设置说明 属性名称2 属性类型 设置说明 …… >

属性类型:
CDATA 表示属性值为字符串
(男|女) “男” 表示只能填男或女,默认男
ID 值为唯一的id
ENTITY 表示实体(自学)

设置说明:
#REQUIRED 必须设置该属性
#IMPLIED 可以设置也可不设置
#FIXED 说明该属性的取值固定为一个值,需多测试
“默认值”

5.1.3.DTD示例

<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT person (name,sex,age,contact,br?)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ELEMENT contact (phone|email)>
<!ELEMENT phone (#PCDATA)>
<!ELEMENT email (#PCDATA)>
<!ELEMENT br EMPTY>
<!ATTLIST person 
	pid	 	ID		#REQUIRED
	pname	CDATA	#IMPLIED
	psex	(男|女) "男"
>

]>

张三 男 22 13308082222
李四 女 23 1234@qq.com

5.2.Schema
Schema是DTD的替代者,可描述XML文档的结构,也可作为XSD(XML Schame Definition)来引用。
Schema比DTD更强大,其最重要的能力之一就是对数据类型的支持。

5.2.1.简单案例
note.xml代码:

<?xml version="1.0"?> George John Reminder Don't forget the meeting!

note.dtd代码:

<!ELEMENT note (to, from, heading, body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)>

note.xsd代码:

<?xml version="1.0"?>

<xs:schema xmlns:xs=“http://www.w3.org/2001/XMLSchema”
targetNamespace=“http://www.w3school.com.cn”
xmlns=“http://www.w3school.com.cn”
elementFormDefault=“qualified”>

<xs:element name=“note”>
xs:complexType
xs:sequence
<xs:element name=“to” type=“xs:string”/>
<xs:element name=“from” type=“xs:string”/>
<xs:element name=“heading” type=“xs:string”/>
<xs:element name=“body” type=“xs:string”/>
</xs:sequence>
</xs:complexType>
</xs:element>

</xs:schema>

5.2.2. 元素
元素是每一个 XML Schema 的根元素:

<?xml version="1.0"?>

xs:schema

</xs:schema>

元素可包含属性。一个 schema 声明往往看上去类似这样:

<?xml version="1.0"?>

<xs:schema xmlns:xs=“http://www.w3.org/2001/XMLSchema”
targetNamespace=“http://www.w3school.com.cn”
xmlns=“http://www.w3school.com.cn”
elementFormDefault=“qualified”>

</xs:schema>

代码解释:
下面的片断:
xmlns:xs=“http://www.w3.org/2001/XMLSchema”
显示 schema 中用到的元素和数据类型来自命名空间 “http://www.w3.org/2001/XMLSchema”。同时它还规定了来自命名空间 “http://www.w3.org/2001/XMLSchema” 的元素和数据类型应该使用前缀 xs:

这个片断:
targetNamespace=“http://www.w3school.com.cn”
显示被此 schema 定义的元素 (note, to, from, heading, body) 来自命名空间: “http://www.w3school.com.cn”。

这个片断:
xmlns=“http://www.w3school.com.cn”
指出默认的命名空间是 “http://www.w3school.com.cn”。

这个片断:
elementFormDefault=“qualified”
指出任何 XML 实例文档所使用的且在此 schema 中声明过的元素必须被命名空间限定。

5.3.对.dtd的引用

<?xml version="1.0"?>

5.4.对.xsd的引用

<?xml version="1.0"?>

<note
xmlns=“http://www.w3school.com.cn”
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation=“http://www.w3school.com.cn note.xsd”>

6.XML解析
XML解析就是操作xml文档,将文档中的数据读取到内存中。

6.1.操作XML文档
(1)解析(读取):将文档中的数据读取到内存中。
(2)写入:将内存中的数据保存到xml文档中。持久化的存储

6.2.XML解析方式
XML解析方式分为两种:
(1)DOM:Document Object Model文档对象模型
将标记语言文档一次性加载进内存,在内存中形成一颗dom树。
是W3C组织推荐解析XML的一种方式。
优点:操作方便,可以对文档进行CRUD的所有操作
缺点:占内存
(2)SAX:Simple API For XML
逐行读取,基于事件驱动的。它是XML社区的标准,几乎所有XML解析器都支持它。
优点:不占内存。
缺点:只能读取,不能增删改

6.3.常见解析器
(1)JAXP:sun公司提供的解析器,支持dom和sax两种思想。
(2)DOM4J:一款非常优秀的解析器。
(3)Jsoup:jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
(4)PULL:Android操作系统内置的解析器,sax方式的。

6.4.Jsoup
Jsoup 是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。

6.4.1.快读入门
操作步骤:
(1)导入jar包
jsoup-1.11.2.jar、JsoupXpath-0.3.2.jar
(2)获取Document对象
//获得路径
String path = XMLTest.class.getClassLoader().getResource(“student.xml”).getPath();
//获得Document对象
Document doc = Jsoup.parse(new File(path), “utf-8”);
(3)获取对应的标签Element对象
//获取元素
Elements elements = doc.getElementsByTag(“name”);
(4)获取数据
//获取数据
for (int i = 0; i < elements.size(); i++){
System.out.println(elements.get(i).text());
}

6.4.2.Jsoup对象的使用
(1)Jsoup:工具类,可以解析html或xml文档,返回Document。
parse:解析html或xml文档,返回Document
parse(File in, String charsetName):解析xml或html文件的。
parse(String html):解析xml或html字符串。
parse(URL url, int timeoutMillis):通过网络路径获取指定的html或xml的文档对象。

(2)Document:文档对象。代表内存中的dom树
获取Element对象方法:
getElementById(String id):根据id属性值获取唯一的element对象。
getElementsByTag(String tagName):根据标签名称获取元素对象集合。
getElementsByAttribute(String key):根据属性名称获取元素对象集合。
getElementsByAttributeValue(String key, String value):根据对应的属性名和属性值获取元素对象集合。

(3)Elements:元素Element对象的集合。可以当做 ArrayList来使用

(4)Element:元素对象
获取子元素对象方法:
getElementById(String id):根据id属性值获取唯一的element对象。
getElementsByTag(String tagName):根据标签名称获取元素对象集合。
getElementsByAttribute(String key):根据属性名称获取元素对象集合。
getElementsByAttributeValue(String key, String value):根据对应的属性名和属性值获取元素对象集合。

获取属性值的方法:
attr(String key):根据属性名称获取属性值

获取文本内容的方法:
text():获取文本内容
html():获取标签体的所有内容(包括字标签的字符串内容)

(5)Node:节点对象
Node是Document和Element的父类。

6.4.3.快捷查询方式
(1)selector:选择
使用的方法:
Elements select(String cssQuery)

参考代码:
//获得路径
path String path = JsoupTest.class.getClassLoader().getResource(“student.xml”).getPath();

//解析
Document document = Jsoup.parse(new File(path), “utf-8”);

//查询name标签
Elements elements = document.select(“name”); System.out.println(elements.get(0).text());

//查询id
Elements id = document.select("#cat"); System.out.println(elements.get(0).select(“name”).text());

//查找student中number等于heima_0001
Elements select = document.select(“student[number=“zhibang_0001”]”); System.out.println(select);

//查找student中number等于heima_0001中的age子标签
Elements select1 = document.select(“student[number=“zhibang_0001”]>age”); System.out.println(select1);

(2)XPath
说明:XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言。
使用Jsoup的Xpath需要额外导入jar包:JsoupXpath-0.3.2.jar

参考代码:
//获得路径path
String path = JsoupTest.class.getClassLoader().getResource(“student.xml”).getPath();
//解析
Document document = Jsoup.parse(new File(path), “utf-8”);

//创建JXDocumnet对象
JXDocument jxDocument=new JXDocument(document);

//结合xpath语法查询
List jxNodes = jxDocument.selN("//student");
System.out.println(jxNodes);
List jxNode = jxDocument.selN("//student[@number=‘zhibang_0001’]");
System.out.println(jxNode);

6.5.dom4j + xpath 解析xml文件
xml解析一般分自带源生态的(效率低) ,另一种使用第三方读取解析(dom4j)。

6.5.1.dom4j
dom4j是java中一个优秀的开源框架,它提供了一组API用来解析xml文件。

优点:开源、轻量级、灵活、高性能、高效率、易维护。
		常用于解析大型XML文档。
思想:将xml中所有元素(Element)称之为节点(Node),一个xml文件由N个节点组成。
		DOM由节点组成:
    		Node分:元素节点(父)
			属性节点(子)
			文本节点(子)
方法:document.selectNodes(xpath);		//查一组
	  document.selectSingleNode(xpath);	//查单个
核心类:SAXReader
		Document

6.5.2.Xpath
path等同数据库的select语句。
/ 定位路径 在系统中建一个文件叫document/students/student/sid|name
@ 属性
示例:
/students 获得students根节点
/students/student 获得students根节点下面所有的student节点
/students/student[@sid=‘s003’] 获得students根节点下面student节点中sid属性等于s003的节点
/students/student[@sid=‘s003’]/name 获得students根节点下面student节点中sid属性等于s003的节点下面的name节点

6.5.3.Dom4j + xpath案例:
//1. 加载xml文件
InputStream is = Demo2.class.getResourceAsStream("/students.xml");
SAXReader saxReader = new SAXReader();
//2. 转换成Document对象
Document document = saxReader.read(is);
//node节点、element元素,可直接将node转成element
//ListstudentNodes = (List)document.selectNodes("/students/student");

 // 3. 获得指定元素路径下所有节点
List<Node> studentNodes = document.selectNodes("/students/student");
// 4. 遍历所有节点
for (Node studentNode : studentNodes) {
        //将节点转换成元素
        Element studentElement = (Element) studentNode;

        // 获得元素中的sid属性值
        // Attribute sidAttribute = studentElement.attribute("sid");
        // 获得元素中属性的数据
        // System.out.println(sidAttribute.getText());

        // 获得元素中的sid属性值
        String sid = studentElement.attributeValue("sid");
        // 获得name的元素

Element nameElement = (Element) studentElement.selectSingleNode(“name”);
// 根据元素名获得数据
String name = nameElement.getText();
System.out.println(sid + “,” + name);
}

其他:
// sid=s003学生的姓名
String xpath = “/students/student[@sid=‘s003’]”;
Element e = (Element) document.selectSingleNode(xpath);
String name = e.selectSingleNode(“name”).getText();
System.out.println(name);

String xpath = “/students/student[@sid=‘s003’]/name”;
Element e = (Element) document.selectSingleNode(xpath);
System.out.println(e.getText());

6.6.XML解析操作

从上面的图很容易发现,应用程序不是直接对XML文档进行操作的,而是由XML解析器对XML文档进行分析,然后应用程序通过XML解析器所提供的DOM接口或者SAX接口对分析结果进行操作,从而间接地实现了对XML文档的访问!
常用的解析器和解析开发包的关系如下所示:

为什么有3种开发包?
jaxp开发包是JDK自带的,不需要导入开发包。
由于sun公司的jaxp不够完善,于是就被研发了Jdom。XML解析如果使用Jdom,需要导入开发包。
dom4j是由于Jdom的开发人员出现了分歧,dom4j由Jdom的一批开发人员所研发。XML解析如果使用Jdom,需要导入开发包【现在用dom4j是最多的!】。

6.6.1.jaxp
虽然jaxp解析XML的性能以及开发的简易度是没有dom4j好,但是jaxp不管怎么说都是JDK内置的开发包,我们是需要学习的!
DOM解析操作
DOM解析是一个基于对象的API,它把XML的内容加载到内存中,生成与XML文档内容对应的模型!当解析完成,内存中会生成与XML文档的结构与之对应的DOM对象树,这样就能够根据树的结构,以节点的形式对文档进行操作!
简单来说:DOM解析会把XML文档加载到内存中,生成DOM树的元素都是以对象的形式存在的!我们操作这些对象就能够操作XML文档了!
下面这样图就能很好地说明了,是怎么样生成与XML文档内容对应的DOM树!

<插图>

6.6.2.dom4j
dom4j是一个非常优秀的开源框架Java XML API,具有性能优异、功能强大和极易使用的特点。它提供了一组API用来解析xml文件。
优点:开源、轻量级、灵活、高性能、高效率、易维护。
注:dom4j常用于解析大型XML文档。

为什么需要有dom4j?
dom缺点:比较耗费内存。
sax缺点:只能对xml文件进行读取,不能修改、添加、删除。
dom4j:既可以提高效率,同时也可以进行crud操作。
因为dom4j不是sun公司的产品,所以我们开发dom4j需要导入开发包。

6.6.3.XPATH
什么是XPATH?
XPath 是一门在XML文档中查找信息的语言。
XPath 用于在 XML 文档中通过元素和属性进行导航。
为什么我们需要用到XPATH?
上面我们使用dom4j的时候,要获取某个节点,都是通过根节点开始,一层一层地往下寻找,这就有些麻烦了!
如果我们用到了XPATH这门语言,要获取得到XML的节点,就非常地方便了!

3.1
思想:将xml中所有元素(Element)称之为节点(Node),一个xml文件由N个节点组成。
DOM由节点组成:
Node分:元素节点(父)
属性节点(子)
文本节点(子)
方法:document.selectNodes(xpath); //查一组
document.selectSingleNode(xpath); //查单个
核心类:SAXReader
Document

3.2 xpath:path等同数据库的select语句。
/   定位路径 在系统中建一个文件叫document/students/student/sid|name
@   属性
示例:
        /students		获得students根节点
        /students/student	获得students根节点下面所有的student节点
        /students/student[@sid='s003']	获得students根节点下面student节点中sid属性等于s003的节点
        /students/student[@sid='s003']/name	获得students根节点下面student节点中sid属性等于s003的节点下面的name节点
  1. 案例:
    //1. 加载xml文件
    InputStream is = Demo2.class.getResourceAsStream("/students.xml");
    SAXReader saxReader = new SAXReader();
    //2. 转换成Document对象
    Document document = saxReader.read(is);

    //node节点、element元素,可直接将node转成element
    //List studentNodes = (List)document.selectNodes("/students/student");

    // 3. 获得指定元素路径下所有节点
    List studentNodes = document.selectNodes("/students/student");
    // 4. 遍历所有节点
    for (Node studentNode : studentNodes) {
    //将节点转换成元素
    Element studentElement = (Element) studentNode;

         // 获得元素中的sid属性值
         // Attribute sidAttribute = studentElement.attribute("sid");
         // 获得元素中属性的数据
         // System.out.println(sidAttribute.getText());
    
         // 获得元素中的sid属性值
         String sid = studentElement.attributeValue("sid");
         // 获得name的元素
         Element nameElement = (Element) studentElement.selectSingleNode("name");
         // 根据元素名获得数据
         String name = nameElement.getText();
         System.out.println(sid + "," + name);
    

    }

// sid=s003学生的姓名
//String xpath = “/students/student[@sid=‘s003’]”;
//Element e = (Element) document.selectSingleNode(xpath);
//String name = e.selectSingleNode(“name”).getText();
//System.out.println(name);

String xpath = “/students/student[@sid=‘s003’]/name”;
Element e = (Element) document.selectSingleNode(xpath);
System.out.println(e.getText());

7.Jsoup
Jsoup是一款Java的Html解析器,可直接解析某个URL地址、HTML文本内容。
它提供了一套非常省力的API,可通过DOM、CSS以及类似于jQuery的操作方法来取出和操作数据。

8.XML建模
建模:通过java代码将xml中元素节点的主从关系描述出来。

以web.xml为例:
是否每次找web.xml中的数据都要读取一次web.xml。
实际是将web.xml中的数据读取出来转换成对象,每次访问调用对象。

案例:

<forward name="failed" path="/reg.jsp" redirect="false" />
<forward name="success" path="/login.jsp" redirect="true" />

分析:

  1. 将每个元素节点看作一个类,元素节点的属性就是类的属性,元素节点下的子元素节点就用集合来装。
    创建一个模型类:ConfigModel、ActionModel、ForwardModel。

    ConfigModel中没有属性,只有0~N个ActionModel;
    ActionModel中有属性path,type,还有0~N个ForwardModel;
    ForwardModel中有属性name,path,redirect,没有子元素节点。


    public class ConfigModel implements Serializable{
    private Map<String, ActionModel> configMaps = new HashMap<String, ActionModel>();
    //封装,重写get方法,put方法自己写
    }

    public class ActionModel implements Serializable{
    private String patht;
    private String type;
    private Map<String, ForwardModel> forwardMaps = new HashMap<String, ForwardModel>();
    //封装,重写get/set方法,集合写put和get
    }

    public class ForwardModel implements Serializable{
    Map<String, String> configMaps = new HashMap<String, String>();
    }

    注:一般类中放一个无参的构造方法。

写好后与xml对比下,写的这些类与xml结构是否匹配,缺什么补什么。

  1. 创建工厂类:ConfigModelFactory,用来生产ConfigModel。
    工厂模式:私有化构造方法,创建静态代理方法。

操作步骤:
1.分析config.xml,根据元素,创建相应的 model 实体类
Forward类
Action类
Config类

  1. 为每个model实体类设置属性和set/get方法
    注意:Action类中声明一个Map集合,并且将Forward对象的name做为Map集合的key,将Forward做为Map集合的value,然后再添加两个操作Map集合的方法:addForward(), getForward(),作用是可以从Map集合中添加Forward对象,和取出Forward对象。

  2. 创建工厂类
    创建Config类的工厂类:ConfigFactory,用于实例化Config对象
    通过dom4j+xpath去解析config.xml,将每个元素都实例化相应的对象,存入父级Map集合中

  3. 创建测试类
    从Config从获得Map集合,遍历
    再从Action中获得Map集合,遍历

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值