??xml version="1.0" encoding="utf-8" standalone="yes"?> 基本程 例子: 文档搜烦l果的主要排序依据是文档的分倹{改变文档分值的Ҏ(gu)是徏立烦引时Q在初始化Document对象后,使用Document的setBoostҎ(gu)来改变文档的boost因子Q分值的倍数Q? 构徏Query: 关键字TermQuery l合查询BooleanQuery BooleanQuery的addҎ(gu)的第二,W三参数说明Q第二参数表C是否必LIW三参数表示是否不需要满Il合一h以下三种情况: 范围搜烦RangeQuery 前缀PrefixQuery 多关键字PhraseQuery 短词~PhrasePrefixQuery 相近词FuzzyQuery 通配WWildcardQuery QueryParserc?把用户各U输入{为Query 另外QQueryParser构造时需要一个分析器Q它应该与徏立烦引时的分析器一?/p>
QueryParser?#8220;?#8221;?#8220;?#8221; 排序及多字段查找 默认情况?IndexSearchercȝsearchҎ(gu)q回查询l果?是按文档的分值排序的,可以使用重蝲的searchҎ(gu)对结果排?/p>
IndexSearcher.search(Query,Sort); new Sort() ?Sort.RELEVANCE,以及null一?采用默认排序,要定义排序字D?Ҏ(gu)是将字段传入Sort对象 Sort sort = new Sort(String field); 也可以对多个字段排序Sort sort = new Sort(String[] fields); ? Sort sort = new Sort(new SortField[]{new SortField(“title”),new SortField(“name”)}); Hits hits=searcher.search(query,Sort); 多字D|找MultiFieldQueryParser 只在某些Term中查?不关心在哪个字段 Query query = new MultiFieldQueryParser.parse(“word”,new String[]{“title”,”content”},analyzer); //在title和content中找word 多字D|默认是OR关系,要改变它,使用以下Ҏ(gu): Query query = MultiFieldQueryParser.parse(“word”,new
String[]{“title”,”content”},new
int[]{MultiFieldQueryParser.REQUIRED_FIELD,MultiFieldQueryParser.PROHIBITED_FIELD},analyzer); 其中: REQUIRED_FIELD 表示该条件必L PROHIBITED_FIELD 表示必须不含 ?strong> 索多个烦引文件MultiSearcher 1) 建立多个索引:使用不同的烦引目?实例化不同的IndexWriter 2) 建立多烦引搜索器: Searcher[] searchers = new SEARCHER[2]; Searchers[0] = new IndexSearcher(dir1); //搜烦索引目录一 Searchers[1]= new IndexSearcher(dir2);//搜烦索引目录?/p>
Searcher searcher = new MultiSearcher(serarchers); 3) 开始查?Hits hits = searcher.search(query);
最q要做一个站内的全文索功能,主要是针?
clob
字段的,于是ȝ上找了点
lucene
的资料,现在新版本的?
2.0.0
Q网上的例子多是
1.4.3
的,有些Ҏ(gu)已经废弃了,搞了
n
久终于把
2.0.0
的功能实CQ呵呵,下面把实现的代码贴出来,实现了烦引的创徏、检索和删除功能Qƈ可以从检索结果去查询数据?
~
//
创徏索引
public void indexFiles() {
//
创徏索引文g存放路径
File indexDir = new File("E:\\lucene_Learning\\lucene-
try {
Date start = new Date();
//
创徏分析?
,
主要用于从文本中抽取那些需要徏立烦引的内容
,
把不需要参与徏索引的文本内容去?
.
//
比如L一?
a the
之类的常用词
,
q有军_是否大小写敏?
.
StandardAnalyzer standardAnalyzer = new StandardAnalyzer();
//
参数
true
用于定是否覆盖原有索引?
IndexWriter indexWriter = new IndexWriter(indexDir, standardAnalyzer, true);
indexWriter.setMergeFactor(100);
indexWriter.setMaxBufferedDocs(100);
//
只烦引这?
Field
的前
5000
个字Q默认ؓ
10000
indexWriter.setMaxFieldLength(5000);
//
从数据库取出所有纪?
List articleList = articleManager.getArticles(null);
for (int i = 0; i < articleList.size(); i++) {
Article article = (Article) articleList.get(i);
//
?
Document
Ҏ(gu)是创建烦引的具体代码
Document doc = Document(article);
indexWriter.addDocument(doc);
}
// Optimize
的过E就是要减少剩下?
Segment
的数?
,
量让它们处于一个文件中
.
indexWriter.optimize();
indexWriter.close();
Date end = new Date();
System.out.println("create index: " + (end.getTime() - start.getTime()) + " total milliseconds");
} catch (IOException e) {
System.out.println(" caught a " + e.getClass() + "\n with message: " + e.getMessage());
}
}
public static Document Document(Article article)
throws java.io.IOException {
Document doc = new Document();
//
?
article
表的d创徏索引Q关?
Field
的几个参C面有详细解释
Field fieldId = new Field("uid", article.getArticleId(), Field.Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.YES);
//
?
detail
字段创徏索引Q?
detail
?
DB
中是
clob
字段Q内容ؓ
html
文本
String contentHtml = article.getDetail();
Reader read = new StringReader(contentHtml);
//
?
HTMLParser
?
detail
字段中的
HTML
分析成文本在索引
// HTMLParser
q个cd以在
lucene
?
demo
中找?
HTMLParser htmlParser = new HTMLParser(read);
BufferedReader breader = new BufferedReader(htmlParser.getReader());
String htmlContent ="";
String tempContent = breader.readLine();
while (tempContent != null && tempContent.length() > 0) {
htmlContent = htmlContent + tempContent;
tempContent = breader.readLine();
}
Field fieldContents = new Field("content", htmlContent,
Field.Store.COMPRESS, Field.Index.TOKENIZED,Field.TermVector.YES);
// db
中的每条U录对应一?
doc
Q每个字D对应一?
field
doc.add(fieldId);
doc.add(fieldContents);
return doc;
}
//
搜烦文gQ?
keyword
是你在页面上输入的查扑օ键字Q这里查扄?
detail
字段
public List searchFiles(String keyword){
String index = "E:\\lucene_Learning\\lucene-
// hitsList
用来保存
db
的纪录,q些U录可以通过查询l果取到
List hitsList = new ArrayList();
try {
Date start = new Date();
IndexReader reader = IndexReader.open(index);
Searcher searcher = new IndexSearcher(reader);
Analyzer analyzer = new StandardAnalyzer();
QueryParser parser = new QueryParser("content", analyzer);
//
解析查询关键字,比如输入的是以空格等分开的多个查询关键字Q这里解析后Q可以多条g查询
Query query = parser.parse(keyword);
// hits
用来保存查询l果Q这里的
hits
相当?
sql
中的
result
Hits hits = searcher.search(query);
for (int i = 0; i < hits.length(); i++) {
Document doc = hits.doc(i);
//
获得
article
表的d
String id = doc.get("uid");
//
Ҏ(gu)d?
db
中取U录Q返回到
hitsList
?
try {
Article article = articleManager.getArticle(id);
} catch (ObjectRetrievalFailureException e) {
article = null;
}
//
如果没有扑ֈ该纪录,表示该纪录已l不存在Q不必添加到
hitsList
?
if(article!=null) hitsList.add(article);
}
searcher.close();
reader.close();
Date end = new Date();
System.out.println("search files: " + (end.getTime() - start.getTime()) + " total milliseconds");
} catch (IOException e) {
System.out.println(" caught a " + e.getClass() + "\n with message: " + e.getMessage());
} catch (ParseException e) {
System.out.println(" caught a " + e.getClass() + "\n with message: " + e.getMessage());
}
return hitsList;
}
//
删除索引
public void deleteIndex(){
String index = "E:\\lucene_Learning\\lucene-
try {
Date start = new Date();
IndexReader reader = IndexReader.open(index);
int numFiles = reader.numDocs();
for (int i = 0; i < numFiles; i++) {
//
q里的删除只是给文档做一个删除标讎ͼ你可以看到执?
deleteDocument
后会产生一?
del
后缀的文Ӟ
//
用来记录q些标记q的文g
reader.deleteDocument(i);
}
reader.close();
Date end = new Date();
System.out.println("delete index: " + (end.getTime() - start.getTime()) + " total milliseconds");
} catch (IOException e) {
System.out.println(" caught a " + e.getClass() + "\n with message: " + e.getMessage());
}
}
//
恢复已删除的索引
public void unDeleteIndex(){
String index = "E:\\lucene_Learning\\lucene-
try {
IndexReader reader = IndexReader.open(index);
reader.undeleteAll();
reader.close();
} catch (IOException e) {
System.out.println(" caught a " + e.getClass() + "\n with message: " + e.getMessage());
}
}
Field
像我们学过的数据库中的字段Q简单的_是一个名值对。这个域有三U属性,分别?
isStored -
是否被存?
q些属性的l合又构成了四种不同cd?
Field
Q而且各有用?
Stored
Indexed
Tokenized
Keyword
Y
Y
N
UnIndexed
Y
N
N
UnStored
N
Y
Y
Text: String
Y
Y
Y
Text : Reader
N
Y
Y
关于
Field
Q?
2.0.0
版本?
1.4.3
版本Ҏ(gu)相比改动比较大,具体见下?
1.4.3
版本中的下面Ҏ(gu)都被
Field(String name, String value, Store store, Index index, TermVector termVector)
取代
Keyword(String name, String value) // only version
存储、烦引、不分词Q用?
URI
Q比?
MSN
聊天记录的日期域、比?
MP3
文g的文件全路径{等Q?
UnIndexed(String name, String value) // only version
存储、不索引、不分词Q比如文件的全\?
UnStored(String name, String value) // only version
不存储、烦引、分词,比如
HTML
的正文?
Word
的内容等{,q部分内Ҏ(gu)要被索引的,但是׃具体内容通常很大Q没有必要再q行存储Q可以到时候根?
URI
再来挖取。所以,q部分只分词、烦引,而不存储?
Text(String name, String value) // only version
存储、烦引、分词,比如文g的各U属性,比如
MP3
文g的歌手、专辑等{?
Field.Store.YES,
Field(String name, String value,Field.Index.TOKENIZED)// version 2.0.0
Text(String name, Reader value) // only version
1?nbsp;初始化IndexSearcher :Searcher searcher = new IndexSearcher(indexDir);//indexDir为烦引存放\?br>
2?nbsp;生成Query对象: QueryParsercȝparse()Ҏ(gu)q回QuerycdŞ对象
3?nbsp;使用search(Query)Ҏ(gu)Q开始搜索,q返回Hits对象
4?nbsp;使用Hits对象的方法检索结?
length();//l果L?br>
doc(int n);//q回Wn个文?Document对象
id(int n);//Wn个文档的内部ID
score(n);//Wn个文档的分|用于排序
IndexSearcher searcher = new IndexSearcher(“c:\\index”);
Query query = QueryParser.parse(“key1”,”name”,new StandardAnalyzer());
Hits hits = searcher.search(query);
If(hits.length()==0){
Out.println(“not found”);
}
else{
for(int i=0;i Document d = hits.doc(i);
Out.println(d.get(“title”));
}
}
Document doc = new Document();
Doc.add(Field.Text(“contents”,”text1 text2”));
Doc.setBoost(1.5f); //改变因子Q如0.3f,1.0f{?/p>
Query是search包中的一个抽象类Q它有许多子c,代表不同cdŞ的查?br>
Term term = new Term(“contents”,”java”);//实质也是一个键/值对
//构造TermQuery
Query query = new TermQuery(term);
BooleanQuery是一个查询容器,提供专门的方法往其中加入查询Qƈ标明条g的关p?br>
IndexSearcher searcher = new IndexSearcher(“c:\\index”);
Query q1 = new TermQuery(new Term(“name”,”tim”));
Query q2 = new TermQuery(new Term(“name”,”fly”));
//构造容?br>
Query query = new BooleanQuery();
query.add(q1,true,false);
query..add(q2,true,false);
Hits hits = searcher.search(query);
True,false:当前查询条g是必要满?br>
False ,true:当前查询是不可以满?br>
False,false:条g是可选的
True,true:q种情况是错误的
以上表明Q上qC子的两个条g都是必须满的,?#8220;?and)”的关p?br>
如果查进?#8220;或(orQ?#8221;q算Q相应地可改?
query.add(q1,false,false);
query.add(q2,false,false)
RangeQuery query = new RangeQuery(begin,end,included);//最后参Cؓ是否包含边界
?
Term begin = new Term(“time”,”20050101”);
Term end = new Term(“time”,”20050202”);
RangeQuery query = new RangeQuery(begin,end,false);
PrefixQuery query = new PrefixQuery(new Term(“name”,”ti”));//name字段中以ti开?/p>
PhraseQuery query = new PhraseQuery();
Query.add(new Term(“content”,”hello”));
Query.add(new Term(“content”,”world”));
Query.setSlop(2);
//讄以上加上的两个关键字坡度,此g表两个关键字之间无关词的个数.对于两个紧连的关键字Q无论将坡度设ؓ多少都能扑ֈQ如果两个词不紧q,且坡度值小于它们之间的无关词的数量Q则无法扑ֈ
Term word1 = new Term(“content”,”david”);
Term word2 = new Term(“content”,”mary”);
Term word3 = new Term(“content”,”robert”);
PhrasePrefixQuery query = new PhrasePrefixQuery();
//加入不确定的?br>
Query.add(new Term[]{word1,word2});//不确定,W一个关键词在Term数组中?br>
//加入定的词
query.add(word3);
query.setSlop(2);//讄坡度
//以上查询中,david robert和mary robert都会出现在查询结?同样圎ͼmary and robert也会被击?/p>
FuzzyQuery query = new FuzzyQuery(new Term(“content”,”david”));
WildcardQuery query = new WildcardQuery(new Term(“content”,”*im”));
WildcardQuery query = new WildcardQuery(new Term(“content”,”t?m??”));
//*代表0个或多个字符Q?一个字W?/p>
Query query = QueryParser.parse(keywords,filedName,new StandardAnalyer());
关键字格?
“tim” //在默认字D|索tim
“name:tim”;//在name字段搜tim
“tim wong”或tim or wong;//在默认字D|搜关键字tim 或wong
“+tim +wong”?#8221;tim and wong” //搜烦tim?wong
”tim*”//在默认字D中搜前~为tim?br>
“name:tim is a programer”;//在name字段中包含短语tim is a programer
“(tim or wong) and php” //在默认字D中搜含有tim 或wong的关键字Q但一定要包含php
“name:tim –title:php” //name字段搜tim,q且title不含有php
当输入两个关键字Ӟ默认关系是或Q要改变q种关系Q方法是:
QueryParser parser = new QueryParser(keyword,fieldNmae,new StandardAnalyzer());
Parser.setOperator(QueryParser.DEFAULT_OPERATOR_AND);
]]>
isIndexed -
是否被烦?
isTokenized -
是否分词
Field(String name, String value, Field.Store.YES, Field.Index.UN_TOKENIZED) // version 2.0.0
Field(String name, String value,Field.Store.YES, Field.Index.NO)// version 2.0.0
Field(String name, String value,Field.Store.YES, Field.Index.TOKENIZED)// version 2.0.0
不存储、烦引、分词?
]]>
String str = null;
if(StringUtils.isEmpty(str)){
}
str = StringUtils.lowerCase(str);
str = StringUtils.capitalize(str);
str = StringUtils.swapCase(str);
StringUtils.isNumeric(str);
StringUtils.isAsciiPrintable(str);
StringUtils.equalsIgnoreCase(str,"");
其中Q?br /> if(StringUtils.isEmpty(str)){
}
相当?br /> if(str == null || str.length() == 0){
}
从以上代码可以看个工L的特点:
W一、这些函数都是静态函敎ͼq且很少抛出异常Q也很少抛出控制针异常?br /> W二、这些函数的功能大多是增强标?Java ?java.lang.String cȝ功能?/p>
其实Q整?lang 包的函数基本上都在增?java.lang 包的功能。一个有的设计是,虽然 StringUtils 里面的函数都是静态函敎ͼ按照通常的做法,会把构造函数设计成 private, 但是不!StringUtils 的构造函数是 public 的。构造函数里面的注释写着 "no init"。这有意思了Q你可以 new 一?StringUtilsQ虽然没有特别的好处Q但是也没有特别的坏处;你可以写一?StringUtils 的子c,虽然q也不太常见。这里面的思想g是,使用q个工具包的软g开发h员想怎么用就怎么用,做工L的时候不用太多限制?br /> 至于不抛异常是因为现在很多h已经意识?Java 中的异常不是什么好东西Q如果不用异怹能写E序Qؓ什么还要用异常Q用了异常就要写很多 try catchQ在很多场合Q比?jdbc driverQ这已经证明了会使代码量增加q且代码的可L变差?br /> q里的思\会不会媄响大家写E序的习惯呢Q?/p>
StringUtils 的函数很多,不一一列D?Lang 中次重要的类要数 ArrayUtilsQ主要功能涉及到数组的比较、{换、拆分、合q、查找、增减、倒{{等操作。在 JDK 中,q类操作没有现成的函数?/p>
Lang 中工L比较多,q里介绍几个主要的:
ClassUtils getShortClassNameQ这个函数应该在 java.lang.Class cM有的Q我看到很多己写q个函数。getAllInterfacesQconvertClassNamesToClassesQisAssignableQprimitivesToWrappersQisInnerClass?br /> NumberUtils 关于数字以及数字和字W串转换的类 stringToIntQtoDoubleQcreateNumberQisAllZerosQ?int compare(float lhs, float rhs)Q?isNumber(String str)Qdouble min(double[] array)?br /> RandomUtils 用于产生随机数的?br /> DateFormatUtils 日期旉格式转换Q以及本地时间和 UTC 旉转换?br /> DateUtils 日期工具cRisSameDayQtruncateQroundQmodify?/p>
Z反射机制的几个类Q?br /> CompareToBuilder 比较Q用在算法、排序、比较的地方。reflectionCompareQappend?br /> EqualsBuilder 通过反射机制比较。reflectionEquals 很多目中用到?br /> HashCodeBuilder 可以通过反射生成 hash codeQ很多算法的地方涉及?hash codeQ但是ƈ不是每个人都知道一U?hash code 的生成方法?
ToStringBuilder 当你需要重?toString 函数而不惛_代码把当前类的所有成员信息列出来Q可以用q个函数?/p>
其它的几个类我用得比较少Q?br /> SerializationUtils Java 中得序列化比较奥妙,Ҏ(gu)出错啊?br /> SystemUtils 可以d一些关?jdk 信息Q操作系l信息的工具cR?/p>
W一ơ接?/span> BeanUtils 是在学习 Struts 的过E中Q在 Struts 中它被大量用于处?/span> FormBean ?/span>
BeanUtils 主要提供了对?/span> JavaBean q行各种操作Q?/span>
BeanUtils 一共分 4 个包Q?/span>
Ø org.apache.commons.beanutils
Ø org.apache.commons.beanutils.converters
Ø org.apache.commons.beanutils.locale
Ø org.apache.commons.beanutils.locale.converters
其中上面两个?/span> BeanUtils 的默认实玎ͼ它没有针Ҏ(gu)地化的Q何处理,q个可以提高执行效率。但是若你的E序对于本地化有要求的话Q那q是使用下面 2 个包比较安全?/span>
2. org.apache.commons.beanutils
q个包主要提供用于操?/span> JavaBean 的工LQ?/span> Jakarta-Common-BeanUtils 的主要功能都在这个包里实现?span lang="EN-US">
下面分别介绍几个主要的工LQ?/span>
1 、首先,我先定义一?/span> JavaBean 作ؓ之后例子的操作对象?/span>
public class Company
{
private String name;
private HashMap address = new HashMap();
private String[] otherInfo;
private ArrayList product;
private ArrayList employee;
private HashMap telephone;
public Company(){}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAddress(String type)
{
return address.get(type).toString();
}
public void setAddress(String type, String address)
{
this.address.put(type,address);
}
public String[] getOtherInfo()
{
return otherInfo;
}
public void setOtherInfo(String[] otherInfo)
{
this.otherInfo = otherInfo;
}
public ArrayList getProduct()
{
return product;
}
public void setProduct(ArrayList product)
{
this.product = product;
}
public ArrayList getEmployee()
{
return employee;
}
public void setEmployee(ArrayList employee)
{
this.employee = employee;
}
public HashMap getTelephone()
{
return telephone;
}
public void setTelephone(HashMap telephone)
{
this.telephone = telephone;
}
}
2 ?/span> BeanUtils 可以直接 get ?/span> set 一个属性的倹{它?yu)?/span> property 分成 3 U类型:
Simple ——简单类型,?/span> Stirng ?/span> Int …?/span>
Indexed ——烦引类型,?/span> 数组?/span> arrayList …?/span>
Maped ——这个不用说也该知道Q就是指 Map 啦,比如 HashMap …?/span>
讉K不同cd的数据可以直接调用函?/span> getProperty ?/span> setProperty 。它们都只有 2 个参敎ͼW一个是 JavaBean 对象Q第二个是要操作的属性名?/span>
Company c = new Company();
c.setName("Simple");
对于 Simple cdQ参C直接是属性名卛_
//Simple
System.out.println(BeanUtils.getProperty(c, "name"));
对于 Map cdQ则需要以“属性名Q?/span> key |”的形式
//Map
System.out.println(BeanUtils.getProperty(c, "address (A2)"));
HashMap am = new HashMap();
am.put("1","234-222-1222211");
am.put("2","021-086-1232323");
BeanUtils.setProperty(c,"telephone",am);
System.out.println(BeanUtils.getProperty(c, "telephone (2)"));
对于 Indexed Q则为“属性名 [ 索引?/span> ] ”,注意q里对于 ArrayList 和数l都可以用一L方式q行操作?/span>
//index
System.out.println(BeanUtils.getProperty(c, "otherInfo[2]"));
BeanUtils.setProperty(c, "product[1]", "NOTES SERVER");
System.out.println(BeanUtils.getProperty(c, "product[1]"));
当然q?/span> 3 U类也可以组合用啦Q?/span>
//nest
System.out.println(BeanUtils.getProperty(c, "employee[1].name"));
3 、此外,q有一个很重要的方?/span> copyProperty Q可以直接进?/span> Bean 之间?/span> clone ?/span>
Company c2 = new Company();
BeanUtils.copyProperties(c2, c);
但是q种 copy 都是拷贝,复制后的 2 ?/span> Bean 的同一个属性可能拥有同一个对象的 ref Q这个在使用时要心Q特别是对于属性ؓ自定义类的情c?/span>
4 、最后还?/span> populate Q它用于一?/span> map 的值填充到一?/span> bean 中,其函数原型如下:
public void populate(java.lang.Object bean,
java.util.Map properties)
throws java.lang.IllegalAccessException,
java.lang.reflect.InvocationTargetException
?/span> struts 中这个函数被用于?/span> http request 中取得参数添加到 FormBean Q目前好像我也没有看到这个函数还有什么其他的用途?Q以后想到再说吧Q?/span> P
它实C个动态的 Bean Q可以直接往里面加入属性,作ؓ一?/span> JavaBean 一样用,也可以用上面?/span> BeanUtils ?/span> get/set Ҏ(gu)q行操作Q而不用事先定义一个标准的 JavaBean cdQ)
记得?/span> J2ee 设计模式中有一U?/span> Value Object 的模式,用于?/span> MVC 各层之间传递数据,避免直接传递大业务对象引v的性能问题Qؓ了避免在目中出现很?/span> Bean c,在书中提供了一个动?/span> Value Object 的实玎ͼ通过扩展 Map Q。这?/span> LazyDynaBean 则可以作ZU更加成熟、稳定的实现来用。呵呵,原来曾打自己写一个类似的 value object cȝQ现在看来可以直接用q个啦: P
a归正传, LazyBean 的确提供了一个很不错?/span> DynaBean 的实现。而且像它的名字中表q的那样Q它的确是ؓ我这L懒h考虑的很周到Q用h几乎不需要写什么多余的代码 ^_^ Q下面就看看使用的例子吧Q?/span>
// q里使用 LazyDynaMap Q它?/span> LazyBean 的一个轻量实现
LazyDynaMap dynaBean1 = new LazyDynaMap();
dynaBean1.set("foo", "bar"); // simple
dynaBean1.set("customer", "title", "Mr"); // mapped
dynaBean1.set("address", 0, "address1"); // indexed
System.out.println(dynaBean1.get("address",0));
Map myMap = dynaBean1.getMap(); // retrieve the Map
System.out.println(myMap.toString());
上面的例子可以看刎ͼ它可以在 set 时自动增?/span> bean ?/span> property Q既赋值的同时增加 Bean 中的 property Q,同时也支?/span> 3 中类型的 property Qƈ?/span> LazyDynaMap q可以导Zؓ map ?/span>
对于q个c还有两个重要的 Field 要注意:
returnnull ——指定在 get Ҏ(gu)使用了一个没有定义过?/span> property Ӟ DynaBean 的行为?/span>
// 取的字段的信?/span>
dynaBean1.setReturnNull(true); // 设ؓ ture 。若 Bean 中没有此字段Q返?/span> null
// 默认?/span> false 。若 Bean 中没有此字段Q自动增加一个:Q?/span>
System.out.println(dynaBean1.get("aaa")); // 此时q回 null
Restricted ——指定是否允许改变这?/span> bean ?/span> property ?/span>
//MutableDynaClass.setRestricted 设ؓ true 后,字段不可再增删和修改 .
// 默认?/span> false Q允许增删和修改
dynaBean1.setRestricted(true);
dynaBean1.set("test","error"); // q里会出错!
通过讄q两个属性,可以防止意外修改 DynaBean ?/span> property 。在设计架构Ӟ你可以在后台从数据表?/span> xml 文g自动产生 DynaBean Q在传到控制层和表示层之前设|上q属性?/span> Bean l构不允怿改,如此׃可能无意中修?/span> Bean 包含的属性……这h可以享用它的便利Q有可以防止由此引入的错误可能,设计者实在深得偷懒的_N啊!Q!Q!
3.1. BeanUtils ?/span> PropertyUtils
q两个类几乎有一怸L功能Q唯一的区别是Q?/span> BeanUtils 在对 Bean 赋值是会进行类型{化。D例来说也是?/span> copyProperty 时只要属性名相同Q就类型不同, BeanUtils 也可以进?/span> copy Q?/span> PropertyBean 则可能会报错Q!
针对上面的例子,新徏一?/span> Company2 的类Q其中代码与 Company 一P只是?/span> otherinfo ?/span> String[] 改ؓ String ?/span>
Company c = init();
Company2 c2 = new Company2();
BeanUtils.copyProperties(c2,c);
// PropertyUtils.copyProperties(c2,c); q句会报错!Q?/span>
System.out.println(c2.getOtherInfo());
当然 2 ?/span> Bean 之间的同名属性的cd必须是可以{化的Q否则用 BeanUtils 一样会报错?/span>
若实C org.apache.commons.beanutils.Converter 接口则可以自定义cd之间的{化?/span>
׃不做cd转化Q用 PropertyUtils 在速度上会有很大提高!
此外Q不作类型{化还有一个好处,如下面的代码Q?/span>
//test data type convert
// ArrayList a1 = BeanUtils.getProperty(c,"product"); //BeanUtils q回的是 String
System.out.println("--" + BeanUtils.getProperty(c,"product")); // 取出后直接被转ؓ String
ArrayList a = (ArrayList)PropertyUtils.getProperty(c,"product"); //PropertyUtils q回的是 Object
System.out.println("--" + a.get(1)) ;
?/span> BeanUtils 无法q回一个对象(除非自己写一?/span> Converter Q,它会自动q行cd转化Q然后返?/span> String 。对于想q回 java cL自定义类的话Q还是不要老它大驾转化了?/span>
3.2. Utils c?/font>
所有的 XXXUtils c都提供的是静态方法,可以直接调用Q其主要实现都在相应?/span> XXXUtilsBean 中:
BeanUtils —?span lang="EN-US">> BeanUtilsBean
ConvertUtils —?span lang="EN-US">> ConvertUtilsBean
PropertyUtils —?span lang="EN-US">> PropertyUtilsBean
DateUtils ?
?/span>
Calendar
?/span>
Date
的基上提供更方便的访问;
DurationFormatUtils ?
提供格式化时间跨度的功能及相兛_量;
FastDateFormat ?
?/span>
java.text.SimpleDateFormat
提供一个的U程安全的替代类Q?/span>
StopWatch ? 是一个方便的计时器?/span>
我们q是在一个例子中来看上述各个cȝ用法吧:
package
sean.study.jakarta.commons.lang;
import
java.util.Calendar;
import
java.util.Date;
import
org.apache.commons.lang.StringUtils;
import
org.apache.commons.lang.time.DateFormatUtils;
import
org.apache.commons.lang.time.DateUtils;
import
org.apache.commons.lang.time.FastDateFormat;
import
org.apache.commons.lang.time.StopWatch;
public
class
DateTimeUsage {
public
static
void
main(String[] args) {
demoDateUtils();
demoStopWatch();
}
public
static
void
demoDateUtils() {
System.out.println(StringUtils.center(" demoDateUtils ", 30, "="));
Date date = new Date();
String isoDateTime = DateFormatUtils.ISO_DATETIME_FORMAT.format(date);
String isoTime = DateFormatUtils.ISO_TIME_NO_T_FORMAT.format(date);
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM");
String customDateTime = fdf.format(date);
System.out.println("ISO_DATETIME_FORMAT: " + isoDateTime);
System.out.println("ISO_TIME_NO_T_FORMAT: " + isoTime);
System.out.println("Custom FastDateFormat: " + customDateTime);
System.out.println("Default format: " + date);
System.out.println("Round HOUR: " + DateUtils.round(date, Calendar.HOUR));
System.out.println("Truncate HOUR: " + DateUtils.truncate(date, Calendar.HOUR));
System.out.println();
}
public
static
void
demoStopWatch() {
System.out.println(StringUtils.center(" demoStopWatch ", 30, "="));
StopWatch sw = new StopWatch();
sw.start();
operationA();
sw.stop();
System.out.println("operationA used " + sw.getTime() + " milliseconds.");
System.out.println();
}
public
static
void
operationA() {
try
{
Thread.sleep(999);
}
catch
(InterruptedException e) {
// do nothing
}
}
}
以下是运行结果:
======= demoDateUtils ========
ISO_DATETIME_FORMAT:
ISO_TIME_NO_T_FORMAT: 12:41:51
Custom FastDateFormat: 2005-08
Default format: Mon Aug 01 12:41:51 CST 2005
Round HOUR: Mon Aug 01 13:00:00 CST 2005
Truncate HOUR: Mon Aug 01 12:00:00 CST 2005
======= demoStopWatch ========
operationA used 1000 milliseconds.