前期准备Q弄清楚weblogicQ或jbossQ、tomcat、JBluderQ或eclipseQMyEclipseQ的使用Ҏ(gu)Q能写一个简单的Zstruts框架的web工程Q然后准备两台联|的?sh)脑Q局域网也可以)Q如果没有条Ӟ也可以在同一台电(sh)脑上分别安装两个web服务器(例如Qweblogic和tomcatQ来代替Q本文将采用后一U方法,采用weblogic作EJB容器Qtomcat作web容器Q用struts工程来调用EJB
准备好了吗?让我们开始下一?/p>
W一步:写一个简单的EJB。写EJB最好用的还是JBuilderQ毕竟够?c)化。当然作Z业h士,eclipse搭配MyEclipse是最佳选择Q不q作为初学者,采用JBuilder。以下是本文试所用到的EJB?/p>
remote接口Q?/p>
package testhello;
import javax.ejb.EJBObject;
public interface SayHello extends EJBObject {
public String sayHello(String name) throws java.rmi.RemoteException;
}
home接口Q?/p>
package testhello;
import javax.ejb.EJBHome;
import javax.ejb.CreateException;
import java.rmi.RemoteException;
public interface SayHelloHome extends EJBHome {
public SayHello create() throws CreateException, RemoteException;
}
beanc:
package testhello;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.CreateException;
public class SayHelloBean implements SessionBean {
SessionContext sessionContext;
public void ejbCreate() throws CreateException {
}
public void ejbRemove() {
}
public void ejbActivate() {
}
public void ejbPassivate() {
}
public void setSessionContext(SessionContext sessionContext) {
this.sessionContext = sessionContext;
}
public String sayHello(String name) {
return "Hello "+name;
}
}
如果你是采用上面两种工具来写的话Q配|文件就不必考虑?/p>
W二步:利用JBuilder或eclipse这个EJB工程~译q打包,会得C个jar(如果你的工程名叫testhelloQ那么这个jar文g是testhello.jar)文g。如果你的EJB容器Qweblogic或JBossQ是在本ZQ那么在JBuilder或eclipse中就可以直接鼠标叛_EJB工程Q来部vEJB。如果需要部|到q程服务器上Q只需要通过EJB容器的控制台testhello.jar上传到远E端Q然后在EJB Modler里面按提C部|好EJB。最后,别忘了在JNDI Tree里面察看你的EJB工程的JNDI名,本例的JNDI名叫SayHello
W三步:remote接口和home接口打包成jar文gQcopyC要远E调用EJB的struts工程下的lib目录Q例如:helloapp ->WEB-INF ->libQ?/p>
W四步:weblogic的weblogic.jarQ在weblogic的安装目录->weblogic81Q?gt;serverQ?gt;lib文g夹中Qcopy到tomcat安装目录下的Q?gt;sharedQ?gt;lib文g夹中Q其实这里我们需要用到的只是weblogic.jar里的几个class文g而已Q不q对于初学者而言Q先不必LI到底只需要那几个class?/p>
W五步:~写一个简单的struts工程Q其实这些都可以用工L成)Q一下是调用EJB的HelloAction的源代码(特别要注意的是,记得要将之前W三步生成的jar包导入编辑器中,否则下面的代码编译通不q。如果你不知道导入jar包,把那个jar包多copy一份到你的jdk安装目录 -> jre-> lib-> ext文g夹下)
package logging.actions;
import logging.Constants;
import java.util.*;
import javax.servlet.ServletException;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.util.MessageResources;
import org.apache.struts.validator.DynaValidatorForm;
public final class HelloAction extends Action{
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception{
InitialContext ctx=this.getInitialContext();
//查找JNDI名ؓSayHello的EJBlg
Object obj=ctx.lookup("SayHello");
//获得q程EJBlg的home接口的引?br /> testhello.SayHelloHome home=(testhello.SayHelloHome)PortableRemoteObject.narrow(obj,testhello.SayHelloHome.class);
//获得q程EJBlg的remote接口的引?br /> testhello.SayHello hello=home.create();
String name="飘然随风";
String sayString=hello.sayHello(name);
request.setAttribute("userName",name);
request.setAttribute("passWord",sayString);
request.removeAttribute(mapping.getAttribute());
return mapping.findForward("loginSuccess");
}
/*以下Ҏ(gu)是作用是Q通过传递环境属性选择JNDI驱动和服务器的网l位|,
q连接到q接到JNDI树?br /> q是采用weblogic做EJB容器Ӟq程调用EJB的固定初始化模式Q初学者可以死C?br />*/
private InitialContext getInitialContext() throws Exception {
//EJB容器的地址
String url = "t3://image:7001";
String user = null;
String password = null;
Properties properties;
properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
properties.put(Context.PROVIDER_URL, url);
if (user != null) {
properties.put(Context.SECURITY_PRINCIPAL, user);
properties.put(Context.SECURITY_CREDENTIALS,
password == null ? "" : password);
}
return new javax.naming.InitialContext(properties);
}
}
W六步:如果你严格按照上面的步骤做了Q那么剩下的是同时启动weblogic和tomcat来测试了?/p>
Lucene 是一个基?Java 的全文检索工具包Q你可以利用它来Z的应用程序加入烦引和索功能。Lucene 目前是著名的 Apache Jakarta 家族中的一个开源项目,下面我们卛_学习 Lucene 的烦引机制以及它的烦引文件的l构?/p>
在这文章中Q我们首先演C如何?Lucene 来烦引文档,接着讨论如何提高索引的性能。最后我们来分析 Lucene 的烦引文件结构。需要记住的是,Lucene 不是一个完整的应用E序Q而是一个信息检索包Q它方便你ؓ你的应用E序d索引和搜索功能?/p>
图一昄?Lucene 的烦引机制的架构。Lucene 使用各种解析器对各种不同cd的文档进行解析。比如对?HTML 文档QHTML 解析器会做一些预处理的工作,比如qo文档中的 HTML 标签{等。HTML 解析器的输出的是文本内容Q接着 Lucene 的分词器(Analyzer)从文本内容中提取出烦引项以及相关信息Q比如烦引项的出现频率。接着 Lucene 的分词器把这些信息写到烦引文件中?/p>
图一QLucene 索引机制架构
![]() ![]() |
![]()
|
接下来我一步一步的来演C如何利?Lucene Z的文档创建烦引。只要你能将要烦引的文g转化成文本格式,Lucene pZ的文档徏立烦引。比如,如果你想?HTML 文档或?PDF 文档建立索引Q那么首先你需要从q些文档中提取出文本信息Q然后把文本信息交给 Lucene 建立索引。我们接下来的例子用来演C如何利?Lucene 为后~名ؓ txt 的文件徏立烦引?/p>
1Q?准备文本文g
首先把一些以 txt 为后~名的文本文g攑ֈ一个目录中Q比如在 Windows q_上,你可以放?C:\\files_to_index 下面?/p>
2Q?创徏索引
清单1是ؓ我们所准备的文档创建烦引的代码?/p>
清单1Q用 Lucene 索引你的文档
|
正如清单1所C,你可以利?Lucene 非常方便的ؓ文档创徏索引。接下来我们分析一下清?中的比较关键的代码,我们先从下面的一条语句开始看赗?/p>
|
q条语句创徏了类 StandardAnalyzer 的一个实例,q个cL用来从文本中提取出烦引项的。它只是抽象c?Analyzer 的其中一个实现。Analyzer 也有一些其它的子类Q比?SimpleAnalyzer {?/p>
我们接着看另外一条语句:
|
q条语句创徏了类 IndexWriter 的一个实例,该类也是 Lucene 索引机制里面的一个关键类。这个类能创Z个新的烦引或者打开一个已存在的烦引ƈ所引添加文档。我们注意到该类的构造函数接受三个参敎ͼW一个参数指定了存储索引文g的\径。第二个参数指定了在索引q程中用什么样的分词器。最后一个参数是个布?yu)变量,如果gؓ真,那么pC创徏一个新的烦引,如果gؓ假,pC打开一个已l存在的索引?/p>
接下来的代码演示了如何添加一个文档到索引文g中?/p>
|
首先W一行创Zc?Document 的一个实例,它由一个或者多个的?Field)l成。你可以把这个类惌成代表了一个实际的文档Q比如一?HTML 面Q一?PDF 文档Q或者一个文本文件。而类 Document 中的域一般就是实际文档的一些属性。比如对于一?HTML 面Q它的域可能包括标题Q内容,URL {。我们可以用不同cd?Field 来控制文档的哪些内容应该索引Q哪些内容应该存储。如果想获取更多的关?Lucene 的域的信息,可以参?Lucene 的帮助文档。代码的W二行和W三行ؓ文档d了两个域Q每个域包含两个属性,分别是域的名字和域的内容。在我们的例子中两个域的名字分别?content"?path"。分别存储了我们需要烦引的文本文g的内容和路径。最后一行把准备好的文档dC索引当中?/p>
当我们把文档d到烦引中后,不要忘记关闭索引Q这h保证 Lucene 把添加的文档写回到硬盘上。下面的一句代码演CZ如何关闭索引?/p>
|
利用清单1中的代码Q你可以成功的文本文档添加到索引中去。接下来我们看看对烦引进行的另外一U重要的操作Q从索引中删除文档?/p>
![]() ![]() |
![]()
|
cIndexReader负责从一个已l存在的索引中删除文档,如清?所C?/p>
清单2Q从索引中删除文?/b>
|
在清?中,W二行用静态方?IndexReader.open(indexDir) 初始化了c?IndexReader 的一个实例,q个Ҏ(gu)的参数指定了索引的存储\径。类 IndexReader 提供了两U方法去删除一个文档,如程序中的第三行和第四行所C。第三行利用文档的编h删除文档。每个文档都有一个系l自动生成的~号。第四行删除了\径ؓ"C:\\file_to_index\lucene.txt"的文档。你可以通过指定文g路径来方便的删除一个文档。值得注意的是虽然利用上述代码删除文档使得该文档不能被索到Q但是ƈ没有物理上删除该文档。Lucene 只是通过一个后~名ؓ .delete 的文件来标记哪些文档已经被删除。既然没有物理上删除Q我们可以方便的把这些标Cؓ删除的文档恢复过来,如清?3 所C,首先打开一个烦引,然后调用Ҏ(gu) ir.undeleteAll() 来完成恢复工作?/p>
清单3Q恢复已删除文档
|
你现在也许想知道如何物理上删除烦引中的文档,Ҏ(gu)也非常简单。清?4 演示了这个过E?/p>
清单4Q如何物理上删除文档
|
在清?4 中,W三行创Zc?IndexWriter 的一个实例,q且打开了一个已l存在的索引。第 4 行对索引q行清理Q清理过E中把所有标Cؓ删除的文档物理删除?/p>
Lucene 没有直接提供Ҏ(gu)Ҏ(gu)档进行更斎ͼ如果你需要更C个文档,那么你首先需要把q个文档从烦引中删除Q然后把新版本的文档加入到烦引中厅R?/p>
![]() ![]() |
![]()
|
利用 LuceneQ在创徏索引的工E中你可以充分利用机器的g资源来提高烦引的效率。当你需要烦引大量的文gӞ你会注意到烦引过E的瓉是在往盘上写索引文g的过E中。ؓ了解册个问? Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢?q运的是QLucene 的类 IndexWriter 提供了三个参数用来调整缓冲区的大以及往盘上写索引文g的频率?/p>
1Q合q因子(mergeFactorQ?/p>
q个参数军_了在 Lucene 的一个烦引块中可以存攑֤文档以及把盘上的索引块合q成一个大的烦引块的频率。比如,如果合ƈ因子的值是 10Q那么当内存中的文档数达?10 的时候所有的文档都必d到磁盘上的一个新的烦引块中。ƈ且,如果盘上的索引块的隔数辑ֈ 10 的话Q这 10 个烦引块会被合ƈ成一个新的烦引块。这个参数的默认值是 10Q如果需要烦引的文档数非常多的话q个值将是非怸合适的。对批处理的索引来讲Qؓq个参数赋一个比较大的g得到比较好的索引效果?/p>
2Q最合q文档数
q个参数也会影响索引的性能。它军_了内存中的文档数臛_辑ֈ多少才能它们写回磁盘。这个参数的默认值是10Q如果你有够的内存Q那么将q个值尽量设的比较大一些将会显著的提高索引性能?/p>
3Q最大合q文档数
q个参数军_了一个烦引块中的最大的文档数。它的默认值是 Integer.MAX_VALUEQ将q个参数讄为比较大的值可以提高烦引效率和索速度Q由于该参数的默认值是整型的最大|所以我们一般不需要改动这个参数?/p>
清单 5 列出了这个三个参数用法,清单 5 和清?1 非常怼Q除了清?5 中会讄刚才提到的三个参数?/p>
清单5Q提高烦引性能
|
通过q个例子Q我们注意到在调整缓冲区的大以及写盘的频率上?Lucene l我们提供了非常大的灉|性。现在我们来看一下代码中的关键语句。如下的代码首先创徏了类 IndexWriter 的一个实例,然后对它的三个参数进行赋倹{?/p>
|
下面我们来看一下这三个参数取不同的值对索引旉的媄响,注意参数值的不同和烦引之间的关系。我们ؓq个实验准备?10000 个测试文档。表 1 昄了测试结果?/p>
?Q测试结?/b>
通过?1Q你可以清楚地看C个参数对索引旉的媄响。在实践中,你会l常的改变合q因子和最合q文档数的值来提高索引性能。只要你有够大的内存,你可以ؓ合ƈ因子和最合q文档数q两个参数赋量大的g提高索引效率Q另外我们一般无需更改最大合q文档数q个参数的|因ؓpȝ已经默认它讄成了最大?/p>
![]() ![]() |
![]()
|
在分?Lucene 的烦引文件结构之前,我们先要理解反向索引QInverted indexQ这个概念,反向索引是一U以索引ؓ中心来组l文档的方式Q每个烦引项指向一个文档序列,q个序列中的文档都包含该索引V相反,在正向烦引中Q文档占据了中心的位|,每个文档指向了一个它所包含的烦引项的序列。你可以利用反向索引L的找到那些文档包含了特定的烦引项。Lucene正是使用了反向烦引作为其基本的烦引结构?/p>
![]() ![]() |
![]()
|
在Lucene 中有索引块的概念Q每个烦引块包含了一定数目的文档。我们能够对单独的烦引块q行索。图 2 昄?Lucene 索引l构的逻辑视图。烦引块的个数由索引的文档的L以及每个索引块所能包含的最大文档数来决定?/p>
?Q烦引文件的逻辑视图
![]() ![]() |
![]()
|
下面的部分将会分析Lucene中的主要的烦引文Ӟ可能分析有些索引文g的时候没有包含文件的所有的字段Q但不会影响到对索引文g的理解?/p>
1Q烦引块文g
q个文g包含了烦引中的烦引块信息Q这个文件包含了每个索引块的名字以及大小{信息。表 2 昄了这个文件的l构信息?/p>
?Q烦引块文gl构
2Q域信息文g
我们知道Q烦引中的文档由一个或者多个域l成Q这个文件包含了每个索引块中的域的信息。表 3 昄了这个文件的l构?/p>
?Q域信息文gl构
3Q烦引项信息文g
q是索引文g里面最核心的一个文Ӟ它存储了所有的索引的g及相关信息,q且以烦引项来排序。表 4 昄了这个文件的l构?/p>
?Q烦引项信息文gl构
4Q频率文?/p>
q个文g包含了包含烦引项的文档的列表Q以及烦引项在每个文档中出现的频率信息。如果Lucene在烦引项信息文g中发现有索引和搜烦词相匚w。那?Lucene ׃在频率文件中找有哪些文g包含了该索引V表5昄了这个文件的一个大致的l构Qƈ没有包含q个文g的所有字Dc?/p>
?Q频率文件的l构
5Q位|文?/p>
q个文g包含了烦引项在每个文档中出现的位|信息,你可以利用这些信息来参与对烦引结果的排序。表 6 昄了这个文件的l构
到目前ؓ止我们介l了 Lucene 中的主要的烦引文件结构,希望能对你理?Lucene 的物理的存储l构有所帮助?/p>
![]() ![]() |
![]()
|
目前已经有非常多的知名的l织正在使用 LuceneQ比如,Lucene ?Eclipse 的帮助系l,ȝ理工学院?OpenCourseWare 提供了搜索功能。通过阅读q篇文章Q希望你能对 Lucene 的烦引机制有所了解Qƈ且你会发现利?Lucene 创徏索引是非常简单的事情?/p>
一、absoluteChildNumber
含义Q返回结点相对于它所有的兄弟Q不论名字是否相同)的序受?/p>
语法QabsoluteChildNumber(node)
参数Qnode ── 对象Q欲q回~号的结炏V?/p>
CZQ?/p>
1、假定文档结构ؓQ?lt;document><head/><body/></document>Q其中document为顶层结点,下述表达式将输出Q?/p>
<xsl:eval>
absoluteChildNumber(this.selectNodes('/document/body').item(0))
</xsl:eval>
2、确定当前结点相对于其所有兄弟的序号Q?/p>
<xsl:eval>
absoluteChildNumber(this)
</xsl:eval>
二、ancestorChildNumber
含义Q从l定l点出发Ҏ(gu)l定先l点名返回最q的先l点的序P相对于同名结点)。如果找不祖先,则返??/p>
语法QancestorChildNumber(bstrNodeName, pNode)
参数Q?/p>
bstrNodeName ── 字符丌Ӏ被搜烦的祖先结点的名字?/p>
pNode ── 对象。搜索开始位|的l点?/p>
CZ查找当前l点最q的名ؓreport先l点Q?/p>
ancestorChildNumber('report',this)
三、attributes
含义Q返回结点属性的集合?/p>
语法Qobject.attributes
参数Qobject ── l点对象?/p>
CZQ当前结点属性的个数
this.attributes.length
当前l点W三个属性的?/p>
this.attributs.item(2).value
?br />
this.attributes.item(2).text
?br />
this.attributes(2).text
注意Q如果给定的下标大于属性d?出错,W一个属性的下标??/p>
四、baseName
含义Q返回有名字I间限制的基本名Q即不包括名字前~?/p>
语法Qobject.baseName
参数Qobject ── l点对象
CZQ当前结点的基本名:
this.baseName
五、childNumber
含义Q返回结点相对于同名同胞(yu)的序受?/p>
语法QchildNumber(object)
参数Qobject ── l点对象
CZQ假定XML文档l构如下Q?/p>
<x><y><z></z></y></x>
如果当前l点是zQ则childNumber(this)q回1Q而absoluteChildNumber(this)q回3?
六、dataType
含义Q设定或dl点的数据类型?/p>
语法Q设定结点的数据cd object.dataType=objValue
dl点的数据类?objValue=object.dataType
参数Qobject ── l点对象?br />
CZQ读取当前结点的数据cdQ?/p>
dtType=this.dataType
七、depth
含义Q指定结点出现在文档树上的深度,卌l点位于文档W几层,层l点位于W一层,根结点(即用"/"表示的结点)位于W?层?/p>
语法Qdepth(pNode)
参数QpNode ── l点对象
CZQ当前结点的深度Q?/p>
depth(this)
八、firstChild、lastChild
含义Q返回结点的W一个子l点Q或最后一个子l点Q?/p>
语法QpNode.firstChild
pNode.lastChild
参数QpNode ── l点对象
CZQ当前结点的W一个结点的名字Q?/p>
this.firstChild.nodeName
?ji)、formatIndex
含义Q用指定的计数系l格式化提供的整数?/p>
语法QformatIndex(lIndex, bstrFormat)
参数Q?/p>
lIndex ── 整型数值或变量
bstrFormat ── 数据格式Q可选值有a、A、i、I??1Q以0打头的数值Ş式,如果要求固定长度的编号如0001?002则非常有用)?/p>
CZQ当前结点的大写|马数字~号Q?/p>
formatIndex(childNumber(this),'I')
十、formatNumber
含义Q以指定格式输出数倹{?/p>
语法QformatNumber(dblNumber, bstrFormat)
参数Q说明同formatNumberQ不同之处在于格式化的可以是数?/p>
CZQ对变量a的值格式化Z位小敎ͼ
formatNumber(a,'#.00')Q?/p>
十一、hasChildNodes
含义Q如果结Ҏ(gu)子结点则q回trueQ?1Q,否则为falseQ?Q?/p>
语法QpNode.hasChildNodes()
注意Q与此前介绍的函C同,此函数后必须带一个空括号?/p>
CZQ判断当前结Ҏ(gu)否有子结点:
this.hasChildNodes
十二、namespaceURI、prefix
含义Q返回结点名字空间的全局资源标识W(或前~Q?/p>
语法QpNode.namespaceURI
pNode.prifix
十三、nextSibling、previousSibling、parentNode
含义Q返回结点的下一个兄弟(或前一个兄弟、或l点的父l点Q?/p>
语法QpNode.nextSibling
pNode.previousSibling
pNode.parentNode
注意Q对根结点(?/"Q应用parentNodeҎ(gu)、对W一个孩子结点应用previousSiblingҎ(gu)、对最后一个孩子结点应用nextSiblingҎ(gu)均会D错误Q可通过此过关系q算W?=Q等于)?=Q不{于Q来判断一个结Ҏ(gu)否某一指定l点Q格式ؓpNode1 = pNode2或pNode2 != pNode2?/p>
十四、nodeName
含义Q返回元素、属性、入口的名字或其他类型结点的一个特定字W串?/p>
语法QpNode.nodeName
CZQ当前结点的名字Q?/p>
this.nodeName
十五、nodeType、NodeTypeString
含义Q返回结点的cd的数值Ş式(或字W串形式Q?br />
语法QpNode.nodeType ?pNode.nodeTypeString
q回|
l点cd | l点cd?/font> | l点的字WŞ式描q?/font> |
Element | 1 | 'element' |
Element Attribute | 2 | 'attribute' |
Markup-Delimited Region of Text | 3 | 'text' |
Processing Instruction | 7 | 'processing_instruction' |
Comment | 8 | 'comment' |
Document Entity | 9 | 'document' |
十六、nodeTypedValue
含义Q以l点预定义的数据cdq回l点的倹{?/p>
语法QpNode.nodeTypedValue
CZQ假定当前结点的数据cd是fixed.14.4Q下例将以数D回结点的|而不是文本一个字W串Q?/p>
this.nodeTypedValue
十七、nodeValue
含义Q返回结点的文本?/p>
语法QpNode.nodeValue
注意Q该Ҏ(gu)不用于元素类l点Q可用于属性、CDATA、注释、文本等l点?/p>
CZQ当前元素第一个属性的|
this.attributes(0).nodeValue
当前元素内的文本Q假定该元素内只有文本,无其它元素,?lt;mark>text</mark>Q徏议多几ơ掌握其切的用法)?/p>
this.firstChild.nodeValue
十八、ownerDocument
含义Q返回包含该l点的文档的栏V?/p>
语法QpNode.ownerDocument
注意Q该Ҏ(gu)用于文档的根l点出错?/p>
十九(ji)、selectNodes
含义Q给定的样式匚w应用于当前结点ƈq回匚w的结炚w合?/p>
语法QpNode.selectNodes('pattern')
提示Qpattern的编写与<xsl:for-each>的select属性的值类|其中?/"开头表CZ文档的根出发搜烦Q以"http://"开头表遍历文档的所有结点;?.."开头表CZ当前l点的父l点开始;如果Ʋ从当前l点向下搜烦则不能有以上Ҏ(gu)字符打头?/p>
CZQ与当前l点同名的元素在其父元素内的个数Q?/p>
childNumber(this.selectNodes("../"+this.nodeName+"[end()]").item(0))
当前元素内名字ؓ"skill"的元素的个数Q?/p>
childNumber(this.selectNodes("skill[end()]").item(0))
二十、selectSingleNode
含义Q与selectNodescMQ不同的只返回匹配的W一个结炏V而不是结炚w合?/p>
语法QpNode.selectSingleNode('pattern')
CZQ与当前l点同名的元素在其父元素内的个数Q?/p>
childNumber(this.selectSingleNode("../"+this.nodeName+"[end()]"))
当前元素内名字ؓ"skill"的元素的个数Q?/p>
childNumber(this.selectSingleNode("skill[end()]"))
二十一、text
含义Q返回结点与它的子树内的文字内容?/p>
语法QpNode.text
CZQ整个文档内的文字内容:
this.ownerDocument.text
当前元素及其子树的文字内容:
this.text
二十二、xml
含义Q返回结点及其后代的XML表示?/p>
语法QpNode.xml
CZQ当前文档的XML内容Q?/p>
this.ownerDocument.xml
另有几个函数不作介绍Q列于其下以供参考,如感兴趣Q请讉Khttp://msdn.microsoft.com获取详细说明?/p>
formatTime(varTime, bstrFormat,varDestLocale)
formatDate(varDate, bstrFormat,varDestLocale)
apendChild(newChild)
definition
CloneNode
insertBefore(newChild, refChild)
parsed
removeChild(oldChild)
replaceChild(newChild, oldChild)
specified
transformNode(stylesheet)
transformNodeToObject(stylesheet,outputObject)
uniqueID(pNode)
Java提供了container classes来解册一问题。container classes包括两个部分QCollection和Map。它们的l构是这LQ?/p>
本文重点介绍HashMap。首先介l一下什么是Map。在数组中我们是通过数组下标来对其内容烦引的Q而在Map中我们通过对象来对对象q行索引Q用来烦引的对象叫做keyQ其对应的对象叫做value。在下文中会有例子具体说明?/p>
再来看看HashMap和TreeMap有什么区别。HashMap通过hashcode对其内容q行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得C个有序的l果你就应该使用TreeMapQHashMap中元素的排列序是不固定的)?/p>
下面pq入本文的主题了。先举个例子说明一下怎样使用HashMap:
import java.util.*;
public class Exp1 { class Ctime{ |
在HashMap中通过get()来获取valueQ通过put()来插入valueQContainsKey()则用来检验对象是否已l存在。可以看出,和ArrayList的操作相比,HashMap除了通过key索引其内容之外,别的斚w差异q不大?/p>
前面介绍了,HashMap是基于HashCode的,在所有对象的类Object中有一个HashCode()Ҏ(gu)Q但是它和equalsҎ(gu)一Pq不能适用于所有的情况Q这h们就需要重写自qHashCode()Ҏ(gu)。下面就举这样一个例子:
import java.util.*;
public class Exp2 { class Element{ class Figureout{ |
在这个例子中QElement用来索引对象Figureout,也即Element为keyQFigureout为value。在Figureout中随机生成一个QҎ(gu)Q如果它?.5大,打印“OK!”,否则打印“Impossible!”。之后查看Element(3)对应的Figureoutl果如何?/p>
l果却发玎ͼ无论你运行多次Q得到的l果都是“Not found”。也是说烦引Element(3)q不在HashMap中。这怎么可能呢?
原因得慢慢来_Element的HashCodeҎ(gu)l承自ObjectQ而Object中的HashCodeҎ(gu)q回的HashCode对应于当前的地址Q也是说对于不同的对象Q即使它们的内容完全相同Q用HashCodeQ)q回的g会不同。这样实际上q背了我们的意图。因为我们在使用HashMapӞ希望利用相同内容的对象烦引得到相同的目标对象Q这需要HashCode()在此时能够返回相同的倹{在上面的例子中Q我们期望new Element(i) (i=5)与 Element test=new Element(5)是相同的Q而实际上q是两个不同的对象,管它们的内容相同,但它们在内存中的地址不同。因此很自然的,上面的程序得不到我们设想的结果。下面对ElementcL改如下:
class Element{ int number; public Element(int n){ number=n; } public int hashCode(){ return number; } public boolean equals(Object o){ return (o instanceof Element) && (number==((Element)o).number); } } |
在这里Element覆盖了Object中的hashCode()和equals()Ҏ(gu)。覆盖hashCode()使其以number的g为hashcodeq回Q这样对于相同内容的对象来说它们的hashcode也就相同了。而覆盖equals()是ؓ了在HashMap判断两个key是否相等时ɾl果有意义(有关重写equals()的内容可以参考我的另一文章《重新编写ObjectcM的方?》)。修改后的程序运行结果如下:
h2:
Get the result for Element:
Impossible!
误住:如果你想有效的用HashMapQ你必重写在其的HashCode()?/p>
q有两条重写HashCode()的原则:
至于W二条原则的具体原因Q有兴趣者可以参考Bruce Eckel的《Thinking in Java》,在那里有对HashMap内部实现原理的介l,q里׃赘述了?/p>
掌握了这两条原则Q你p够用好HashMap~写自己的程序了。不知道大家注意没有Qjava.lang.Object中提供的三个Ҏ(gu)Qclone()Qequals()和hashCode()虽然很典型,但在很多情况下都不能够适用Q它们只是简单的由对象的地址得出l果。这需要我们在自己的程序中重写它们Q其实javacd中也重写了千千万万个q样的方法。利用面向对象的多态性——覆盖,Java的设计者很优雅的构ZJava的结构,也更加体CJava是一门纯OOP语言的特性?/p>
Java提供的Collection和Map的功能是十分强大的,它们能够使你的程序实现方式更为灵z,执行效率更高。希望本文能够对大家更好的用HashMap有所帮助?
Ҏ(gu)一、用Autofs
1、Autofs的特点:Autofs与Mount/Umount的不同之处在于,它是一U看守程序(deamonQ。如果它到用户正试图访问一个尚未挂接的文gpȝQ它?yu)׃自动该文gp?
l,如果该文件系l存在,那么Autofs会自动将其挂接。另一斚wQ如果它到某个已挂接的文gpȝ在一D|间内没有被用,那么Autofs会自?
其卸蝲。因此一旦运行了Autofs后,用户׃在需要手动完成文件系l的挂接和卸载?br />
2、Autofs的安装:
只需执行以下一条命令:rpm Qivh autofsQ?.1.3Q?0.i386.rpm。安装完成后Q以后每ơ启动LinuxQAutofs都会自动q行?br />
3、Autofs的配|:首先Q?/font>
Autofs需要从/etc/auto.masterq个文g中读取配|信息。该文g?
可以同时指定多个挂接点,每个挂接点单独用一行来定义,每一行可包括3个部分,分别用于指定挂接点位|,挂接旉使用的配|文Ӟ卻I所谓的map
file)及所挂接文gpȝ在空闲多长时间后自动被卸载。例如,auto.master文g中包括如下一行:
/auto /etc/auto.misc Q-timeout 60?/font>
?
中第一部分指定一个安装点?autoQ第二部分指?auto的map文g?etc/auto.miscQ第三部分指定文件系l在其空?0U后自动
被卸载。其ơ,?etc/auto.miscq个文gd挂接旉要用的配置信息。例如,auto.misc文g包括如下内容
cd -fstype=iso9660,ro,nosuid,nodev :/dev/cdrom
Windows_C -fstype=auto,iocharset=cp936 :/dev/hda1
Windows_D -fstype=auto,iocharset=cp936 :/dev/hda5
Windows_E -fstype=auto,iocharset=cp936 :/dev/hda6
其中W一行指定将讑֤/dev/cdrom挂接?auto的cd子目录中Q第二行指定
硬盘的Windows分区挂接?auto的Windows_*子目录中。每一行的W二个|fstype是一个可选项Q用来表明所挂接的文件系l的cd和挂接选项Q在
mount命o能用挂接选项同样适用于-fstype?
修改了配|文件后Q可通过执行命o?etc/init.d/autofs restart”,使新的配|生效?
现在输入命o“ls
/auto/cd”,Autofs会自动检光׃是否有光盘,如果有,它会自动其挂接?auto/cd中,q样ls׃列出其中的内宏V如果我们在
60U内没有再次讉K/auto/cdӞAutofs会自动将其卸载掉?br />转蝲自:http://family.chinaok.com/showcontent.php?articleid=1674
1、fstab文g的作?br />
文g/etc/fstab存放的是pȝ中的文gpȝ信息。当正确的设|了该文Ӟ则可以通过"mount
/directoryname"命o来加载一个文件系l,每种文gpȝ都对应一个独立的行,每行中的字段都有I格或tab键分开。同时fsck?
mount、umount的等命o都利用该E序?br />
2、下面是/etc/fatab文g的一个示例行Q?
fs_spec fs_file fs_type fs_options fs_dump fs_pass
/dev/hda1 / ext2 defaults 1 1
fs_spec - 该字D定义希望加载的文gpȝ所在的讑֤或远E文件系l,对于一般的本地块设备情冉|_IDE讑֤一般描qCؓ
/dev/hdaXNQX是IDE
讑֤通道(a, b, or c)QN代表分区PSCSI讑֤一描述?dev/sdaXN。对于NFS情况Q格式一般ؓ:,例如Q?
`knuth.aeb.nl:/'。对于procfsQ用`proc'来定义?
fs_file - 该字D|q希望的文gpȝ加蝲的目录点Q对于swap讑֤Q该字段为noneQ对于加载目录名包含I格的情况,?0来表C空根{?
fs_type - 定义了该讑֤上的文gpȝQ一般常见的文gcd为ext2 (Linux讑֤的常用文件类?、vfat(Windowspȝ的fat32格式)、NTFS、iso9600{?
fs_options - 指定加蝲该设备的文gpȝ是需要用的特定参数选项Q多个参数是由逗号分隔开来。对于大多数pȝ使用"defaults"可以满需要。其他常见的选项包括Q?
选项 含义
ro 以只L式加载该文gpȝ
sync 不对该设备的写操作进行缓冲处理,q可以防止在非正常关机时情况下破坏文件系l,但是却降低了计算机速度
user 允许普通用户加载该文gpȝ
quota 强制在该文gpȝ上进行磁盘定额限?
noauto 不再使用mount Qa命oQ例如系l启动时Q加载该文gpȝ
fs_dump - 该选项?dump"命o使用来检查一个文件系l应该以多快频率q行转储Q若不需要{储就讄该字Dؓ0
fs_pass - 该字D被fsck命o用来军_在启动时需要被扫描的文件系l的序Q根文gpȝ"/"对应该字D늚值应该ؓ1Q其他文件系l应该ؓ2。若该文件系l无需在启动时扫描则设|该字段?
3、修?etc/fstab实现自动挂蝲Windows分区Qƈ昄中文目录
LABEL=/ / ext3 defaults 1 1
none /dev/pts devpts gid=5,mode=620 0 0
none /proc proc defaults 0 0
none /dev/shm tmpfs defaults 0 0
LABEL=/usr /usr ext3 defaults 1 2
/dev/hda9 swap swap defaults 0 0
#d如下几行
/dev/hda1 /mnt/win_c vfat codepage=936,iocharset=cp936 0 0
/dev/hda5 /mnt/win_d vfat codepage=936,iocharset=cp936 0 0
/dev/hda6 /mnt/win_e vfat codepage=936,iocharset=cp936 0 0
4、对部分分区格式的支持需要编译相关的支持到内怺来实玎ͼ如NTFS?br />
首先,以rootw䆾登陆Q在/mnt下,你要有win_c win_d win_eq几个目录,如果没有可以通过在虚拟终端分别输入mkdir
/mnt/win_c,mkdir /mnt/win_d,mkdir /mnt/win_e来徏立。接着打开虚拟l端Q,输入 vi
mymountQ然后按insert输入如下代码Q?br />
#!/bin/bash
case $1 in
m)
mount -o iocharset=cp936 -t vfat /dev/hda1 /mnt/win_c
mount -o iocharset=cp936 -t vfat /dev/hda5 /mnt/win_d
mount -o iocharset=cp936 -t vfat /dev/hdc6 /mnt/win_e
;;
u)
umount -o iocharset=cp936 -t vfat /dev/hda1 /mnt/win_c
umount -o iocharset=cp936 -t vfat /dev/hda5 /mnt/win_d
umount -o iocharset=cp936 -t vfat /dev/hda6 /mnt/win_e
;;
esac
然后按Esc输入:wq回R可以了.W一?!/bin/bash指定以bash shell执行此文
?case $1 in 为取的命令行参数.若ؓm则开始挂?若ؓu则卸?其中-o
iocharset=cp936能够昄中文?-t vfat 为指定文件系l类型ؓWINDOWS下的VFAT文gp?br />
l?win_c win_d win_e为目?mnt下的子目?
到这里,该程序已l写好了.但是它还没有执行权利.我们只要输入下面q个命o可以了.
chmod u+x mymount
到这步你只要输入./mymount m,可以挂载windows分区?如果?etc/rc.d/rc.local 文g中添加这一行:
sh ./root/mymount m
重启后linux会自动挂载windows分区?br />
http://bbs.chinaunix.net/archiver/?tid-431527.html
在做一般的XML数据交换q程中,我更乐意传递XML字符Ԍ而不是格式化的XML Document。这涉及到XML字符串和Xml Document的{换问题,说白了这是个很简单的问题Q本文就各种XML解析器分别列丑֦下,以方便自׃后查阅?/font>
一、用最原始的javax.xml.parsersQ标准的jdk api
// 字符串{XML
String xmlStr = \"......\";
StringReader sr = new StringReader(xmlStr);
InputSource is = new InputSource(sr);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc = builder.parse(is);
//XML转字W串
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setOutputProperty(\"encoding\",\"GB23121\");//解决中文问题Q试q用GBK不行
ByteArrayOutputStream bos = new ByteArrayOutputStream();
t.transform(new DOMSource(doc), new StreamResult(bos));
String xmlStr = bos.toString();
q里的XML DOCUMENT为org.w3c.dom.Document
二、用dom4j后程序变得更?/font>
// 字符串{XML
String xmlStr = \"......\";
Document document = DocumentHelper.parseText(xmlStr);
// XML转字W串
Document document = ...;
String text = document.asXML();
q里的XML DOCUMENT为org.dom4j.Document
三、用JDOM
JDOM的处理方式和W一U方法处理非常类?/font>
//字符串{XML
String xmlStr = \".....\";
StringReader sr = new StringReader(xmlStr);
InputSource is = new InputSource(sr);
Document doc = (new SAXBuilder()).build(is);
//XML转字W串
Format format = Format.getPrettyFormat();
format.setEncoding(\"gb2312\");//讄xml文g的字Wؓgb2312Q解决中文问?br />XMLOutputter xmlout = new XMLOutputter(format);
ByteArrayOutputStream bo = new ByteArrayOutputStream();
xmlout.output(doc,bo);
String xmlStr = bo.toString();
q里的XML DOCUMENT为org.jdom.Document
四、JAVASCRIPT中的处理
//字符串{XML
var xmlStr = \".....\";
var xmlDoc = new ActiveXObject(\"Microsoft.XMLDOM\");
xmlDoc.async=false;
xmlDoc.loadXML(xmlStr);
//可以处理q个xmlDoc?br />var name = xmlDoc.selectSingleNode(\"/person/name\");
alert(name.text);
//XML转字W串
var xmlDoc = ......;
var xmlStr = xmlDoc.xml
q里的XML DOCUMENT为javascript版的XMLDOM
java代码: |
CREATE TABLE SNCPARAMETERS ( ID NUMBER(19) NOT NULL, SNCID NUMBER(19), NAME VARCHAR2(255), VALUE CLOB ) |
java代码: |
publicclass SNCParameters extends BaseObject { /** * Returns the id. * * @return long * @hibernate.id * column = "id" * type = "long" * generator-class = "native" * unsaved-value = "null" */ publicLong getId() { return id; } /** * Sets the Id attribute of the SNCParameters object * * @param id The new Id value */ publicvoid setId(Long id) { this.id = id; } /** * Returns the name. * * @return String * * @hibernate.property * column = "name" * type = "string" * not-null = "true" * unique = "false" */ publicString getName() { return name; } /** * Sets the Name attribute of the SNCParameters object * * @param name The new Name value */ publicvoid setName(String name) { this.name = name; } /** * Returns the sncId. * * @return Long * * @hibernate.property * column = "sncId" * type = "long" * not-null = "true" * unique = "false" */ publicLong getSncId() { return sncId; } /** * Sets the SncId attribute of the SNCParameters object * * @param sncId The new SncId value */ publicvoid setSncId(Long sncId) { this.sncId = sncId; } /** * Returns the values. * * @return Clob * * @hibernate.property * column = "value" * type = "clob" * not-null = "true" * unique = "false" */ publicClob getValue() { return value; } /** * Sets the Values attribute of the SNCParameters object * * @param values The new Values value */ publicvoid setValue(Clob value) { this.value = value; } privateLong id; privateLong sncId; privateString name; privateClob value; privateString valueString; publicString getValueString() { return valueString; } publicvoid setValueString(String valueString) { this.valueString = valueString; } } |
java代码: |
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="com.idncn.mc.bo.SNCParameters" table="SNCParameters" dynamic-update="false" dynamic-insert="false" > <id name="id" column="id" type="long" unsaved-value="null" > <generator class="native"> </generator> </id> <property name="name" type="string" update="true" insert="true" column="name" not-null="true" unique="false" /> <property name="sncId" type="long" update="true" insert="true" column="sncId" not-null="true" unique="false" /> <property name="value" type="clob" update="true" insert="true" column="value" not-null="true" unique="false" /> </class> </hibernate-mapping> |
java代码: |
publicList batchAddSncParameters(List sncParametersList, Long sncId)throws DbAccessException { logger.enterMethod(); List ret = newArrayList(); try { sess = getSession(); if(sncParametersList != null && sncParametersList.size() > 0) { for(int i = 0; i < sncParametersList.size(); i++) { SNCParameters cp = (SNCParameters) sncParametersList.get(i); long newId = -1; if(cp != null) { SNCParameters cpNew = new SNCParameters(); cpNew.setSncId(sncId); cpNew.setName(cp.getName()); cpNew.setValue(Hibernate.createClob(" ")); newId = ((Long) sess.save(cpNew)).longValue(); sess.flush(); sess.refresh(cpNew, LockMode.UPGRADE); String content = cp.getValueString(); String appserver = System.getProperty("appserver", "jboss"); if(!appserver.equalsIgnoreCase("jboss")) { //weblogic OracleThinClob clob = (OracleThinClob) cpNew.getValue(); java.io.Writer pw = clob.getCharacterOutputStream(); pw.write(content); pw.flush(); pw.close(); } else { //jboss oracle.sql.CLOB clob = (oracle.sql.CLOB) cpNew.getValue(); java.io.Writer pw = clob.getCharacterOutputStream(); pw.write(content); pw.flush(); pw.close(); } ret.add(newLong(newId)); } } } } catch(Exception e) { logger.error(e); ErrorReason errorReason = new ErrorReason(ErrorReason.INSERT_OBJECT_FAILED_REASON); throw new DbAccessException(DbAccessException.DBA_OPERATE_EXCEPTION, errorReason); } finally { closeSession(sess); logger.exitMethod(); } return ret; } |
java代码: |
publicList selectSncParametersBySncId(long sncId)throws DbAccessException { logger.enterMethod(); List ret = newArrayList(); try { sess = getSession(); String query = "select cp from cp in class com.idncn.mc.bo.SNCParameters where cp.sncId = ?"; logger.debug("SQL=" + query); List iter = sess.find(query, newLong(sncId), Hibernate.LONG); for(int i = 0; i < iter.size(); i++) { SNCParameters newCp = new SNCParameters(); SNCParameters cp = (SNCParameters)(iter.get(i)); logger.debug("after fetch:" + cp); newCp.setId(cp.getId()); newCp.setSncId(cp.getSncId()); newCp.setName(cp.getName()); java.sql.Clob clob = cp.getValue(); if(clob != null) { logger.debug("b===" + clob.length()); String b = clob.getSubString(1, (int) clob.length()); //logger.debug("b==="+b); newCp.setValueString(b); } ret.add(newCp); } } catch(Exception e) { logger.error(e); ErrorReason errorReason = new ErrorReason(ErrorReason.SELECT_FAILED_REASON); throw new DbAccessException(DbAccessException.DBA_OPERATE_EXCEPTION, errorReason); } finally { closeSession(sess); logger.exitMethod(); } return ret; } |
java代码: |
publicvoid updateSncParameters(SNCParameters newParam)throws DbAccessException { logger.enterMethod(); try { sess = getSession(); Long id = newParam.getId(); SNCParameters pp = (SNCParameters) sess.load(SNCParameters.class, id, net.sf.hibernate.LockMode.UPGRADE); pp.setSncId(newParam.getSncId()); pp.setName(newParam.getName()); pp.setId(newParam.getId()); String newValue = newParam.getValueString(); logger.debug("Update Length =" + newValue.length()); String appserver = System.getProperty("appserver", "jboss"); logger.debug("appserver: " + appserver); if(!appserver.equalsIgnoreCase("jboss")) { //weblogic OracleThinClob clob = (OracleThinClob) pp.getValue(); if(pp != null) { java.io.Writer pw = clob.getCharacterOutputStream(); pw.write(newValue); pw.flush(); pw.close(); } } else { //jboss oracle.sql.CLOB clob = (oracle.sql.CLOB) pp.getValue(); if(pp != null) { java.io.Writer pw = clob.getCharacterOutputStream(); pw.write(newValue); pw.flush(); pw.close(); } } } catch(Exception e) { logger.error(e); ErrorReason errorReason = new ErrorReason(ErrorReason.UPDATE_OBJECT_FAILED_REASON); throw new DbAccessException(DbAccessException.DBA_OPERATE_EXCEPTION, errorReason); } finally { closeSession(sess); logger.exitMethod(); } } |