码迷,mamicode.com
首页 > 其他好文 > 详细

Jakarta Commons Cookbook

时间:2015-04-27 13:11:59      阅读:387      评论:0      收藏:0      [点我收藏+]

标签:

技术分享

Cookbook就是工具书,应该是前年看的,在中关村看的影印版,全英文,本书主要讲解了一下模块:
  1. Core:BeanUtils,Lang,Collections,logging
  2. Db:DbUtils,DBCP,Pool
  3. IO: IO,
  4. XML vs Bean:betwixt,Digester,JXPath,Jelly
  5. 模版:EL, JEXL
  6. 通用:Codec,Id
  7. Web:FileUpload,httpClient
  8. 文件系统:VFS
apache的工具包几乎是每个java工程都用到了的,或是common或是log等等,建议编程一两年的java开发人员熟知,这样你的生产力将大大的提高。很多网页上有各种总结,但我更喜欢系统性的看书,当然我看的时候已经编了四五年了,有种相逢恨晚的感觉,于是现在我的eclipse工程里多了所有这些开源工程最新的代码,可以迟到,不能错过。

1.apache的commons工程包括了许多方便的工程可以节省开发人员的时间,本书主要介绍了:BeanUtils,Betwixt,CLI,Codec,Collections,Configuretion,Digester,HttpClient,ID,IO,JEXL,JXPath,Lang,
Logging,Math,Net,Log4j,Velocity,FreeMarker,Lucene,Slide
//-------------------------Lang----------------------------------
http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/index.html
2.toString方法,ReflectionToStringBuilder.toString(obj)可以按默认格式打印对象的内容,也可以用toStringBuilder.append来设置打印的内容,并可以设置ToStringBuilder的ToStringStyle。
3.hashCode方法,可以用new HashCodeBuilder(17,37).append(firstName).append(lastName).toHashCode()方法来生成hashCode,如果要让对象的所有field都作用于hashCode,可以调用HashCodeBuilder.reflectionHashCode(obj).
4.isEquals方法,EqualsBuilder用法类似HashCodeBuilder,可以用append(支持所有原始类型及对象,也支持数组比较元素),也可以用reflectionEquals(this,obj)来比较对象的每个field。
5.compareTo方法,用于排序或比较对象,CompareToBuilder.reflectionCompare(this,obj)比较的是对象的field,不考虑static field和transient field,注意如果是append(first,obj.first).append(last,obj.last).toComparison()方法,则有一个比较顺序问题,是从最后一个append开始往前比较,只有当前比较的的结果相同时才会比较前一个append的值。当然,如果要比较bean可以用BeanComparator,更细致的比较可以chain Comparetor......
6.ArrayUtils实用方法简介,具体可参考
        1.toString方法打印数组内容
        2.clone出完全新的数组
        3.reverse反转数组元素,Java提供的Collections.reverse参数是list
        4.clone方法,内部调用了java自带的clone方法,只是对null做了判断,如果是null则返回null
        5.toObject/toPrimitive方法提供了装箱与拆箱方法,java1.5后用不上了
        6.contains/indexOf/lastIndexOf用于判断某数是否在数组中以及查找其位置,对象比较内部使用的是object.equals方法
        7.toMap方法,可以将一个二维数组转换为map,第二维的数组必须至少有两个元素,第一个为key,第二个为value
7.日期操作函数,用DataFormatUtils的多种格式创建线程安全的FastDateFormat来替换java原生的线程不安全的SimpleDateFormat.一般来说Sun提供的所有format类比如SimpleDateFormat,MessageFormat,NumberFormat,DecimalFOrmat,CoiceFormat等都是线程不安全的,DateUtils提供的一下实用方法:
        1.灵活的set方法,方便设置年月日,时间等
        2.round四舍五入及ceil去尾数法
        3.turncate可以清除到指定时间幅度的值,比如将2014-1-8 23:06:03 做小时truncate会到2014-1-8 23:00:00
8.Validate类可以提供一些基本的为空,非null,数组范围,正则等,如果验不过则抛出exception,可以在方法中做断言用,可以配Range范围类来做一些边界等判断
9.StopWatch方法可以像秒表一样提供时间的准确计算,可以用在程序耗时方面,当然用System.nanoTime也可以来做,但是StopWatch提供的start,stop,split等方式更具可读性。
10.StringUtils处理字符串,主要方法如下:
  • abbreviate 缩写
  • IsEmpty/IsBlank - checks if a String contains text
  • Trim/Strip - removes leading and trailing whitespace,strip提供了丰富的截除部分字符串的功能
  • Equals - compares two strings null-safe
  • startsWith - check if a String starts with a prefix null-safe
  • endsWith - check if a String ends with a suffix null-safe
  • IndexOf/LastIndexOf/Contains - null-safe index-of checks
  • IndexOfAny/LastIndexOfAny/IndexOfAnyBut/LastIndexOfAnyBut - index-of any of a set of Strings
  • ContainsOnly/ContainsNone/ContainsAny - does String contains only/none/any of these characters
  • Substring/Left/Right/Mid - null-safe substring extractions
  • SubstringBefore/SubstringAfter/SubstringBetween - substring extraction relative to other strings
  • Split/Join - splits a String into an array of substrings and vice versa
  • repeat 克隆字符
  • Remove/Delete - removes part of a String
  • Replace/Overlay - Searches a String and replaces one String with another
  • Chomp/Chop - removes the last part of a String
  • LeftPad/RightPad/Center/Repeat - pads a String
  • UpperCase/LowerCase/SwapCase/Capitalize/Uncapitalize - changes the case of a String
  • CountMatches - counts the number of occurrences of one String in another
  • IsAlpha/IsNumeric/IsWhitespace/IsAsciiPrintable - checks the characters in a String
  • DefaultString - protects against a null input String
  • Reverse/ReverseDelimited - reverses a String
  • Abbreviate - abbreviates a string using ellipsis
  • Difference/indexOfDifference - compares Strings and reports on their differences
  • LevenshteinDistance - the number of changes needed to change one String into another
     
11.WordUtils提供对字符串大小写转换,缩写等操作,方法capitalize/uncapitalize/swapCase/initials等
12 Lang All Classes :
AggregateTranslator ,AnnotationUtils ,ArrayUtils ,AtomicInitializer ,AtomicSafeInitializer ,BackgroundInitializer ,BasicThreadFactory ,BasicThreadFactory.Builder ,BitField ,BooleanUtils ,Builder ,CallableBackgroundInitializer ,CharEncoding ,CharSequenceTranslator ,CharSequenceUtils ,CharSet ,CharSetUtils ,CharUtils ,ClassUtils ,CloneFailedException ,CodePointTranslator ,CompareToBuilder ,CompositeFormat ,ConcurrentException ,ConcurrentInitializer ,ConcurrentRuntimeException ,ConcurrentUtils ,ConstantInitializer ,ConstructorUtils ,ContextedException ,ContextedRuntimeException ,DateFormatUtils ,DateUtils ,DefaultExceptionContext ,DurationFormatUtils ,EntityArrays ,EnumUtils ,EqualsBuilder ,EventListenerSupport ,EventUtils ,ExceptionContext ,ExceptionUtils ,ExtendedMessageFormat ,FastDateFormat ,FieldUtils ,FormatFactory ,FormattableUtils ,Fraction ,HashCodeBuilder ,IEEE754rUtils ,ImmutablePair ,JavaVersion ,LazyInitializer ,LocaleUtils ,LookupTranslator ,MethodUtils ,MultiBackgroundInitializer ,MultiBackgroundInitializer.MultiBackgroundInitializerResults ,Mutable ,MutableBoolean ,MutableByte ,MutableDouble ,MutableFloat ,MutableInt ,MutableLong ,MutableObject ,MutablePair ,MutableShort ,NumberUtils ,NumericEntityEscaper ,NumericEntityUnescaper ,NumericEntityUnescaper.OPTION ,ObjectUtils ,ObjectUtils.Null ,OctalUnescaper ,Pair ,RandomStringUtils ,Range ,ReflectionToStringBuilder ,SerializationException ,SerializationUtils ,StandardToStringStyle ,StopWatch ,StrBuilder ,StringEscapeUtils ,StringUtils ,StrLookup ,StrMatcher ,StrSubstitutor ,StrTokenizer ,SystemUtils ,TimedSemaphore ,ToStringBuilder ,ToStringStyle ,TypeUtils ,UnicodeEscaper ,UnicodeUnescaper ,Validate ,WordUtils 
// Lang包的一些补充说明: 2014年3月13日
12.1.Fraction是一个分数的类,提供分子分母或分式型的字符串来生成一个Fraction对象,此类封装了加减乘除,约分,变号,指数等常见的数学操作
12.2.NumberUtil提供了一些字符串解析成各种数字型的方法,包括解析成Number类型,同时提供了参数是各种数组或多个参数里找出min/max的使用工具方法。Math包也提供了Min/Max类
12.3.Range类提供了抽象类型的范围类,根据默认或传入的comparator来确定范围和判断是否属于此范围

//----------------------------------------------------Commons Codes --------------------------------------------------
13.提供了用来处理常用的编码方法的工具类包,例如DES、SHA1、MD5、Base64,URL,Soundx等等http://commons.apache.org/proper/commons-codec
Commons Codes All Classes AbstractCaverphone,Base32,Base32InputStream,Base32OutputStream,Base64,Base64InputStream,Base64OutputStream,BaseNCodec,BaseNCodecInputStream,BaseNCodecOutputStream,BCodec,BeiderMorseEncoder,BinaryCodec,BinaryDecoder,BinaryEncoder,Caverphone,Caverphone1,Caverphone2,CharEncoding,Charsets,ColognePhonetic,Crypt,Decoder,DecoderException,DigestUtils,DoubleMetaphone,Encoder,EncoderException,Hex,Lang,Languages,Languages.LanguageSet,Languages.SomeLanguages,MatchRatingApproachEncoder,Md5Crypt,MessageDigestAlgorithms,Metaphone,NameType,Nysiis,PhoneticEngine,QCodec,QuotedPrintableCodec,RefinedSoundex,Rule,Rule.Phoneme,Rule.PhonemeExpr,Rule.PhonemeList,Rule.RPattern,RuleType,Sha2Crypt,Soundex,StringDecoder,StringEncoder,StringEncoderComparator,StringUtils,UnixCrypt,URLCodec

//----------------------------------------------------Commons BeanUtils--------------------------------------------------
14.beanutils是Struts等web开源框架的最基本思想实现库,主要用于操作类及属性,通过发射等手段提供方便对bean的基本工具方法:
15.PropertyUtils主要方法及使用:
  • 中提供了获取bean中普通元素,bean元素,list元素,Map元素的值方法,分别是getSimpleProperty(bean,"name"),getNestedProperty(bean,"ext.balance"),getIndexedProperty(bean,"list[1]"),getMappedProperty(bean,"map(key)"),也可以直接调用getProperty(bean,"ext.list[0].map(key)")组合的形式,被解析的时候根据具体形式再调用上面的具体方法,相应的set方法使用,尤其是JEXL的描述用法很方便
  • isReadable/isWritable(bean,"name")可以查看此属性是否可读/可写
  • describe方法返回所有get方法可访问的bean元素到一个Map中,key为属性名。BeanMap类通过传入一个bean构造一个map,在此map上用map的基本方法直接操作bean,酷啊。
16.BeanComparator提供比较具体bean属性从而排序的方法,此类也支持传入具体的Comparator实现具体排序的算法
17.克隆bean可以用PropertyUtils.copyProperties(destBean,sourBean),也可以直接调用BeanUtils.cloneBean(sourBean)直接返回一个新的bean,但是需要注意,bean里面如果是对象元素,则对象元素是两个bean共同"引用"的,也就是在一个bean里修改了对象元素,另一个bean能看到。BeanUtils里有一些和PropertyUtils重复的方法,但是BeanUtils里的方法能灵活的convert,尤其是setProperty的时候,如BeanUtils.setProperty(bean,"age","50"),而bean中的age为int型,如果是用PropertyUtils.setProperty则会报类型错误
18.通过设置DynaProperty,DynaClass可用new出一个动态的bean用于灵活的代表一个data model。如可以通过一个xml文件的配置来创建一个dynabean
19.BeanPredicae可以利用collections提供的多种类型的Predicate来通过bean中的具体属性对bean的某些属性条件进行验证,所有Predicate的子类:

 
//----------------------------------------------------Commons Collections--------------------------------------------------
20.ReverseComparator/ComparatorChain/NullComparator/FixedOrderComparator比较器,ComparatorChain可以add多个comparator,从最后一个add的comparator开始比较直到不为0,NullComparator通过构造的时候传入false/ture来比较null对象与其他对象相比时是-1/1, FixedOrderComparator则是通过预设的数组或list顺序来比较传入的对象,按此预设的值来决定顺序
21.PredicateUtil提供了创建多种Predicate对象的方法,用于对bean进行判断,TransForm用于根据传入的对象来create 新对象,而Closure则是对传入的对象进行修改,本质都相当于Decorator模式,根据传入的对象做一些处理
22.LoopIterator可以做循环iter,通过设置reset来重置,ArrayListIterator可以iter部分list,FilterIterator可以根据Predicate对象对集合遍历时做一些条件限制,符合条件的才iter,比如UniqueFilterIterator就是一个唯一性遍历的子实现
23.Bag可以用来控制对象使用的数量,HashBag/TreeBag
24.一些牛B的Map
  •     MultiKeyMap:多个key共同作用才能对应到一个value
  • MultiValueMap:一个key可以对应多个value,get(key)时返回的是一个ArrayList实例
  • BidiMap可以通过value来反找key,这个时候key-value都是一一对应的,put的时候如果key不同而value,则后put的key会替换相同value对应的已经存在的key。
  • CaseInsensitiveMap 对key大小写敏感的Map,即大小写不同但是内容相同的key会被认为是同一个key
25.Predicate*提供了对多种集合进行decorate的验证的类,用于控制集合的有效性,如PredicatedBag,PredicatedSortedBag,PredicatedCollection,PredicateDecorator,PredicateTransformer,PredicatedList,PredicatedMap,PredicatedSortedMap,PredicatedQueue,PredicatedSet,PredicatedSortedSet
    示例:
        List list = PredicatedList.decorate(new ArrayList(),new Predicate<String>() {
            public boolean evaluate(String str) {               
                return str.startWith("cfca");
            }
        }); // PredicatedList继承了list,并重写了add方法,在add里加入了验证
    
26.可以利用CollecionUtils里的transform对Collection系列类里的元素进行一些转换,传入collection及former即可将collection 里的各元素转换,此CollecionUtils还有一个方法transformingCollection()用法类似,只不过是返回一个collection,在往此collection加入元素时才开始进行转换
CollecionUtils里一些常见静态工具方法:
  •         countMatches(collection,predicate)计算符合predicate的collection中的元素的个数
  • cardinality(ele,collection)计算ele在collection出现的次数
  • getCardinalityMap(collection)得到一个map,key为collection中的元素,value为每个元素出现的次数
  • union,intersection,disjunction,subtract可以实现两个iterable对象的并集,交集,非交集,不包括集

27.LRUMap根据Least Recently Used算法来淘汰放入里面的元素,注意它是线程不安全的,需要用Collections.synchronized***来保障线程安全。
28. LazyMap.lazyMap(map,factory)  可以将一个普通的map转化成lazymap,即当get的时候如果map里没有对应的key,则会调用factory里面一次生成value放到map中。
29.MapUtils里封装了很多转化成不同功能map 的方法:
get***Value可以将得到的object或泛型V转化成***对应的类型,比较方便

//----------------------------------------------------Commons Digester/Betwixt--------------------------------------------------
30.Digester可以将xml文件转成javabean,其原理是利用sax栈解析,根据定义好的rules(rules可以是文件也可以是Rules实例)
31.rules的作用就是告诉digester的parser当遇到xml中的某个节点时,应该按照什么方式去解析,是生成对象,还是设置属性之类的。
demo:
        Digester digester = new Digester();          
         //设置对XML文档资料是否进行DTD验证 
         digester.setValidating( false );          
         //当遇见 catalog 元素的时候,产生一个Catalog对象 
         digester.addObjectCreate( "catalog", Catalog.class );          
         //当遇见 catalog 元素下面的book的时候,产生一个Book对象 
         digester.addObjectCreate( "catalog/book", Book.class ); 
         // 当遇见 catalog 元素下面的book的author时候,调用author属性的Set方法 
         digester.addBeanPropertySetter( "catalog/book/author", "author" ); 
         digester.addBeanPropertySetter( "catalog/book/title", "title" ); 
         //当再一次遇见 catalog 元素下面的book的时候,调用catalog类的addBook()方法 
         digester.addSetNext( "catalog/book", "addBook" ); 
 
32.如果有多个namespace,则需要分别设置不同的namesapce后再设置不同的RuleSet,如:
digester.setRuleNamesapceURI("http://***1");digester.addRuleSet(new RuleSetBase1);
digester.setRuleNamesapceURI("http://***2");digester.addRuleSet(new RuleSetBase1);
33.所有的rule其实就是根据xpath的规则告诉digester按照不同的方式去处理当前处理到的这个节点,其优势相比较于sax在于匹配规则的灵活性及调用的方便性,如digester.addRule("*/email",new EmailRule());这样在EmailRule可以通过继承Rule类来自己重载begin(),body(),end(),finish()等方法来实现特殊操作,比如真发emial。(继承Rule的方式其实和sax解析实现ContentHandler接口思想是一致的)
34.digester也可以通过setSubstitutor方法来设置解析时提供的值来替换xml里类似${name}来实现类似“模板”解析,很方便
35.Betwixt用于在xml与bean之间做序列化和发序列化,利用BeanWriter/xmlintrospector的设置将bean转化成xml字符串(利用了Digester),利用BeanReader/xmlIntrospector的设置将xml字符串转化成bean 参考:http://lavasoft.blog.51cto.com/62575/107349/

//----------------------------------------------------Commons CLI/Configuration--------------------------------------------------
36.cli包可以方便执行java应用时设置一些命令及参数,类似ls -l,rm -rf之类的,有多中命令方式:

Commons CLI supports different types of options:

  • POSIX like options (ie. tar -zxvf foo.tar.gz)
  • GNU like long options (ie. du --human-readable --max-depth=1)
  • Java like properties (ie. java -Djava.awt.headless=true -Djava.net.useSystemProxies=true Foo)
  • Short options with value attached (ie. gcc -O2 foo.c)
  • long options with single hyphen (ie. ant -projecthelp)
cli是一个很小的包,做的事情就是把命令中的参数和值用option接收到而已。
而且在一个配置文件中可以配置有不同的配置方式,如config.xml中可以按xml的格式配置properties文件,ConfigurationFactory and a CompositeConfiguration会根据文件类型自动找到对应的解析类去加载
38. Configuration支持reloading,可以灵活设置配置动态更新策略
//----------------------------------------------------Commons-logging--------------------------------------------------
39.commons-logging是一个抽象的日志框架,当调用LogFactory.getLog("Test")试图得到log对象的时候,会按照如下步骤获取log对象:通过获取“org.apache.commons.logging.Log"属性获取Logger对象--->在类路径上查找Log4j对象--->通过获取"org.apache.commons.logging.impl.Jdk14Logger"属性获取JDK的log框架--->在类路径上查找JDK 自身的log框架--->用自身的SimpleLog对象。
40.查找的顺序按LogFactory定义的数组顺序:
 private static final String[] classesToDiscover = {
          org.apache.commons.logging.impl.Log4JLogger,
            "org.apache.commons.logging.impl.Jdk14Logger",
            "org.apache.commons.logging.impl.Jdk13LumberjackLogger",
            "org.apache.commons.logging.impl.SimpleLog"
    };
一般来说如果项目中没有配第一个(即用classLoad找不到Log4jLogger,没有log4j.jar),那么肯定会有第二个的。
//----------------------------------------------------Commons Math--------------------------------------------------
41.RandomDataImpl提供各种随机数的方法
42.StatUtils提供了操作基本算术的方法,如平均值,乘积,方差等
43.给定方程组的变量参数二维数组和值的数组,利用RealMatrix等类可以解线性方程
44.利用SimpleRegression和StopWatch可以来判断剩余操作时间估算,基于线性的估算算法。如果操作本身是非线性的,可能存在估算不准的情况
//----------------------------------------------------Commons JEXL--------------------------------------------------
45.JEXL有点像PropertyUtils里的按一定的语法来获取对象属性,以${obj.prop}、${obj.fun()}的形式。Expression是模板文本,Content是设置传入值的上下文环境
//----------------------------------------------------Velocity--------------------------------------------------
http://velocity.apache.org/
46.Velocity相比JEXL有更丰富的功能,有专门的Velocity Template Language语法。支持语法基本的if/for/iterator/macro宏定义等。init的时候可以设置一些基本的属性。以$obj的方式。需要初始化engin,设置Context上下文和输入输出。可以通过engin设置一些类路径来动态调用模板里面的方法定义等。Velocity也提供基本的tools工具类,如NumberTool,DateTool,MathTool等。可以和web应用及IDE整合。
//----------------------------------------------------FreeMarker--------------------------------------------------
http://freemarker.org/
47.FreeMarker功能类似Velocity,也有专门的FTL语法,有专门的将VTL转换成FTL的工具。可以和web应用及IDE整合。
//----------------------------------------------------Commons  IO--------------------------------------------------
http://commons.apache.org/proper/commons-io/javadocs/api-release/index.html
48.IO包主要包括的功能:
48.5 CopyUtils类已经在2系列版本里被制成了Deprecated,其全部的功能都在IOUtils里的copy/write实现。copy就是对源流按bufffer大小读一遍write到目标流里。copy后源流也被读完了,需要reset才可以重新被读。
49.IOUtils主要的方法类型:
50.IOUtils中所有读写都是buffer的,大小默认是4k。可以用readLine/writeLine来按行读写。一般来说,close流需要调用者自己调用。
51.FileUtils主要功能及方法:
  •    writing to a file
  • reading from a file
  • make a directory including parent directories
  • copying files and directories
  • deleting files and directories
  • converting to and from a URL
  • listing files and directories by filter and extension
  • comparing file content
  • file last changed date
  • calculating a checksum 
  •  byteCountToDisplaySize显示human-readable size
  • copyFile/Directory/ 复制文件或目录
  • copy[url,inputstream]ToFile 复制url链接内容或输入流到文件
  • move/deleteDirectory
  • touch文件

52.多种过滤文件的FileFilter,CountIntput/OutPutStream可以获取已经读写的字节数,TeeInput/OutputStream可以分发读写到两个流里。
//----------------------------------------------------Commons Net--------------------------------------------------
http://commons.apache.org/proper/commons-net/
53.Net工程实现了除http外的常见网络应用协议,如FTP/FTPS,FTP over HTTP (experimental),NNTP,SMTP(S),POP3(S),IMAP(S),Telnet,TFTP,Finger,Whois,rexec/rcmd/rlogin,Time (rdate) and Daytime,Echo,Discard,NTP/SNTP等
54.官网上有一些基本的实例可以参考作为开发的依据。
//----------------------------------------------------Common HttpComponents --------------------------------------------------
http://hc.apache.org/
55. Apache HttpComponents project 即使原来的httpClient工程,原来属于commons工程,升级成一级工程后变成HttpComponents  ,并且由 HttpClient 和 HttpCore 两部分组成。
56.HttpCore is a set of low level HTTP transport components that can be used to build custom client and server side HTTP services with a minimal footprint. HttpCore supports two I/O models: blocking I/O model based on the classic Java I/O and non-blocking, event driven I/O model based on Java NIO.

The blocking I/O model may be more appropriate for data intensive, low latency scenarios, whereas the non-blocking model may be more appropriate for high latency scenarios where raw data throughput is less important than the ability to handle thousands of simultaneous HTTP connections in a resource efficient manner.


 

57.HttpClient is a HTTP/1.1 compliant HTTP agent implementation based on HttpCore. It also provides reusable components for client-side authentication, HTTP state management, and HTTP connection management. HttpComponents Client is a successor of and replacement for Commons HttpClient 3.x. Users of Commons HttpClient are strongly encouraged to upgrade.
58.还有一个异步的httpClient, a HTTP/1.1 compliant HTTP agent implementation based on HttpCore NIO and HttpClient components. It is a complementary module to Apache HttpClient intended for special cases where ability to handle a great number of concurrent connections is more important than performance in terms of a raw data throughput.
59.WebDav基于http协议,允许客户端管理和锁定webserver上的资源,目前slide已经退役,新的配置webdav的是Jackrabbit
//----------------------------------------------------Commons jxpath--------------------------------------------------
http://commons.apache.org/proper/commons-jxpath/apidocs/index.html
60.jxpath可以用xpath语法来操作JavaBeans, Maps, Servlet contexts, DOM 等多种数据集合。













Jakarta Commons Cookbook

标签:

原文地址:http://www.cnblogs.com/dimmacro/p/4459783.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!