java digester_Apache Commons Digester 一 (基础内容、核心API)
前言
在许多需要处理XML格式数据的应用环境中, 如果能够以“事件驱动”的方式来处理XML文档,比如,当识别出特定的XML元素时,触发“创建对象”操作事件(或者触发调用对象的方法事件),这对于应用程序开发来说,是非常有用的;
熟悉以SAX(Simple API for XML Parsing)方式来处理XML文档的开发人员会认识到,Digester为SAX事件提供了更高层次,对开发者更加友好的接口,它隐藏了大部分导航XML元素层次结构的细节,以便于开发者更加专注于要执行的处理操作;
使用Digester的基本步骤
创建一个 org.apache.commons.digester3.Digester 类的实例对象。这里补充说明下,只要我们已经完成XML解析操作,并且不在多个线程中使用同一个Digester对象,那么就可以安全的重复使用我们预先创建的这个Digester实例;不过重用Digester实例并不是非常推荐,最好每个XML解析对应一个单独的Digester实例;
为Digester实例配置属性值,通过配置属性值,我们可以改变Digester 的解析行为,具体有哪些属性值可以配置,待会会介绍;
可选的, 可以将我们的一些初始对象push到Digester栈里;.
在输入的XML文档中,给所有需要触发规则(rule)处理的元素匹配模式(pattern)注册规则;针对任何一个模式,你可以注册任意数量的规则;补充说明下,如果一个模式对应多个规则,则begin和body事件方法会按照它们注册的顺序依次执行,而end事件方法是倒序执行的;
最后,调用digester.parse()方法,该方法需要传入XML文件的引用作为参数,该参数支持多种格式的文件流;另外需要注意的是,该方法会抛出IOException or SAXException异常,以及各种可能的在规则解析处理时遇到的异常,如NoSuchMethodException、IllegalAccessException…
了解基本步骤后,来看一个简单的示例,如下所示,是我们即将要解析的xml文件:
首先,创建两个java bean对应xml中的元素信息:
Foo类
packageapache.commons.digester3.example.pojo;importjava.util.ArrayList;importjava.util.Iterator;importjava.util.List;/***@author http://www.cnblogs.com/chenpi/*@version2017年6月3日*/
public classFoo
{privateString name;private List barList = new ArrayList();public voidaddBar(Bar bar)
{
barList.add(bar);
}public Bar findBar(intid)
{for(Bar bar : barList)
{if (bar.getId() ==id)
{returnbar;
}
}return null;
}public IteratorgetBars()
{returnbarList.iterator();
}/***@returnthe name*/
publicString getName()
{returnname;
}/***@paramname the name to set*/
public voidsetName(String name)
{this.name =name;
}/***@returnthe barList*/
public ListgetBarList()
{returnbarList;
}/***@parambarList the barList to set*/
public void setBarList(ListbarList)
{this.barList =barList;
}
}
View Code
Bar类
packageapache.commons.digester3.example.pojo;/***@author http://www.cnblogs.com/chenpi/*@version2017年6月3日*/
public classBar
{private intid;privateString title;/***@returnthe id*/
public intgetId()
{returnid;
}/***@paramid the id to set*/
public void setId(intid)
{this.id =id;
}/***@returnthe title*/
publicString getTitle()
{returntitle;
}/***@paramtitle the title to set*/
public voidsetTitle(String title)
{this.title =title;
}
}
View Code
使用Digester解析xml:
packageapache.commons.digester3.example.simpletest;importjava.io.IOException;importorg.apache.commons.digester3.Digester;importorg.xml.sax.SAXException;importapache.commons.digester3.example.pojo.Bar;importapache.commons.digester3.example.pojo.Foo;/***
*@author http://www.cnblogs.com/chenpi/*@version2017年6月3日*/
public classMain
{public static voidmain(String[] args)
{try{//1、创建Digester对象实例
Digester digester = newDigester();//2、配置属性值
digester.setValidating(false);//3、push对象到对象栈//digester.push(new Foo());//4、设置匹配模式、规则
digester.addObjectCreate("foo", "apache.commons.digester3.example.pojo.Foo");
digester.addSetProperties("foo");
digester.addObjectCreate("foo/bar", "apache.commons.digester3.example.pojo.Bar");
digester.addSetProperties("foo/bar");
digester.addSetNext("foo/bar", "addBar", "apache.commons.digester3.example.pojo.Bar");//5、开始解析
Foo foo = digester.parse(Main.class.getClassLoader().getResourceAsStream("example.xml"));//6、打印解析结果
System.out.println(foo.getName());for(Bar bar : foo.getBarList())
{
System.out.println(bar.getId()+ "," +bar.getTitle());
}
}catch(IOException e)
{
e.printStackTrace();
}catch(SAXException e)
{
e.printStackTrace();
}
}
}
结果打印:
The Parent
123,The First Child
456,The Second Child
789,The Second Child
注意以上代码涉及类型的自动转换,如id属性,由字符串类型转为整型,这里所有的类型转换都是由commons-beanutils包的ConvertUtils来完成的。
Digester属性配置
org.apache.commons.digester3.Digester实例对象包含若干成员属性,这些属性值是可以设置的,以便我们自定义解析操作;
为了让这些配置在XML解析前生效,这些属性值的更改一定要在parse方法调用之前设置;
如下是一些可以配置的属性
PropertyDescription
classLoader
通过配置这个属性值,我们可以指定ObjectCreateRule和FactoryCreateRule规则使用的类加载器;另外,在没指定该值的时候,如果useContextClassLoader属性值设为true,则会使用当前线程上下文类加载器,否则直接使用加载Digester类的同一个类加载器;
errorHandler
通过配置这个属性值,我们可以指定一个SAX ErrorHandler,当解析错误出现的时候,该Handler会收到通知;
namespaceAware
通过设置该boolean值,可以让Digester在解析的时候,识别出XML命名空间;
xincludeAware
通过设置该boolean值,可以让Digester在解析的时候,识别出语法 ,注意该设置只有在namespaceAware设为true的前提下才有效.
ruleNamespaceURI
该值一般配合namespaceAware使用,在namespaceAware设为true的情况下,设置ruleNamespaceURI,那么接下来的规则只会匹配ruleNamespaceURI命名空间下的元素;
rules
通过该属性,我们可以额外添加一些自定义解析匹配规则;
useContextClassLoader
如果useContextClassLoader属性值设为true,则会使用当前线程上下文类加载器,否则直接使用加载Digester类的同一个类加载器
注意 - 如果设置了classLoader属性值,改属性配置将被忽略;
validating
通过设置该boolean值, 可以配置Digester是否做DTD检查;
另外,我们可以通过Digester的register方法,让Digester在遇到DOCTYPE声明时,使用本地dtd,而不是从网上获取,如下所示:
URL url = new URL("/org/apache/struts/resources/struts-config_1_0.dtd");
digester.register("-//Apache Software Foundation//DTD Struts Configuration 1.0//EN", url.toString());
Digester对象栈
Digester使用的一个核心技术就是动态构建一颗java对象树,在构建的过程中,一个重要的辅助数据结构即对象栈;
以如下xml为例:
在解析的时候:
首先会创建一个foo对象,并压入对象栈,然后设置foo属性值name,紧接着,创建bar对象并压入栈,然后设置bar的属性值,然后将该bar对象添加的到foo对象的barlist属性集合中,然后bar对象弹出对象栈;
以此类推,遇到起始标记的元素创建对象入栈,遇到结尾标记的元素做出栈操作,出栈前,需要将出栈对象并关联到上一个栈顶对象;
最终,解析完xml后,留在栈顶的就关联了所有在xml解析中创建的动态对象了;
Digester暴露出的与对象栈操作API如下所示:
clear() - 清除对象栈.
peek() - 返回栈顶对象引用,但是不弹出.
pop() - 返回栈顶对象,并弹出.
push() - 入栈操作.
Digester元素匹配模式
Digester的一个关键特性是可以自动识别xml的层次结构,程序员只需要关心遇到匹配到某个元素后需要做哪些操作即可;
如下是一个示例,其中a, a/b, a/b/c为匹配模式,对应xml中特定位置的元素:
-- Matches pattern "a"-- Matches pattern "a/b"-- Matches pattern "a/b/c"-- Matches pattern "a/b/c"
-- Matches pattern "a/b"-- Matches pattern "a/b/c"-- Matches pattern "a/b/c"-- Matches pattern "a/b/c"
Digester规则处理
当匹配到模式时,会触发规则处理,具体的规则处理机制是由这个org.apache.commons.digester3.Rule接口封装的,该接口定义了以下几个方法:
begin() - 匹配到xml元素开始标记时,调用该方法;
body() - 匹配到xml元素body时,调用该方法;
end() - 匹配到xml元素结束标记时,调用该方法;
finish() - 当所有解析方法解析完毕后,调用该方法,用于清楚临时数据等;
默认情况下,Digester提供了以下Rule接口的实现类,我们在编码的时候可以直接使用,详见API文档:
如下是一个SetNextRule规则实现类的示例(两种写法):
Rule rule = new SetNextRule("addBar",Bar.class);
digester.addRule("foo/bar", rule );//digester.addSetNext("foo/bar", "addBar", Bar.class.getName());
Digester日志
日志是调试、排查错误非常关键的一个环节,Digester记录了非常详细的日志,我们可以按如下方式来开启日志打印功能;
这里的日志实现选择log4j,
首先,在pom.xml加上如下依赖:
log4j
log4j
1.2.17
然后,编写一个配置文件log4j.properties放到resources路径下:
### set log levels ###
log4j.rootLogger = debug, stdout
### \u8F93\u51FA\u5230\u63A7\u5236\u53F0 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
运行程序,发现已经可以看到DEBUG调试日志了日志:
2017-06-04 18:26:33 [ main:51 ] - [ DEBUG ] Fire body() for SetPropertiesRule[aliases={}, ignoreMissingProperty=true]
2017-06-04 18:26:33 [ main:51 ] - [ DEBUG ] Popping body text ''
2017-06-04 18:26:33 [ main:51 ] - [ DEBUG ] Fire end() for SetPropertiesRule[aliases={}, ignoreMissingProperty=true]
2017-06-04 18:26:33 [ main:52 ] - [ DEBUG ] Fire end() for ObjectCreateRule[className=apache.commons.digester3.example.pojo.Foo, attributeName=null]
2017-06-04 18:26:33 [ main:52 ] - [ DEBUG ] [ObjectCreateRule]{foo} Pop 'apache.commons.digester3.example.pojo.Foo'
2017-06-04 18:26:33 [ main:52 ] - [ DEBUG ] endDocument()
The Parent
123,The First Child
456,The Second Child
789,The Second Child
Digester例子
前面我们已经举了一个Digester的简单使用例子,这里将继续展示几个示例;
解析xml元素body值
如下XML文档就是我们要解析内容:
action
org.apache.struts.action.ActionServlet
application
org.apache.struts.example.ApplicationResources
config
/WEB-INF/struts-config.xml
首先,定义一个ServletBean,存储以上xml信息,如下所示:
/*
* File Name: ServletBean.java
* Description:
* Author: http://www.cnblogs.com/chenpi/
* Create Date: 2017年6月4日
*/
package apache.commons.digester3.example.pojo;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author http://www.cnblogs.com/chenpi/
* @version 2017年6月4日
*/
public class ServletBean
{
private String servletName;
private String servletClass;
private Map initParams = new HashMap();
public void addInitParam(String paramName, String paramValue){
initParams.put(paramName, paramValue);
}
/**
* @return the servletName
*/
public String getServletName()
{
return servletName;
}
/**
* @param servletName the servletName to set
*/
public void setServletName(String servletName)
{
this.servletName = servletName;
}
/**
* @return the servletClass
*/
public String getServletClass()
{
return servletClass;
}
/**
* @param servletClass the servletClass to set
*/
public void setServletClass(String servletClass)
{
this.servletClass = servletClass;
}
/**
* @return the initParams
*/
public MapgetInitParams()
{
return initParams;
}
/**
* @param initParams the initParams to set
*/
public void setInitParams(MapinitParams)
{
this.initParams = initParams;
}
}
编写规则解析xml,如下所示:
/** File Name: Main2.java
* Description:
* Author:http://www.cnblogs.com/chenpi/* Create Date: 2017年6月4日*/
packageapache.commons.digester3.example.simpletest;importjava.io.IOException;importorg.apache.commons.digester3.Digester;importorg.apache.commons.digester3.Rule;importorg.apache.commons.digester3.SetNextRule;importorg.xml.sax.SAXException;importapache.commons.digester3.example.pojo.Bar;importapache.commons.digester3.example.pojo.Foo;importapache.commons.digester3.example.pojo.ServletBean;/***
*@author http://www.cnblogs.com/chenpi/*@version2017年6月4日*/
public classWebMain
{public static voidmain(String[] args)
{try{//1、创建Digester对象实例
Digester digester = newDigester();//2、配置属性值
digester.setValidating(false);//3、push对象到对象栈//4、设置匹配模式、规则
digester.addObjectCreate("web-app/servlet", "apache.commons.digester3.example.pojo.ServletBean");
digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0);
digester.addCallMethod("web-app/servlet/servlet-class", "setServletClass", 0);
digester.addCallMethod("web-app/servlet/init-param", "addInitParam", 2);
digester.addCallParam("web-app/servlet/init-param/param-name", 0);
digester.addCallParam("web-app/servlet/init-param/param-value", 1);//5、开始解析
ServletBean servletBean =digester
.parse(ExampleMain.class.getClassLoader().getResourceAsStream("web.xml"));//6、打印解析结果
System.out.println(servletBean.getServletName());
System.out.println(servletBean.getServletClass());for(String key : servletBean.getInitParams().keySet()){
System.out.println(key+ ": " +servletBean.getInitParams().get(key));
}
}catch(IOException e)
{
e.printStackTrace();
}catch(SAXException e)
{
e.printStackTrace();
}
}
}
结果打印:
action
org.apache.struts.action.ActionServlet
application: org.apache.struts.example.ApplicationResources
config: /WEB-INF/struts-config.xml
解析XML命名空间
对于没有使用命名空间的xml来说,Digester默认的处理机制已经足够满足我们的需求了。但是当XML文档使用命名空间的时候,对于不同命名空间的元素来说,有时候我们希望使用不同的规则去解析它。
Digester 没有提供对命名空间的完全支持, 但已经足够完成大多数任务了. 开启Digester的命名空间支持只需要以下几个步骤即可:
1、通过配置以下属性值,告诉 Digester,需要开启命名空间解析:
digester.setNamespaceAware( true );
2、声明接下来的规则关联的命名空间,注意我们这里没有指明任何前缀,XML文档的作者是可以使用任何他们喜欢的前缀的
digester.setRuleNamespaceURI( "http://www.mycompany.com/MyNamespace" );
3、添加该命名空间下的规则, 通常会调用 addObjectCreate() 或者 addSetProperties()这类方法. 注意,这里匹配的模式是不需要加上前缀的:
digester.addObjectCreate( "foo/bar", "com.mycompany.MyFoo");
digester.addSetProperties("foo/bar");
4. 重复2、3步骤,解析其它命名空间的元素.
如下,是一个示例,使用以上步骤即可完成解析:
xmlns:m="http://www.mycompany.com/MyNamespace"xmlns:y="http://www.yourcompany.com/YourNamespace">
由于我们给Digester指定的命名空间为http://www.mycompany.com/MyNamespace,所以以上xml只有第一个bar会被解析出来。
如下是一个完整示例(XML及对应解析代码):
/** File Name: Main.java
* Description:
* Author:http://www.cnblogs.com/chenpi/* Create Date: 2017年6月3日*/
packageapache.commons.digester3.example.simpletest;importjava.io.IOException;importorg.apache.commons.digester3.Digester;importorg.xml.sax.SAXException;importapache.commons.digester3.example.pojo.Bar;importapache.commons.digester3.example.pojo.Foo;/***
*@author http://www.cnblogs.com/chenpi/*@version2017年6月3日*/
public classExampleNSMain
{public static voidmain(String[] args)
{try{
Digester digester= newDigester();
digester.setValidating(false);
digester.setNamespaceAware(true);
digester.setRuleNamespaceURI("http://www.mycompany.com/MyNamespace");
digester.addObjectCreate("foo", Foo.class);
digester.addSetProperties("foo");
digester.addObjectCreate("foo/bar", Bar.class);
digester.addSetProperties("foo/bar");
digester.addSetNext("foo/bar", "addBar", Bar.class.getName());
Foo foo=digester
.parse(ExampleNSMain.class.getClassLoader().getResourceAsStream("example_ns.xml"));
System.out.println(foo.getName());for(Bar bar : foo.getBarList())
{
System.out.println(bar.getId()+ "," +bar.getTitle());
}
}catch(IOException e)
{
e.printStackTrace();
}catch(SAXException e)
{
e.printStackTrace();
}
}
}
使用命名空间前缀用于模式匹配
当一个命名空间下的规则集合与另一个命名空间的规则集合相互独立的话,使用带命名空间的规则非常有用,但是当我们的规则逻辑需要使用到不同命名空间下的元素时,那么使用带命名空间前缀的模式将会是一个更好的策略;
很简单,我们只需要,设置NamespaceAware 属性为false,然后在模式前面带上命名空间前缀即可。
比如, (将 NamespaceAware 设为false), 那么模式 m:bar' 只会匹配命名空间前缀为m的bar元素.
如下是一个完整demo:
/** File Name: Main.java
* Description:
* Author:http://www.cnblogs.com/chenpi/* Create Date: 2017年6月3日*/
packageapache.commons.digester3.example.simpletest;importjava.io.IOException;importorg.apache.commons.digester3.Digester;importorg.xml.sax.SAXException;importapache.commons.digester3.example.pojo.Bar;importapache.commons.digester3.example.pojo.Foo;/***
*@author http://www.cnblogs.com/chenpi/*@version2017年6月3日*/
public classExampleNS2Main
{public static voidmain(String[] args)
{try{
Digester digester= newDigester();
digester.setValidating(false);
digester.setNamespaceAware(false);//digester.setRuleNamespaceURI("http://www.mycompany.com/MyNamespace");
digester.addObjectCreate("m:foo", Foo.class);
digester.addSetProperties("m:foo");
digester.addObjectCreate("m:foo/m:bar", Bar.class);
digester.addSetProperties("m:foo/m:bar");
digester.addSetNext("m:foo/m:bar", "addBar", Bar.class.getName());
digester.addObjectCreate("m:foo/y:bar", Bar.class);
digester.addSetProperties("m:foo/y:bar");
digester.addSetNext("m:foo/y:bar", "addBar", Bar.class.getName());
Foo foo=digester
.parse(ExampleNS2Main.class.getClassLoader().getResourceAsStream("example_ns.xml"));
System.out.println(foo.getName());for(Bar bar : foo.getBarList())
{
System.out.println(bar.getId()+ "," +bar.getTitle());
}
}catch(IOException e)
{
e.printStackTrace();
}catch(SAXException e)
{
e.printStackTrace();
}
}
}
错误排查
Digester 是基于 SAX 开发的. Digestion 会抛出两种类型的 Exception:
java.io.IOException
org.xml.sax.SAXException
第一个异常很少会抛出,且该异常众所周知。 通常我们遇到最多的是第二个异常,当SAX解析无法完成的时候会抛出该异常,所以熟悉SAX的错误处理方式对诊断SAXException很有帮助。
当一个SAX 解析器 遇到xml问题时 (哈哈,有时候,会在遇到xml问题之后),会抛出SAXParseException异常. 该异常是SAXException 的子类,并且包含了一些额外信息(哪里出错,出了什么错误),如果我们捕获了这类异常,那么就可以明确知道问题是XML引起的,而不是Digester或者我们的解析规则。通常来说,捕获该异常并记录详细信息到日志对诊断错误非常有帮助。
一般情况下 SAXException 异常内部会组合另一个异常,换句话说,就是当Digester遇到异常的时候,会首先将该异常封装成一个SAXException异常,然后将该SAXException重新抛出 。所以,捕获SAXException异常,并仔细检查被封装的内部异常,有助于排查错误;
错误示例:
org.xml.sax.SAXParseException; lineNumber: 4; columnNumber: 44; 元素类型 "y:bar" 必须后跟属性规范 ">" 或 "/>"。
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1239)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:648)
at org.apache.commons.digester3.Digester.parse(Digester.java:1642)
at org.apache.commons.digester3.Digester.parse(Digester.java:1701)
at apache.commons.digester3.example.simpletest.ExampleNS2Main.main(ExampleNS2Main.java:48)
参考资料
示例代码
java digester_Apache Commons Digester 一 (基础内容、核心API)相关推荐
- JBOSS java.lang.NoClassDefFoundError: org/apache/commons/digester/RuleSet
经常在启动JBOSS的时候,发现在myeclipse的console中报错java.lang.NoClassDefFoundError: org/apache/commons/digester/Rul ...
- Java基础内容/基础语法/流程控制
基础内容 1.如何高效的学好java 多写代码,多写笔记,多写文章 多练交流,多练思维,多练技能 多分享,多提问,多思考 最重要(坚持) 2.计算机应用领域 1)科学计算 2)数据处理 3)自动控制 ...
- JAVA基础内容拓展 链接汇总
JAVA基础内容拓展链接汇总 Java基础部分需要学习很多的内容,其实学习就是一个逐步深入递进的过程 从易到难,我们可以进行进一步的拓展 希望本文可以帮助到你,本文是程序媛泡泡给大家总结的链接汇总,欢 ...
- java中commons意思_java的Commons包简介
Jakarta Commons是Jakarta的一个子项目,目的是创建和维护独立于其他框架和产品的程序包(packages).Jakarta Commons项目源于重用,其中的程序包必须确保能够重用. ...
- java Apache Commons jar包简介
一.Commons BeanUtils 说明:针对Bean的一个工具集.由于Bean往往是有一堆get和set组成,所以BeanUtils也是在此基础上进行一些包装. 二.Commons CLI 说明 ...
- 跟我20天学Java:01-计算机基础以及JDK、IDEA等安装详解
文章目录 第一章 计算机基础知识 1.1 基础班介绍 Java基础班分类: 1.2 计算机简介 1.3 计算机硬件和软件 1.3.1 计算机硬件 运算器和控制器 输入设备 存储器 输出设备 1.3.2 ...
- Java面试宝典之:基础篇
一. Java基础部分 1.Java多态的具体体现 [必背] 面向对象编程有四个特征:抽象,封装,继承,多态. 多态有四种体现形式: 1. 接口和接口的继承. 2. 类和类的继承. 3. 重载. ...
- 130道Python练习题,涵盖基础内容的方方面面
1.数据类型篇 1.1 基本数据类型 1.1.1 逻辑推理练习(类型转换) 1.1.1.1 bool函数转换规则 1.1.1.2 int("3.42") 为什么会报错 1.1.1. ...
- Java Web应用开发_04javaWeb基础
Java Web应用开发_04javaWeb基础 4.1 XML节内小测 4.2HTTP协议 4.3 搭建开发环境 04javaWeb基础单元测验4 4.1 XML节内小测 1下列关于XML的描述中, ...
- 给Java开发者的Flutter开发基础---Dart语言
接近半年没有在简书冒泡了.这段时间一是忙于使用云信IM开发相应项目,二是整理和收集相关Flutter的相关资料进行学习.国内关于Flutter的资料还是太过于稀少,以至于我只能去YouTube和Ude ...
最新文章
- 干货,师兄倾力推荐的14个实验心得
- 树莓派超声波模块测距
- Android Glide图片加载框架(二)源码解析之load()
- 吴恩达入驻知乎,涨粉秒过万!知乎首答:如何系统学习机器学习
- java获取字典所有的key_JAVA脱水学习-java集合介绍,常用集合类
- Java实现一个字符串的反转
- 程序员到CTO还需要大补什么营养
- Android系统的若干关键词大汇总
- 肥城市c语言入门自学零基础,2019年自考C语言程序设计模拟试题十三答案.doc
- 2022年美赛成绩什么时候出,2022美赛思路与注意事项。
- 十天学会php之第六天
- 修身养性的句子_关于修身养性的名言
- Spring cloud oauth2搭建OAuth2.0授权服务
- 音乐计算机曲谱狂妄之人,【B】 Undertale Sans战斗曲 MEGALOVANIA狂妄之人
- 一篇关于数学建模美赛论文撰写的心得
- KeyShot 11 Pro for Mac(3D渲染和动画制作) V11.3.2.2中文安装+更新内容
- win10DCH驱动卸载后无法安装标准驱动的问题(与首选图形处理器拒绝访问)
- 第十节 Java工具包-Collections 流--lambada表达式
- 【第六章】使用jQuery操作表单和表格2
- 20170908一些随笔感悟
热门文章
- 雷蛇鼠标 雷云3 驱动无法启动 Razer Syncapse 3 Failed to start
- 初识马尔科夫链,原来是这样的
- matlab如何释放内存,怎么能释放已经使用的内存
- WPS Office 2020 for Mac(wps2020)3.8.0(6081)中文
- mysql 主键 sql语句_Mysql主键相关的sql语句集锦
- 【工具篇】Unity迷宫地图生成器MazeSpawner随机迷宫信手拈来
- 北航计算机学院考研英语一还是二,2020北京航空航天大学计算机考研考试科目知多少?...
- HCIA—冲突域与广播域(详解 + 区别)
- svn和git的区别
- 怎样在html中插入ppt,PPT怎么插入网页中的视频