<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.2" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>Enabling Technology</title>
	<link>http://blog.enabling-tech.com</link>
	<description>Java, Technical Management, China Market, Game, Online Casual Game Industry</description>
	<pubDate>Sun, 17 Aug 2008 02:33:31 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.2</generator>
	<language>en</language>
			<item>
		<title>Quck Dev env for PHP</title>
		<link>http://blog.enabling-tech.com/enabling-tech/php/php%e7%9a%84%e5%bf%ab%e9%80%9f%e5%bc%80%e5%8f%91%e7%8e%af%e5%a2%83%e3%80%82</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/php/php%e7%9a%84%e5%bf%ab%e9%80%9f%e5%bc%80%e5%8f%91%e7%8e%af%e5%a2%83%e3%80%82#comments</comments>
		<pubDate>Mon, 16 Jun 2008 05:12:45 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>PHP</dc:subject>
	<dc:subject>Enabling-tech</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/php/php%e7%9a%84%e5%bf%ab%e9%80%9f%e5%bc%80%e5%8f%91%e7%8e%af%e5%a2%83%e3%80%82</guid>
		<description><![CDATA[http://www.apachefriends.org/en/index.html
IDE: Eclipse PDT all in one.
No Tags]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.apachefriends.org/en/index.html" title="http://www.apachefriends.org/en/index.html">http://www.apachefriends.org/en/index.html</a></p>
<p>IDE: Eclipse PDT all in one.</p>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/php/php%e7%9a%84%e5%bf%ab%e9%80%9f%e5%bc%80%e5%8f%91%e7%8e%af%e5%a2%83%e3%80%82/feed</wfw:commentRss>
		</item>
		<item>
		<title>Swing thread articles</title>
		<link>http://blog.enabling-tech.com/enabling-tech/java/swing-thread-articles</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/java/swing-thread-articles#comments</comments>
		<pubDate>Fri, 13 Jun 2008 13:51:55 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>JavaBasic</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/java/swing-thread-articles</guid>
		<description><![CDATA[&#160;
http://www.yesky.com/418/1743418_5.shtml
http://java.chinaitlab.com/line/10270.html
http://fanqiang.chinaunix.net/program/java/2005-07-04/3363.shtml
http://www.21tx.com/dev/2002/02/22/10107.html
http://www.ddvip.com/program/java/index2/79.htm
http://www.ddvip.com/program/java/index2/78.htm
http://www.21tx.com/dev/2005/04/07/14818.html
http://www.jspcn.net/htmlnews/11049310422031206.html
http://www.matrix.org.cn/resource/article/0/132.html
No Tags]]></description>
			<content:encoded><![CDATA[<h6>&#160;</h6>
<p><a href="http://www.yesky.com/418/1743418_5.shtml">http://www.yesky.com/418/1743418_5.shtml</a></p>
<p><a href="http://java.chinaitlab.com/line/10270.html">http://java.chinaitlab.com/line/10270.html</a></p>
<p><a href="http://fanqiang.chinaunix.net/program/java/2005-07-04/3363.shtml">http://fanqiang.chinaunix.net/program/java/2005-07-04/3363.shtml</a></p>
<p><a href="http://www.21tx.com/dev/2002/02/22/10107.html">http://www.21tx.com/dev/2002/02/22/10107.html</a></p>
<p><a href="http://www.ddvip.com/program/java/index2/79.htm">http://www.ddvip.com/program/java/index2/79.htm</a></p>
<p><a href="http://www.ddvip.com/program/java/index2/78.htm">http://www.ddvip.com/program/java/index2/78.htm</a></p>
<p><a href="http://www.21tx.com/dev/2005/04/07/14818.html">http://www.21tx.com/dev/2005/04/07/14818.html</a></p>
<p><a href="http://www.jspcn.net/htmlnews/11049310422031206.html">http://www.jspcn.net/htmlnews/11049310422031206.html</a></p>
<p><a href="http://www.matrix.org.cn/resource/article/0/132.html">http://www.matrix.org.cn/resource/article/0/132.html</a></p>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/java/swing-thread-articles/feed</wfw:commentRss>
		</item>
		<item>
		<title>Implementation for running OS commands by using Java [Chinese]</title>
		<link>http://blog.enabling-tech.com/enabling-tech/java/%e7%94%a8java%e8%bf%90%e8%a1%8c%e6%93%8d%e7%ba%b5%e7%b3%bb%e7%bb%9f%e4%b8%8b%e7%9a%84%e5%91%bd%e4%bb%a4%ef%bc%8c%e7%a8%8b%e5%ba%8f%e7%9a%84%e5%ae%9e%e7%8e%b0%e6%96%b9%e6%b3%95%e3%80%82</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/java/%e7%94%a8java%e8%bf%90%e8%a1%8c%e6%93%8d%e7%ba%b5%e7%b3%bb%e7%bb%9f%e4%b8%8b%e7%9a%84%e5%91%bd%e4%bb%a4%ef%bc%8c%e7%a8%8b%e5%ba%8f%e7%9a%84%e5%ae%9e%e7%8e%b0%e6%96%b9%e6%b3%95%e3%80%82#comments</comments>
		<pubDate>Fri, 13 Jun 2008 06:00:25 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>JavaBasic</dc:subject>
	<dc:subject>Enabling-tech</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/java/%e7%94%a8java%e8%bf%90%e8%a1%8c%e6%93%8d%e7%ba%b5%e7%b3%bb%e7%bb%9f%e4%b8%8b%e7%9a%84%e5%91%bd%e4%bb%a4%ef%bc%8c%e7%a8%8b%e5%ba%8f%e7%9a%84%e5%ae%9e%e7%8e%b0%e6%96%b9%e6%b3%95%e3%80%82</guid>
		<description><![CDATA[关键一点就是处理外部子程序产生的输出，错误（和有时候需要的输入）流。不然就会发生死锁的情况。]]></description>
			<content:encoded><![CDATA[<p>【<a href="http://enabling-tech.com" target="_blank">enabling-tech.com</a>原创】</p>
<p>Java 语言本身提供了执行外部程序的机制，那就是<strong>java.lang.Runtime</strong>。改类自Java诞生就已经从在，这个可以从见JDK帮助文档的Since得到。随着Java的发展，该类也多次修订。<a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Runtime.html" title="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Runtime.html">http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Runtime.html</a></p>
<p>改类提供了6个重载的方法（截至目前1.5版本），我们把它拷过来，用作参考：</p>
<p><code><a href="http://java.sun.com/java/lang/Process.html">Process</a> </code><code><strong><a href="http://java.sun.com/java/lang/Runtime.html#exec(java.lang.String)">exec</a></strong>(<a href="http://java.sun.com/java/lang/String.html">String</a> command)</code><br />
Executes the specified string command in a separate process.</p>
<p><code><a href="http://java.sun.com/java/lang/Process.html">Process</a> </code><code><strong><a href="http://java.sun.com/java/lang/Runtime.html#exec(java.lang.String[])">exec</a></strong>(<a href="http://java.sun.com/java/lang/String.html">String</a>[] cmdarray)</code><br />
Executes the specified command and arguments in a separate process.</p>
<p><code><a href="http://java.sun.com/java/lang/Process.html">Process</a> </code><code><strong><a href="http://java.sun.com/java/lang/Runtime.html#exec%28java.lang.String%5B%5D,%20java.lang.String%5B%5D%29">exec</a></strong>(<a href="http://java.sun.com/java/lang/String.html">String</a>[] cmdarray, <a href="http://java.sun.com/java/lang/String.html">String</a>[] envp)</code><br />
Executes the specified command and arguments in a separate process with the specified environment.</p>
<p><code><a href="http://java.sun.com/java/lang/Process.html">Process</a> </code><code><strong><a href="http://java.sun.com/java/lang/Runtime.html#exec%28java.lang.String%5B%5D,%20java.lang.String%5B%5D,%20java.io.File%29">exec</a></strong>(<a href="http://java.sun.com/java/lang/String.html">String</a>[] cmdarray, <a href="http://java.sun.com/java/lang/String.html">String</a>[] envp, <a href="http://java.sun.com/java/io/File.html">File</a> dir)</code><br />
Executes the specified command and arguments in a separate process with the specified environment and working directory.</p>
<p><code><a href="http://java.sun.com/java/lang/Process.html">Process</a> </code><code><strong><a href="http://java.sun.com/java/lang/Runtime.html#exec%28java.lang.String,%20java.lang.String%5B%5D%29">exec</a></strong>(<a href="http://java.sun.com/java/lang/String.html">String</a> command, <a href="http://java.sun.com/java/lang/String.html">String</a>[] envp)</code><br />
Executes the specified string command in a separate process with the specified environment.</p>
<p><code><a href="http://java.sun.com/java/lang/Process.html">Process</a> </code><code><strong><a href="http://java.sun.com/java/lang/Runtime.html#exec%28java.lang.String,%20java.lang.String%5B%5D,%20java.io.File%29">exec</a></strong>(<a href="http://java.sun.com/java/lang/String.html">String</a> command, <a href="http://java.sun.com/java/lang/String.html">String</a>[] envp, <a href="http://java.sun.com/java/io/File.html">File</a> dir)</code><br />
Executes the specified string command in a separate process with the specified environment and working directory</p>
<p>按照文档上说，这行exec，就会产生一个与操作系统相关的process，Java用Process与之相联系，就是在Process里面有个这个实际的Process的引用。类Process的说明如下：</p>
<p>The <a href="http://java.sun.com/java/lang/ProcessBuilder.html#start()"><code>ProcessBuilder.start()</code></a> and <a href="http://java.sun.com/java/lang/Runtime.html#exec%28java.lang.String%5B%5D,%20java.lang.String%5B%5D,%20java.io.File%29"><code>Runtime.exec</code></a> methods create a <strong>native</strong> process and return an instance of a subclass of <code>Process</code> that can be used to control the process and obtain information about it.</p>
<p>就是说执行了exec，剩下的(输入，输出，等待结束，结束返回值等等）就交给Process具体的实现类来处理：</p>
<p>The class <code>Process</code> provides methods for performing input from the process, performing output to the process, waiting for the process to complete, checking the exit status of the process, and destroying (killing) the process.</p>
<p>网络上有很多介绍的文章，但是如果你看了还是不是很明白的话，其实最重要的还是回到JDK的帮助文档里来，在类Process的文档剩下的部分写的很明白：</p>
<p>The methods that create processes may not work well for special processes on certain native platforms, such as native windowing processes, daemon processes, Win16/DOS processes on Microsoft Windows, or shell scripts. The created subprocess does not have its own terminal or console. All its standard io (i.e. stdin, stdout, stderr) operations will be redirected to the parent process through three streams (<a href="http://java.sun.com/java/lang/Process.html#getOutputStream()"><code>getOutputStream()</code></a>, <a href="http://java.sun.com/java/lang/Process.html#getInputStream()"><code>getInputStream()</code></a>, <a href="http://java.sun.com/java/lang/Process.html#getErrorStream()"><code>getErrorStream()</code></a>). The parent process uses these streams to feed input to and get output from the subprocess. Because some native platforms only provide limited buffer size for standard input and output streams, failure to promptly write the input stream or read the output stream of the subprocess may cause the subprocess to block, and even deadlock.</p>
<p>The subprocess is not killed when there are no more references to the <code>Process</code> object, but rather the subprocess continues executing asynchronously.</p>
<p>There is no requirement that a process represented by a <code>Process</code> object execute asynchronously or concurrently with respect to the Java process that owns the <code>Process</code> object.</p>
<p>简单的说，所有的标准IO操作都会转给父进程，父进程需要用那三种流给子进程。更糟的是标准输入输出流的缓冲啊，就是buffer，有些操作系统给的是有限的（废话），那么不能及时写输入和读输出给子进程就或许导致子进程被block或者甚至死锁！</p>
<p>明白了上边的几点，我们来看一段例程，就比较清楚了：</p>
<p>直接使用参考文献1中的例程：</p>
<p>public class BadExecJavac<br />
{<br />
public static void main(String args[])<br />
{<br />
try<br />
{<br />
Runtime rt = Runtime.getRuntime();<br />
Process proc = rt.exec(&#8221;javac&#8221;);<br />
int exitVal = proc.exitValue();<br />
System.out.println(&#8221;Process exitValue: &#8221; + exitVal);<br />
}<br />
catch (Throwable t)<br />
{<br />
t.printStackTrace();<br />
}<br />
}<br />
}</p>
<p>执行结果如下：</p>
<p>java.lang.IllegalThreadStateException: <strong>process has not exited</strong><br />
at java.lang.ProcessImpl.exitValue(Native Method)<br />
at com.test.tools.test.book.Test.main(Test.java:17)<br />
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)<br />
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)<br />
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)<br />
at java.lang.reflect.Method.invoke(Method.java:585)<br />
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)</p>
<p>什么原因呢？ 查查文档，原来是说子进程还未结束，如果call exitValue（）的话，就会报错。</p>
<p>老方法，查查文档，Process有个waitFor() 方法：</p>
<h5>waitFor</h5>
<pre>public abstract int <strong>waitFor</strong>()
                     throws <a href="http://java.sun.com/java/lang/InterruptedException.html">InterruptedException</a></pre>
<dl>
<dd>causes the <strong>current</strong> thread to wait, if necessary, until the process represented by this <code>Process</code> object has terminated. This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be <strong>blocked</strong> until the subprocess exits. </dd>
<dd>
<dl>
<dt><strong>Returns:</strong></dt>
<dd>the exit value of the process. By convention, <code>0</code> indicates normal termination. </dd>
<dt><strong>Throws:</strong></dt>
<dd><code><a href="http://java.sun.com/java/lang/InterruptedException.html">InterruptedException</a></code> - if the current thread is <a href="http://java.sun.com/java/lang/Thread.html#interrupt()"><code>interrupted</code></a> by another thread while it is waiting, then the wait is ended and an <a href="http://java.sun.com/java/lang/InterruptedException.html"><code>InterruptedException</code></a> is thrown.</dd>
</dl>
</dd>
</dl>
<p>好，我们立即改进我们的程序，使用waitFor():</p>
<p>public class Test</p>
<p>{</p>
<p>public static void main(String args[])</p>
<p>{</p>
<p>try</p>
<p>{</p>
<p>Runtime rt = Runtime.getRuntime();</p>
<p>Process proc = rt.exec(&#8221;javac&#8221;);</p>
<p>int exitVal = proc.waitFor();</p>
<p>System.out.println(&#8221;Process exitValue: &#8221; + exitVal);</p>
<p>}</p>
<p>catch (Throwable t)</p>
<p>{</p>
<p>t.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>编译，运行。。。结果。。。结果。。。好像死在那里了#￥@%@@</p>
<p>好惨。。。立刻反省一下哪里错了？原来前文有提：我们没有处理输入，输出流×可能会×导致死锁！ Javac执行如上的话，会把结果输入到stderr流中去的，结果父进程没有处理(所有的外部流都导给父进程，见文档），子进程等父进程处理，父进程等子进程结束（waitFor())，典型的死锁情节。下面，我们的程序需要加上流的处理的部分！</p>
<p>import java.io.BufferedReader;</p>
<p>import java.io.InputStream;</p>
<p>import java.io.InputStreamReader;</p>
<p>public class Test</p>
<p>{</p>
<p>public static void main(String args[])</p>
<p>{</p>
<p>try</p>
<p>{</p>
<p>Runtime rt = Runtime.getRuntime();</p>
<p>Process proc = rt.exec(&#8221;javac&#8221;);<br />
//prepare to receive input err stream directed to This Process to drain.</p>
<p>InputStream stderr = proc.getErrorStream(); 得到错误流</p>
<p>InputStreamReader isr = new InputStreamReader(stderr);</p>
<p>BufferedReader br = new BufferedReader(isr);</p>
<p>String line = null;</p>
<p>System.out.println(&#8221;&lt;ERROR&gt;&#8221;);</p>
<p>while ((line = br.readLine()) != null)</p>
<p>{</p>
<p>System.out.println(line);</p>
<p>}</p>
<p>System.out.println(&#8221;&lt;/ERROR&gt;&#8221;);</p>
<p>int exitVal = proc.waitFor();</p>
<p>System.out.println(&#8221;Process exitValue: &#8221; + exitVal);</p>
<p>}</p>
<p>catch (Throwable t)</p>
<p>{</p>
<p>t.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>运行结果如下：</p>
<p>&lt;ERROR&gt;</p>
<p>用法：javac &lt;选项&gt; &lt;源文件&gt;</p>
<p>其中，可能的选项包括：</p>
<p>-g                         生成所有调试信息</p>
<p>-g:none                    不生成任何调试信息</p>
<p>-g:{lines,vars,source}     只生成某些调试信息</p>
<p>-nowarn                    不生成任何警告</p>
<p>-verbose                   输出有关编译器正在执行的操作的消息</p>
<p>-deprecation               输出使用已过时的 API 的源位置</p>
<p>-classpath &lt;路径&gt;            指定查找用户类文件的位置</p>
<p>-cp &lt;路径&gt;                   指定查找用户类文件的位置</p>
<p>-sourcepath &lt;路径&gt;           指定查找输入源文件的位置</p>
<p>-bootclasspath &lt;路径&gt;        覆盖引导类文件的位置</p>
<p>-extdirs &lt;目录&gt;              覆盖安装的扩展目录的位置</p>
<p>-endorseddirs &lt;目录&gt;         覆盖签名的标准路径的位置</p>
<p>-d &lt;目录&gt;                    指定存放生成的类文件的位置</p>
<p>-encoding &lt;编码&gt;             指定源文件使用的字符编码</p>
<p>-source &lt;版本&gt;               提供与指定版本的源兼容性</p>
<p>-target &lt;版本&gt;               生成特定 VM 版本的类文件</p>
<p>-version                   版本信息</p>
<p>-help                      输出标准选项的提要</p>
<p>-X                         输出非标准选项的提要</p>
<p>-J&lt;标志&gt;                     直接将 &lt;标志&gt; 传递给运行时系统</p>
<p>&lt;/ERROR&gt;</p>
<p>Process exitValue: 2</p>
<p>Process finished with exit code 0</p>
<p>因为我在IDE里运行的，所以你会看到退出码是0，就是这个java类运行是正常。但是对于javac在例程中运行code是2.不同系统不同意义，这里代表文件没有找到。一般来说，0代表正常，非0都代表错误。</p>
<p>这段程序对这个例子来说足够了，但是缺乏灵活和完美！最要命的是这个程序还没有处理标准输入和输出流。</p>
<p>在开始完美化之前，先说说一个常见的错误。或许你已经迫不及待的编写和运行如下程序，结果发现是有问题的：</p>
<p>public class Test</p>
<p>{</p>
<p>public static void main(String args[])</p>
<p>{</p>
<p>try</p>
<p>{</p>
<p>Runtime rt = Runtime.getRuntime();</p>
<p><strong>     Process proc = rt.exec(&#8221;dir&#8221;);</strong></p>
<p>InputStream stdin = proc.getInputStream();</p>
<p>InputStreamReader isr = new InputStreamReader(stdin);</p>
<p>BufferedReader br = new BufferedReader(isr);</p>
<p>String line = null;</p>
<p>System.out.println(&#8221;&lt;OUTPUT&gt;&#8221;);</p>
<p>while ((line = br.readLine()) != null)</p>
<p>{</p>
<p>System.out.println(line);</p>
<p>}</p>
<p>System.out.println(&#8221;&lt;/OUTPUT&gt;&#8221;);</p>
<p>int exitVal = proc.waitFor();</p>
<p>System.out.println(&#8221;Process exitValue: &#8221; + exitVal);</p>
<p>}</p>
<p>catch (Throwable t)</p>
<p>{</p>
<p>t.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>为什么不行呢？这是因为dir这个命令需要windows 命令解释器，而不是一个单独存在的命令！也就是说该程序无法找到dir.</p>
<p>现在就让我们开始振奋人心的编程吧！采用一个专门的类处理外部程序需要输出的流，对于我们来说就是输入流。采用线程执行，所以可以异步的处理多个流。</p>
<p>/**</p>
<p>*  gobbler</p>
<p>1. 雄火鸡</p>
<p>2. 狼吞虎咽的人</p>
<p>*/</p>
<p>class <strong>StreamGobbler</strong> extends <strong>Thread</strong></p>
<p>{</p>
<p>InputStream is;</p>
<p>String type;</p>
<p>StreamGobbler(InputStream is, String type)</p>
<p>{</p>
<p>this.is = is;</p>
<p>this.type = type;</p>
<p>}</p>
<p>public void run()</p>
<p>{</p>
<p>try</p>
<p>{</p>
<p>InputStreamReader isr = new InputStreamReader(is);</p>
<p>BufferedReader br = new BufferedReader(isr);</p>
<p>String line = null;</p>
<p>while ((line = br.readLine()) != null)</p>
<p>{</p>
<p>System.out.println(type + &#8220;&gt;&#8221; + line);</p>
<p>}</p>
<p>}</p>
<p>catch (IOException ioe)</p>
<p>{</p>
<p>ioe.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>class <strong>GoodWindowsExec</strong></p>
<p>{</p>
<p>public static void main(String args[])</p>
<p>{</p>
<p>if (args.length &lt; 1)</p>
<p>{</p>
<p>System.out.println(&#8221;USAGE: java GoodWindowsExec &lt;cmd&gt;&#8221;);</p>
<p>System.exit(1);</p>
<p>}</p>
<p>try</p>
<p>{</p>
<p><strong>String</strong> osName = <strong>System</strong>.<strong>getProperty</strong>(&#8221;os.name&#8221;);</p>
<p>String[] cmd = new String[3];</p>
<p>if (osName.equals(&#8221;Windows NT&#8221;))</p>
<p>{</p>
<p>cmd[0] = &#8220;cmd.exe&#8221;;</p>
<p>cmd[1] = &#8220;/C&#8221;;</p>
<p>cmd[2] = args[0];</p>
<p>}</p>
<p>else if (osName.equals(&#8221;Windows 95&#8243;))</p>
<p>{</p>
<p>cmd[0] = &#8220;command.com&#8221;;</p>
<p>cmd[1] = &#8220;/C&#8221;;</p>
<p>cmd[2] = args[0];</p>
<p>}</p>
<p>Runtime rt = Runtime.getRuntime();</p>
<p>System.out.println(&#8221;Execing &#8221; + cmd[0] + &#8221; &#8221; + cmd[1]</p>
<p>+ &#8221; &#8221; + cmd[2]);</p>
<p>Process proc = rt.exec(cmd);</p>
<p><strong>// any error message?</p>
<p>StreamGobbler errorGobbler = new</strong></p>
<p><strong>                    StreamGobbler(proc.getErrorStream(), &#8220;ERROR&#8221;); </strong></p>
<p><strong>            // any output?</p>
<p>StreamGobbler outputGobbler = new</strong></p>
<p><strong>                    StreamGobbler(proc.getInputStream(), &#8220;OUTPUT&#8221;); </strong></p>
<p><strong>            // kick them off</p>
<p>errorGobbler.start();</strong></p>
<p><strong>            outputGobbler.start(); </strong></p>
<p>// 还是惹不起那些进程，我等。</p>
<p>int exitVal = proc.waitFor();</p>
<p>System.out.println(&#8221;ExitValue: &#8221; + exitVal);</p>
<p>}</p>
<p>catch (Throwable t)</p>
<p>{</p>
<p>t.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>用这个方式执行：</p>
<p>列目录，java GoodWindowsExec &#8220;dir *.java&#8221; 。</p>
<p>打开word文档，java GoodWindowsExec &#8220;yourdoc.doc&#8221;。其他就不赘述了。</p>
<p>另外，要记住，exec不是个命令解释器，它的作用只是运行命令。千万不要认为exec() method 好像一个shell interpreter。如果你那么认为，就会犯下面的错误：</p>
<p>class BadWinRedirect</p>
<p>{</p>
<p>public static void main(String args[])</p>
<p>{</p>
<p>try</p>
<p>{</p>
<p>Runtime rt = Runtime.getRuntime();</p>
<p>Process proc = rt.exec(&#8221;java jecho &#8216;Hello World&#8217; &gt; test.txt&#8221;);</p>
<p>// any error message?</p>
<p>StreamGobbler errorGobbler = new</p>
<p>StreamGobbler(proc.getErrorStream(), &#8220;ERROR&#8221;);</p>
<p>// any output?</p>
<p>StreamGobbler outputGobbler = new</p>
<p>StreamGobbler(proc.getInputStream(), &#8220;OUTPUT&#8221;);</p>
<p>// kick them off</p>
<p>errorGobbler.start();</p>
<p>outputGobbler.start();</p>
<p>// any error???</p>
<p>int exitVal = proc.waitFor();</p>
<p>System.out.println(&#8221;ExitValue: &#8221; + exitVal);</p>
<p>}</p>
<p>catch (Throwable t)</p>
<p>{</p>
<p>t.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>该程序本意是想执行jecho &#8216;Hello World‘,然后把执行结果存入test.txt。Sorry，错了。你必须用编程的方法来实现。还记得我们前面说过子进程的输出流么，把子进程的输出流===》得到，然后存入test.txt就可以实现了。</p>
<p>有点晕？呵呵。我们里一下思路。该例程运行程序（java jecho &#8216;Hello World&#8217;）,产生个子进程，子进程产生输出流。子进程如前所述没有地方释放，需要父进程排泄。所以，对父进程来说，就是得到proc.getInputStream(), 就是把子进程要输出的东西得到。</p>
<p>这样还需要改进一下我们（吃流者）这个类。SteamBobbler.:) 如下：</p>
<p>import java.io.BufferedReader;</p>
<p>import java.io.FileOutputStream;</p>
<p>import java.io.IOException;</p>
<p>import java.io.InputStream;</p>
<p>import java.io.InputStreamReader;</p>
<p>import java.io.OutputStream;</p>
<p>import java.io.PrintWriter;</p>
<p>class <strong>StreamGobbler</strong> extends Thread</p>
<p>{</p>
<p>InputStream is;</p>
<p>String type;</p>
<p>OutputStream os;</p>
<p>StreamGobbler(InputStream is, String type)</p>
<p>{</p>
<p>this(is, type, null);</p>
<p>}</p>
<p>StreamGobbler(InputStream is, String type, <strong>OutputStream redirect</strong>)</p>
<p>{</p>
<p>this.is = is;</p>
<p>this.type = type;</p>
<p><strong> this.os = redirect;</strong></p>
<p>}</p>
<p>public void run()</p>
<p>{</p>
<p>try</p>
<p>{</p>
<p><strong>       PrintWriter pw = null;</p>
<p>if (os != null)</strong></p>
<p><strong>            {</strong></p>
<p><strong>                pw = new PrintWriter(os);</strong></p>
<p><strong>            }</strong></p>
<p>InputStreamReader isr = new InputStreamReader(is);</p>
<p>BufferedReader br = new BufferedReader(isr);</p>
<p>String line = null;</p>
<p>while ((line = br.readLine()) != null)</p>
<p>{</p>
<p>if (pw != null)</p>
<p>{</p>
<p><strong>          pw.println(line);</strong></p>
<p>}</p>
<p>System.out.println(type + &#8220;&gt;&#8221; + line);</p>
<p>}</p>
<p>if (pw != null)</p>
<p>{</p>
<p><strong>              pw.flush();</strong></p>
<p>}</p>
<p>}</p>
<p>catch (IOException ioe)</p>
<p>{</p>
<p>ioe.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>class <strong>GoodWinRedirect</strong></p>
<p>{</p>
<p>public static void main(String args[])</p>
<p>{</p>
<p>if (args.length &lt; 1)</p>
<p>{</p>
<p>System.out.println(&#8221;<strong>USAGE java GoodWinRedirect &lt;outputfile&gt;&#8221;);</strong></p>
<p>System.exit(1);</p>
<p>}</p>
<p>try</p>
<p>{</p>
<p><strong>FileOutputStream fos = new FileOutputStream(args[0]);</strong></p>
<p>Runtime rt = Runtime.getRuntime();</p>
<p>Process proc = rt.exec(&#8221;java jecho &#8216;Hello World&#8217;&#8221;);<br />
// any error message?</p>
<p>StreamGobbler errorGobbler = new</p>
<p>StreamGobbler(proc.getErrorStream(), &#8220;ERROR&#8221;);</p>
<p>// any output?</p>
<p>StreamGobbler outputGobbler = new</p>
<p>StreamGobbler(proc.getInputStream(), &#8220;OUTPUT&#8221;, <strong>fos</strong>);</p>
<p>// kick them off</p>
<p>errorGobbler.start();</p>
<p>outputGobbler.start();</p>
<p>// any error???</p>
<p>int exitVal = proc.waitFor();</p>
<p>System.out.println(&#8221;ExitValue: &#8221; + exitVal);</p>
<p>fos.flush();</p>
<p>fos.close();</p>
<p>}</p>
<p>catch (Throwable t)</p>
<p>{</p>
<p>t.printStackTrace();</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>OK，大功告成，基本上成功。</p>
<p>小结如下：</p>
<ol>
<li>You cannot obtain an exit status from an external process until it has exited</li>
<li>You must immediately handle the input, output, and error streams from your spawned external process</li>
<li>You must use Runtime.exec() to execute programs</li>
<li>You cannot use Runtime.exec() like a command line</li>
</ol>
<p>本文完。下期谈谈如何使用目录，环境变量等高级话题。</p>
<p>参考文档：</p>
<ol>
<li><a href="http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html">http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html</a></li>
</ol>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/java/%e7%94%a8java%e8%bf%90%e8%a1%8c%e6%93%8d%e7%ba%b5%e7%b3%bb%e7%bb%9f%e4%b8%8b%e7%9a%84%e5%91%bd%e4%bb%a4%ef%bc%8c%e7%a8%8b%e5%ba%8f%e7%9a%84%e5%ae%9e%e7%8e%b0%e6%96%b9%e6%b3%95%e3%80%82/feed</wfw:commentRss>
		</item>
		<item>
		<title>What a good Engineering Code Review is</title>
		<link>http://blog.enabling-tech.com/enabling-tech/what-a-good-engineering-code-review-is</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/what-a-good-engineering-code-review-is#comments</comments>
		<pubDate>Wed, 19 Dec 2007 07:04:53 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>Enabling-tech</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/what-a-good-engineering-code-review-is</guid>
		<description><![CDATA[
Contact the Key reviewer in advance and confirm when they are available 
Having all codes packaged in a zip file and check into server and send out the link.
For changing existing code, print out the diff version in pdf &#8230;.
make use of computer when doing a code review
clarify and confirm
write clear meeting notes and send [...]]]></description>
			<content:encoded><![CDATA[<ol>
<li>Contact the Key reviewer in advance and confirm when they are available </li>
<li>Having all codes packaged in a zip file and check into server and send out the link.</li>
<li>For changing existing code, print out the diff version in pdf &#8230;.</li>
<li>make use of computer when doing a code review</li>
<li>clarify and confirm</li>
<li>write clear meeting notes and send out the meeting notes afterwards to confirm the changes.</li>
<li>if necessary, let&#8217;s have another meeting.</li>
</ol>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/what-a-good-engineering-code-review-is/feed</wfw:commentRss>
		</item>
		<item>
		<title>Essence of Hiring a good engineer</title>
		<link>http://blog.enabling-tech.com/enabling-tech/essence-of-hiring-a-good-engineer</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/essence-of-hiring-a-good-engineer#comments</comments>
		<pubDate>Thu, 13 Dec 2007 10:13:02 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>Enabling-tech</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/essence-of-hiring-a-good-engineer</guid>
		<description><![CDATA[
Ask him /her to revise the bad code of the guy after one hour&#8217;s long talk. This is to test: 

good working attitude 
willing do stuff even feel tired 
have good sense of taking pressure 
refractor ability that we strongly need


No Tags]]></description>
			<content:encoded><![CDATA[<ol>
<li>Ask him /her to revise the bad code of the guy after one hour&#8217;s long talk. This is to test: </li>
<ol>
<li>good working attitude </li>
<li>willing do stuff even feel tired </li>
<li>have good sense of taking pressure </li>
<li>refractor ability that we strongly need</li>
</ol>
</ol>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/essence-of-hiring-a-good-engineer/feed</wfw:commentRss>
		</item>
		<item>
		<title>Essence of People Management</title>
		<link>http://blog.enabling-tech.com/engineering-management/essence-of-people-management</link>
		<comments>http://blog.enabling-tech.com/engineering-management/essence-of-people-management#comments</comments>
		<pubDate>Thu, 13 Dec 2007 07:34:15 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>Engineering Management</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/engineering-management/essence-of-people-management</guid>
		<description><![CDATA[General Management Sense

Demonstrate that you ARE ABLE TO work well with your peer managers.
When questions comes, try to get them solved with a reasonable way.
Don&#8217;t quarrel which doesn&#8217;t solve any problems and will lead you to a worse situation.
Being a manager, you have the right to decide the next step as you are the one [...]]]></description>
			<content:encoded><![CDATA[<p><strong>General Management Sense</strong></p>
<ol>
<li>Demonstrate that you ARE ABLE TO work well with your peer managers.</li>
<li>When questions comes, try to get them solved with a reasonable way.</li>
<li>Don&#8217;t quarrel which doesn&#8217;t solve any problems and will lead you to a worse situation.</li>
<li>Being a manager, you have the right to decide the next step as you are the one who take responsibility.</li>
<li>Listening to others&#8217; advice doesn&#8217;t mean you have to take&#8217; em. Take only if they are right.</li>
</ol>
<p><strong>Team Management:</strong></p>
<ol>
<li>Think as a Team.Then make decision on key stuff. Leave things to others to decide.</li>
</ol>
<p>&#160;</p>
<p><strong>Trust Relationship Build Up</strong></p>
<ol>
<li>Know what the most important stuff to the individual</li>
<li>Over sharing sometimes</li>
</ol>
<p><strong>Manage Up!</strong></p>
<ol>
<li>Know what the are good at and leverage it.</li>
<li>push to meet with you even they don&#8217;t want to. &#8216;cos they are nice so they don&#8217;t want to feel bad if they don&#8217;t meet with you.</li>
</ol>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/engineering-management/essence-of-people-management/feed</wfw:commentRss>
		</item>
		<item>
		<title>Protected: 得到地理解码</title>
		<link>http://blog.enabling-tech.com/enabling-tech/%e5%be%97%e5%88%b0%e5%9c%b0%e7%90%86%e8%a7%a3%e7%a0%81</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/%e5%be%97%e5%88%b0%e5%9c%b0%e7%90%86%e8%a7%a3%e7%a0%81#comments</comments>
		<pubDate>Thu, 27 Sep 2007 08:53:44 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>Enabling-tech</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/%e5%be%97%e5%88%b0%e5%9c%b0%e7%90%86%e8%a7%a3%e7%a0%81</guid>
		<description><![CDATA[There is no excerpt because this is a protected post.]]></description>
			<content:encoded><![CDATA[<form action="http://blog.enabling-tech.com/wp-pass.php" method="post">
<p>This post is password protected. To view it please enter your password below:</p>
<p><label>Password:<br />
<input name="post_password" type="password" size="20" /></label><br />
<input type="submit" name="Submit" value="Submit" /></p></form>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/%e5%be%97%e5%88%b0%e5%9c%b0%e7%90%86%e8%a7%a3%e7%a0%81/feed</wfw:commentRss>
		</item>
		<item>
		<title>Google Map to your website</title>
		<link>http://blog.enabling-tech.com/enabling-tech/google-technology-gadget-etc/google-map-to-your-website</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/google-technology-gadget-etc/google-map-to-your-website#comments</comments>
		<pubDate>Thu, 13 Sep 2007 10:38:30 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>Google Tech</dc:subject>
	<dc:subject>Enabling-tech</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/google-technology-gadget-etc/google-map-to-your-website</guid>
		<description><![CDATA[http://www.google.com/intl/zh-CN/apis/maps/signup.html
No Tags]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.google.com/intl/zh-CN/apis/maps/signup.html">http://www.google.com/intl/zh-CN/apis/maps/signup.html</a></p>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/google-technology-gadget-etc/google-map-to-your-website/feed</wfw:commentRss>
		</item>
		<item>
		<title>Wordpress Stats plug-in BSUITE [Chinese]</title>
		<link>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/bsuite%e6%98%af%e4%b8%80%e6%ac%bewordpress%e7%bb%9f%e8%ae%a1%e6%8f%92%e4%bb%b6</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/bsuite%e6%98%af%e4%b8%80%e6%ac%bewordpress%e7%bb%9f%e8%ae%a1%e6%8f%92%e4%bb%b6#comments</comments>
		<pubDate>Wed, 08 Aug 2007 06:36:45 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>SEO</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/bsuite%e6%98%af%e4%b8%80%e6%ac%bewordpress%e7%bb%9f%e8%ae%a1%e6%8f%92%e4%bb%b6</guid>
		<description><![CDATA[http://www.maisonbisson.com/blog/post/10900/#section-3
bsuite是一款wordpress统计插件，它的前身是bstat，简单好用的来访者统计插件。
它的功能如下：

跟踪网页点击次数。
跟踪搜索引挚关键字。
输出点击率最高的文章。
输出最近的评论。
输出最多的搜索关键字。
输出整个网站或单篇文章的访问量脉冲图
高亮搜索单词。
在文章底部列出有联系的相关文章。
与bsuite_speedcache结合一体。
列出文章tag。

请到这儿点击下载，这儿是安装方法。
No Tags]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.maisonbisson.com/blog/post/10900/#section-3" title="http://www.maisonbisson.com/blog/post/10900/#section-3">http://www.maisonbisson.com/blog/post/10900/#section-3</a></p>
<p><a href="http://www.maisonbisson.com/blog/post/10900/#section-3">bsuite</a>是一款wordpress统计插件，它的前身是bstat，简单好用的来访者统计插件。<br />
它的功能如下：</p>
<ol>
<li>跟踪网页点击次数。</li>
<li>跟踪搜索引挚关键字。</li>
<li>输出点击率最高的文章。</li>
<li>输出最近的评论。</li>
<li>输出最多的搜索关键字。</li>
<li>输出整个网站或单篇文章的访问量脉冲图</li>
<li>高亮搜索单词。</li>
<li>在文章底部列出有联系的相关文章。</li>
<li>与<a href="http://www.maisonbisson.com/blog/post/10861/">bsuite_speedcache</a>结合一体。</li>
<li>列出文章tag。</li>
</ol>
<p>请到<a href="http://homepage.mac.com/misterbisson/projects/bsuite.zip">这儿</a>点击下载，<a href="http://www.maisonbisson.com/blog/post/10900/#section-3">这儿</a>是安装方法。</p>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/bsuite%e6%98%af%e4%b8%80%e6%ac%bewordpress%e7%bb%9f%e8%ae%a1%e6%8f%92%e4%bb%b6/feed</wfw:commentRss>
		</item>
		<item>
		<title>Test for finding job in Baidu.com(in Chinese)</title>
		<link>http://blog.enabling-tech.com/enabling-tech/search-engine-optimization/%e7%99%be%e5%ba%a6%e7%ac%94%e8%af%95%e9%a2%98%e7%9b%ae%ef%bc%88%e8%bd%ac%ef%bc%89</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/search-engine-optimization/%e7%99%be%e5%ba%a6%e7%ac%94%e8%af%95%e9%a2%98%e7%9b%ae%ef%bc%88%e8%bd%ac%ef%bc%89#comments</comments>
		<pubDate>Wed, 08 Aug 2007 03:37:14 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>SEO</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/%e7%99%be%e5%ba%a6%e7%ac%94%e8%af%95%e9%a2%98%e7%9b%ae%ef%bc%88%e8%bd%ac%ef%bc%89</guid>
		<description><![CDATA[ 百度笔试题目（转）
题目大致是这样的：
&#160;&#160; 第一部分选择题：有几道网络相关的题目，巨简单，比如第一题是TCP、RIP、IP、FTP中哪个协议是传输层的&#8230;&#8230;。有一道linux的chown使用题目。其他的全是数据结构的题目！什么链，表，码的，不知所云~~~唉，我可以没有学过数据结构的人呐！真残忍！这一部分迅速猜完！
&#160;&#160;&#160; 第二部分简答题：
&#160;&#160;&#160; 1、在linux中如何编译C程序，使之成为可执行文件？如何调试？
答案：1)检查程序中.h文件所在的目录，将其加入系统PATH中；
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 2)执行C编译：#gcc [源文件名] -o [目标文件名]
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 执行C++编译：#g++ [源文件名] -o [目标文件名]
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 3)改变目标文件为可执行文件：#chmod +x [目标文件名]
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 4)如需将多个可执行文件连续执行，可生成批处理文件：
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; #vi [批处理文件名]
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 可执行文件1
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 可执行文件2
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#8230;&#8230;&#8230;
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 最后将该批处理文件属性该位可执行。
&#160;&#160;&#160; 调试：在编译时使用-g参数，就可以使用gdb进行调试。
&#160;&#160;&#160; 2、写出内存分配和释放的函数，并指出区别。
答案：
&#160;&#160;&#160;&#160;&#160; C语言的标准内存分配函数：malloc，calloc，realloc，free等。   &#160;&#160;&#160;&#160;&#160; malloc与calloc的区别为1块与n块的区别：    &#160;&#160;&#160;&#160;&#160;&#160;&#160; malloc调用形式为(类型*)malloc(size)：在内存的动态存储区中分配一块长度为&#8220;size&#8221;字节的连续区域，返回该区域的首地址。    &#160;&#160;&#160;&#160;&#160;&#160; calloc调用形式为(类型*)calloc(n，size)：在内存的动态存储区中分配n块长度为&#8220;size&#8221;字节的连续区域，返回首地址。    &#160;&#160;&#160;&#160;&#160;&#160; realloc调用形式为(类型*)realloc(*ptr，size)：将ptr内存大小增大到size。    &#160;&#160;&#160;&#160;&#160;&#160; free的调用形式为free(void*ptr)：释放ptr所指向的一块内存空间。    &#160;&#160;&#160; C++中为new/delete函数。
&#160;&#160;&#160; [...]]]></description>
			<content:encoded><![CDATA[<p> 百度笔试题目（转）</p>
<p>题目大致是这样的：</p>
<p>&#160;&#160; 第一部分选择题：有几道网络相关的题目，巨简单，比如第一题是TCP、RIP、IP、FTP中哪个协议是传输层的&#8230;&#8230;。有一道linux的chown使用题目。其他的全是数据结构的题目！什么链，表，码的，不知所云~~~唉，我可以没有学过数据结构的人呐！真残忍！这一部分迅速猜完！</p>
<p>&#160;&#160;&#160; 第二部分简答题：</p>
<p>&#160;&#160;&#160; 1、在linux中如何编译C程序，使之成为可执行文件？如何调试？</p>
<p>答案：1)检查程序中.h文件所在的目录，将其加入系统PATH中；</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 2)执行C编译：#gcc [源文件名] -o [目标文件名]</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 执行C++编译：#g++ [源文件名] -o [目标文件名]</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 3)改变目标文件为可执行文件：#chmod +x [目标文件名]</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 4)如需将多个可执行文件连续执行，可生成批处理文件：</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; #vi [批处理文件名]</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 可执行文件1</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 可执行文件2</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#8230;&#8230;&#8230;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 最后将该批处理文件属性该位可执行。</p>
<p>&#160;&#160;&#160; 调试：在编译时使用-g参数，就可以使用gdb进行调试。</p>
<p>&#160;&#160;&#160; 2、写出内存分配和释放的函数，并指出区别。</p>
<p>答案：</p>
<p>&#160;&#160;&#160;&#160;&#160; C语言的标准内存分配函数：malloc，calloc，realloc，free等。   <br />&#160;&#160;&#160;&#160;&#160; malloc与calloc的区别为1块与n块的区别：    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; malloc调用形式为(类型*)malloc(size)：在内存的动态存储区中分配一块长度为&#8220;size&#8221;字节的连续区域，返回该区域的首地址。    <br />&#160;&#160;&#160;&#160;&#160;&#160; calloc调用形式为(类型*)calloc(n，size)：在内存的动态存储区中分配n块长度为&#8220;size&#8221;字节的连续区域，返回首地址。    <br />&#160;&#160;&#160;&#160;&#160;&#160; realloc调用形式为(类型*)realloc(*ptr，size)：将ptr内存大小增大到size。    <br />&#160;&#160;&#160;&#160;&#160;&#160; free的调用形式为free(void*ptr)：释放ptr所指向的一块内存空间。    <br />&#160;&#160;&#160; C++中为new/delete函数。</p>
<p>&#160;&#160;&#160; 3、写出socket函数，并指出其功能。</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160; socket():建立socket通信描述符；   <br />&#160;&#160;&#160;&#160;&#160;&#160; bind()：将套接字和机器上的一定的端口关联；    <br />&#160;&#160;&#160;&#160;&#160; connect()：连接到远程主机；    <br />&#160;&#160;&#160;&#160;&#160; listen()：使套接字做好连接的准备，规定等待服务请求队列的长度；    <br />&#160;&#160;&#160;&#160;&#160; accept()：接受连接，一旦有客户端发出连接，accept返回客户地址信息和一个新的sock；    <br />&#160;&#160; 有了这个新的sock，双方就可以开始收发数据：    <br />&#160;&#160;&#160;&#160;&#160; send()和recv()：用于流式套接字或者数据套接字的通讯；    <br />&#160;&#160;&#160;&#160;&#160; sendto()和recvfrom()：用于无连接的数据报套接字；    <br />&#160;&#160;&#160;&#160;&#160; close()：关闭套接字；    <br />&#160;&#160;&#160;&#160;&#160; shutdown()：选择性的关闭套接字，可以只允许某一方向的通讯关闭；    <br />&#160;&#160;&#160;&#160;&#160; getpeername()：返回流式套接字时对端peer信息；    <br />&#160;&#160;&#160;&#160;&#160; gethostname()：返回程序所运行的机器的主机名字；    <br />&#160;&#160;&#160;&#160;&#160; gethostbyname()：返回本机IP；</p>
<p>&#160;&#160; 第三部分编程题：</p>
<p>&#160;&#160;&#160; 1、从文件中读取字符串数据，反序显示并大小写转换。</p>
<p>&#160;&#160;&#160; 2、给定26字母表以及对应的密码表，编程实现加密及解密功能。</p>
<p>&#160; 第四部分思考题(正是传说中的字典纠错题)：</p>
<p>&#160;&#160;&#160;&#160; 用户在输入英文单词时经常出错，现对其进行就错。给定一个正确的英文词典，考虑纠错实现。1)指出思路。2)流程、算法难易程度及可能的改进策略。</p>
<p>一道算法题目答案</p>
<p>int Replace(Stringtype &amp;S,Stringtype T,Stringtype V);//将串S中所有子串T替换为V,并返回置换次数    <br />{     <br />for(n=0,i=1;i〈=Strlen(S)-Strlen(T)+1;i++) //注意i的取值范围     <br />if(!StrCompare(SubString(S,i,Strlen(T)),T)) //找到了与T匹配的子串     <br />{ //分别把T的前面和后面部分保存为head和tail     <br />StrAssign(head,SubString(S,1,i-1));     <br />StrAssign(tail,SubString(S,i+Strlen(T),Strlen(S)-i-Strlen(T)+1));     <br />StrAssign(S,Concat(head,V));     <br />StrAssign(S,Concat(S,tail)); //把head,V,tail连接为新串     <br />i+=Strlen(V); //当前指针跳到插入串以后     <br />n++;     <br />}//if     <br />return n;     <br />}//Replace     <br />分析:i+=Strlen(V);这一句是必需的,也是容易忽略的.如省掉这一句,则在某些情况下,会引起不希望的后果,虽然在大多数情况下没有影响.请思考:设S=&#8217;place&#8217;, T=&#8217;ace&#8217;, V=&#8217;face&#8217;,则省掉i+=Strlen(V);运行时会出现什么结果? （无限递归face）</p>
<pre><strong>百度2005年的笔试题</strong>

</pre>
<pre>
</pre>
<pre>

&#160;
</pre>
<pre>1.实现 void delete_char(char * str, char ch);

</pre>
<pre>&#160; 把str中所有的ch删掉

</pre>
<pre>

&#160;
</pre>
<pre>2.把字符串S中所有A子串换成B,这个没给函数原型

</pre>
<pre>

&#160;
</pre>
<pre>3.搜索引擎的日志要记录所有查询串,有一千万条查询,不重复的不超过三百万

</pre>
<pre>&#160; 要统计最热门的10条查询串. 内存&lt;1G. 字符串长 0-255

</pre>
<pre>&#160; (1) 主要解决思路 //具体用词和原题不大一样

</pre>
<pre>&#160; (2) 算法及其复杂度分析

</pre>
<pre>

&#160;
</pre>
<pre>4.有字典,设计一个英文拼写纠正算法 (1) 思想 (2) 算法及复杂度 (3) 改进

</pre>
<pre>

&#160;
</pre>
<pre>5. { aaa, bb, ccc, dd }, { bbb, ff }, { gg } 等一些字符串的集合

</pre>
<pre>&#160; 要求把交集不为空的集合并起来,如上例会得到 { aaa, bb, ccc, dd, ff }, {gg}

</pre>
<pre>&#160; (1) 思想 (2) 算法及复杂度 (3) 改进</pre>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/search-engine-optimization/%e7%99%be%e5%ba%a6%e7%ac%94%e8%af%95%e9%a2%98%e7%9b%ae%ef%bc%88%e8%bd%ac%ef%bc%89/feed</wfw:commentRss>
		</item>
		<item>
		<title>What People are searching for?</title>
		<link>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/what-people-are-searching-for</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/what-people-are-searching-for#comments</comments>
		<pubDate>Wed, 08 Aug 2007 03:33:47 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>SEO</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/what-people-are-searching-for</guid>
		<description><![CDATA[http://searchenginewatch.com/showPage.html?page=2156041
No Tags]]></description>
			<content:encoded><![CDATA[<p><a title="http://searchenginewatch.com/showPage.html?page=2156041" href="http://searchenginewatch.com/showPage.html?page=2156041">http://searchenginewatch.com/showPage.html?page=2156041</a></p>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/what-people-are-searching-for/feed</wfw:commentRss>
		</item>
		<item>
		<title>Did You Mean: Lucene?</title>
		<link>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/did-you-mean-lucene</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/did-you-mean-lucene#comments</comments>
		<pubDate>Wed, 08 Aug 2007 03:27:05 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>SEO</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/did-you-mean-lucene</guid>
		<description><![CDATA[
All modern search engines attempt to detect and correct spelling errors in users&#8217; search queries. Google, for example, was one of the first to offer such a facility, and today we barely notice when we are asked &#8220;Did you mean x?&#8221; after a slip on the keyboard. This article shows you one way of adding [...]]]></description>
			<content:encoded><![CDATA[<p><img height="1" src="http://today.java.net/im/a.gif" width="10">
<p>All modern search engines attempt to detect and correct spelling errors in users&#8217; search queries. Google, for example, was one of the first to offer such a facility, and today we barely notice when we are asked &#8220;<i>Did you mean x</i>?&#8221; after a slip on the keyboard. This article shows you one way of adding a &#8220;did you mean&#8221; suggestion facility to your own search applications using the Lucene Spell Checker, an extension written by Nicolas Maisonneuve and David Spencer.
<p>&nbsp;<br />
<h4>Techniques of Spell Checking</h4>
<p>Automatic spell checking has a long history. One important early paper was F. Damerau&#8217;s <i>A Technique for Computer Detection and Correction of Spelling Errors</i>, published in 1964, which introduced the idea of <i>minimum edit distance</i>. Briefly, the concept of edit distance quantifies the idea of one string being &#8220;close&#8221; to another, by counting the number of character edit operations (such as insertions, deletions and substitutions) that are needed to transform one string into the other. Using this metric, the best suggestions for a misspelling are those with the minimum edit distance.
<p>Another approach is the <i>similarity key technique</i>, in which words are transformed into some sort of key so that similarly spelled and, hopefully, misspelled words have the same key. To correct a misspelling simply involves creating the key for the misspelling and looking up dictionary words with the same key for a list of suggestions. Soundex is the best-known similarity key, and is often used for phonetic applications.
<p>A combination of minimum edit distance and similarity keys (<a href="http://aspell.net/metaphone/">metaphone</a>) is at the heart of the successful strategy used by <a href="http://aspell.sourceforge.net/">Aspell</a>, the leading open source spell checker. However, it is a third approach that underlies the implementation of the &#8220;did you mean&#8221; technique described in this article: letter <i>n-grams</i>.
<p>A letter <i>n</i>-gram is a sequence of <i>n</i> letters of a word. For instance, the word &#8220;lucene&#8221; can be divided into four 3-grams, also known as trigrams: &#8220;luc&#8221;, &#8220;uce&#8221;, &#8220;cen&#8221;, and &#8220;ene.&#8221;. Why is it useful to break words up like this? The intuition is that misspellings typically only affect a few of the constituent <i>n</i>-grams, so we can recognize the intended word just by looking through correctly spelled words for those that share a high proportion of <i>n</i>-grams with the misspelled word. There are various ways of computing this similarity measure, but one powerful way is to treat it as a classic search engine problem with an inverted index of <i>n</i>-grams into words. This is precisely the approach taken by Lucene Spell Checker. Let&#8217;s see how to use it.<br />
<h4>A Simple Search Application</h4>
<p>We&#8217;ll first build a very simple search interface that does not include the &#8220;did you mean&#8221; facility. It defines a single method that takes a search query string and returns a search result.
<pre><code>
package org.tiling.didyoumean;

import java.io.IOException;

import org.apache.lucene.queryParser.ParseException;

public interface SearchEngine {
    public SearchResult search(String queryString) throws IOException, ParseException;
}
  </code></pre>
<p>The search result is a <code>SearchResult</code> object, which is a JavaBean that exposes a list of hits (actually just the top hits, for simplicity) and a few other properties. I have omitted the constructor and getters in the listing here as they are boilerplate code. (The full source code is available in the accompanying download&#8211;see the &#8220;References&#8221; section at the end of the article.)
<pre><code>
package org.tiling.didyoumean;

import java.util.List;

public class SearchResult {

    private List topHits;
    private int totalHitCount;
    private long searchDuration;
    private String originalQuery;
    private String suggestedQuery;

}
  </code></pre>
<p>Here&#8217;s a very simple implementation of <code>SearchEngine</code> built with Lucene. It uses Lucene&#8217;s <code>QueryParser</code> to parse the search query string into a <code>Query</code> that is then used to perform the search. The Lucene <code>Hits</code> object is then mapped to an instance of our <code>SearchResult</code> class.
<pre><code>
package org.tiling.didyoumean;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;

public class SimpleSearchEngine implements SearchEngine {

    private String defaultField;
    private String nameField;
    private Directory originalIndexDirectory;
    private int maxHits;

    public SimpleSearchEngine(String defaultField, String nameField,
            Directory originalIndexDirectory, int maxHits) {
        this.defaultField = defaultField;
        this.nameField = nameField;
        this.originalIndexDirectory = originalIndexDirectory;
        this.maxHits = maxHits;
    }

    public SearchResult search(String queryString) throws IOException, ParseException {
        long startTime = System.currentTimeMillis();
        IndexSearcher is = null;
        try {
            is = new IndexSearcher(originalIndexDirectory);
            QueryParser queryParser = new QueryParser(defaultField, new StandardAnalyzer());
            queryParser.setOperator(QueryParser.DEFAULT_OPERATOR_AND);
            Query query = queryParser.parse(queryString);
            Hits hits = is.search(query);
            long endTime = System.currentTimeMillis();
            return new SearchResult(extractHits(hits), hits.length(), endTime - startTime, queryString);
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    private List extractHits(Hits hits) throws IOException {
        List hitList = new ArrayList();
        for (int i = 0, count = 0; i &lt; hits.length() &amp;&amp; count++ &lt; maxHits; i++) {
            hitList.add(hits.doc(i).getField(nameField).stringValue());
        }
        return hitList;
    }
}
  </code></pre>
<p>Note that an <code>IOException</code> may be thrown by Lucene if there is a problem reading the index (typically from disk). The <code>finally</code> clause closes the <code>IndexSearcher</code>, but propagates the exception to indicate the problem to the client, which is the MVC layer, in this case. </p>
<p>With these ingredients it is straightforward to write a user interface that accepts user queries and presents the search results back to the user. I chose <a href="http://www.springframework.org/">Spring</a>&#8217;s <a href="http://www.springframework.org/docs/reference/mvc.html">MVC</a> framework for this. Since this is an article about search and not about Spring, I won&#8217;t present any of the code for the user interface here&#8211;instead, please refer to the accompanying download. </p>
<p>Figure 1 is a screenshot of the search interface, running against an index of <a href="http://www.gutenberg.org/browse/authors/p#a292">texts</a> by <a href="http://en.wikipedia.org/wiki/Beatrix_Potter">Beatrix Potter</a> from <a href="http://www.gutenberg.org/">Project Gutenberg</a>. </p>
<p><img height="250" alt="Figure 1" src="http://today.java.net/images/2005/08/didyoumean_fig1.gif" width="550"><br /><i>Figure 1. A simple search application</i></p>
<p><a href="http://today.java.net/&lt;!--CS_NEXT_REF--&gt;"></a></p>
<h4>Adding &#8220;Did You Mean&#8221; to the Simple Search</h4>
<p>Next we&#8217;ll extend the search to prompt with &#8220;did you mean&#8221; suggestions for misspelled search terms in the query. Let&#8217;s go through this step by step in the following subsections. </p>
<h6>Generating a Spell Index</h6>
<p>The first step is to generate an index from the original index that includes the letter <i>n</i>-grams for each word in the original index. I shall refer to this index as the <i>spell index</i>. With the help of the Lucene Spell Checker, this is very easy:
<pre><code>
package org.tiling.didyoumean;

import java.io.IOException;

import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.spell.Dictionary;
import org.apache.lucene.search.spell.LuceneDictionary;
import org.apache.lucene.search.spell.SpellChecker;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

public class DidYouMeanIndexer {
    private static final String DEFAULT_FIELD = "contents";

    private static final String FIELD_OPTION = "f";
    private static final String ORIGINAL_INDEX_OPTION = "i";
    private static final String SPELL_INDEX_OPTION = "o";

    public void createSpellIndex(String field,
            Directory originalIndexDirectory,
            Directory spellIndexDirectory) throws IOException {

        IndexReader indexReader = null;
        try {
            indexReader = IndexReader.open(originalIndexDirectory);
            Dictionary dictionary = new LuceneDictionary(indexReader, field);
            SpellChecker spellChecker = new SpellChecker(spellIndexDirectory);
            spellChecker.indexDictionnary(dictionary);
        } finally {
            if (indexReader != null) {
                indexReader.close();
            }
        }
    }

}

  </code></pre>
<p>The <code>Dictionary</code> interface specifies a single method:
<pre><code>public Iterator getWordsIterator();</code></pre>
<p>that returns an iterator over the words in the dictionary. Here we use a <code>LuceneDictionary</code> object to read each word in the given <code>field</code> from the original index. We then create a <code>SpellChecker</code>, giving it a new index location to which to write the <i>n</i>-grams as it indexes the dictionary. </p>
<p>To create the spell index, you can instantiate a new <code>DidYouMeanIndexer</code> and invoke the <code>createSpellIndex()</code> method from your code. Alternatively, you can run <code>DidYouMeanIndexer</code> from the command line (the <code>main()</code> method is not shown in the above listing). </p>
<h6>The &#8220;Did You Mean&#8221; Search Engine</h6>
<p>Next, let&#8217;s turn back to our <code>SearchEngine</code> interface and look at the implementation of <code>DidYouMeanSearchEngine</code>. This implementation looks for query suggestions when the search results have low relevance.
<pre><code>
package org.tiling.didyoumean;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;

public class DidYouMeanSearchEngine implements SearchEngine {

    private String defaultField;
    private String nameField;
    private Directory originalIndexDirectory;
    private int maxHits;
    <b>private int minimumHits;
    private float minimumScore;
    private DidYouMeanParser didYouMeanParser;</b>

    public DidYouMeanSearchEngine(String defaultField, String nameField,
            Directory originalIndexDirectory,
            int maxHits, int minimumHits, float minimumScore,
            DidYouMeanParser didYouMeanParser) {

        this.defaultField = defaultField;
        this.nameField = nameField;
        this.originalIndexDirectory = originalIndexDirectory;
        this.maxHits = maxHits;
        this.minimumHits = minimumHits;
        this.minimumScore = minimumScore;
        this.didYouMeanParser = didYouMeanParser;
    }

    public SearchResult search(String queryString) throws IOException, ParseException {
        long startTime = System.currentTimeMillis();
        IndexSearcher is = null;
        try {
            is = new IndexSearcher(originalIndexDirectory);
            Query query = <b>didYouMeanParser.parse(queryString);</b>
            Hits hits = is.search(query);

            <b>String suggestedQueryString = null;
            if (hits.length() &lt; minimumHits || hits.score(0) &lt; minimumScore) {
                Query didYouMean = didYouMeanParser.suggest(queryString);
                if (didYouMean != null) {
                    suggestedQueryString = didYouMean.toString(defaultField);
                }
            }</b>

            long endTime = System.currentTimeMillis();
            return new SearchResult(extractHits(hits), hits.length(),
                    endTime - startTime, queryString, <b>suggestedQueryString)</b>;
        } finally {
            if (is != null) {
                is.close();
            }
        }
    }

    private List extractHits(Hits hits) throws IOException {
        List hitList = new ArrayList();
        for (int i = 0, count = 0; i &lt; hits.length() &amp;&amp; count++ &lt; maxHits; i++) {
            hitList.add(hits.doc(i).getField(nameField).stringValue());
        }
        return hitList;
    }

}

  </code></pre>
<h6>The &#8220;Did You Mean&#8221; Parser</h6>
<p>The key difference between the <code>DidYouMeanSearchEngine</code> class and the <code>SimpleSearchEngine</code> class is the introduction of the <code>DidYouMeanParser</code> interface. The <code>DidYouMeanParser</code> interface encapsulates a strategy both for parsing query strings and for suggesting spelling corrections for query strings:
<pre><code>
package org.tiling.didyoumean;

import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;

public interface DidYouMeanParser {
    public Query parse(String queryString) throws ParseException;
    public Query suggest(String queryString) throws ParseException;
}

  </code></pre>
<p>The <code>DidYouMeanSearchEngine</code> only asks the <code>DidYouMeanParser</code> for a suggested query if the number of hits returned falls below a minimum threshold (the <code>minimumHits</code> property), or if the relevance of the top hit falls below a minimum threshold (the <code>minimumScore</code> property). Of course, you may choose to implement your own criteria for when to make a &#8220;did you mean&#8221; suggestion, but this rule is simple and effective. </p>
<p>The first implementation of <code>DidYouMeanParser</code> is straightforward:
<pre><code>
package org.tiling.didyoumean;

import java.io.IOException;

import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.spell.SpellChecker;
import org.apache.lucene.store.Directory;

public class SimpleDidYouMeanParser implements DidYouMeanParser {

    private String defaultField;
    private Directory spellIndexDirectory;

    public SimpleDidYouMeanParser(String defaultField, Directory spellIndexDirectory) {
        this.defaultField = defaultField;
        this.spellIndexDirectory = spellIndexDirectory;
    }

    public Query parse(String queryString) {
        return new TermQuery(new Term(defaultField, queryString));
    }

    public Query suggest(String queryString) throws ParseException {
        try {
            SpellChecker spellChecker = new SpellChecker(spellIndexDirectory);
            if (spellChecker.exist(queryString)) {
                return null;
            }
            <b>String[] similarWords = spellChecker.suggestSimilar(queryString, 1);</b>
            if (similarWords.length == 0) {
                return null;
            }
            return new TermQuery(new Term(defaultField, similarWords[0]));
        } catch (IOException e) {
            throw new ParseException(e.getMessage());
        }
    }

}

  </code></pre>
<p>The <code>parse()</code> method simply constructs a new <code>TermQuery</code> from the query. (This means that <code>SimpleDidYouMeanParser</code> only works with single-word queries, a deficiency we shall remedy later.) The <code>suggest()</code> implementation is more interesting. Just as when we created the spell index earlier, we construct a new <code>SpellChecker</code> with the index location for the spell index. This time, however, we just read from the index. First we check if the query word is in the index&#8211;if it is, we assume that it is correctly spelled, and make no suggestion by returning <code>null</code>. If instead the query word is not in the index, then we ask the spell checker for a single suggestion, by invoking the <code>suggestSimilar()</code> method. Of course, it may happen that no words are similar enough to the input, so we return <code>null</code> again. But if a suggestion is found, then it is returned as a new <code>TermQuery</code>. </p>
<p>Whew! Let&#8217;s see it in action after everything has been wired up using Spring. Figure 2 is a screenshot for the misspelled query &#8220;lettice.&#8221; </p>
<p><img height="250" alt="Figure 2" src="http://today.java.net/images/2005/08/didyoumean_fig2.gif" width="550"><br /><i>Figure 2. Suggesting a sensible alternative query</i></p>
<p><a href="http://today.java.net/&lt;!--CS_NEXT_REF--&gt;"></a></p>
<h4>How It Works</h4>
<p>There&#8217;s a lot going on in the <code>suggestSimilar()</code> method of <code>SpellChecker</code>, so let&#8217;s follow it through with an example. Take the correctly spelled word &#8220;lettuce,&#8221; which appears in the Beatrix Potter texts I&#8217;ve used for this article. In the original index, where each Lucene document corresponds to a text, &#8220;lettuce&#8221; appears in two Lucene documents in the <code>contents</code> field. On the other hand, the spell index contains a whole Lucene document for every distinct word in the original index. Each document has a number of fields, as shown here with the values for the document representing the word &#8220;lettuce.&#8221; </p>
<p>Field name<br />Field values</p>
<p><code>word</code><br /><code>lettuce</code></p>
<p><code>start3</code><br /><code>let</code></p>
<p><code>gram3</code><br /><code>let ett ttu tuc uce</code></p>
<p><code>end3</code><br /><code>uce</code></p>
<p><code>start4</code><br /><code>lett</code></p>
<p><code>gram4</code><br /><code>lett ettu ttuc tuce</code></p>
<p><code>end4</code><br /><code>tuce</code></p>
<p>Notice how both trigrams and 4-grams are indexed. In fact, precisely which <i>n</i>-grams are indexed depends on the size of the word. For very short words, unigrams and bigrams are indexed, whereas for longer words, trigrams and 4-grams are indexed. </p>
<p>The <code>suggestSimilar()</code> method forms a Lucene query to search the spell index for candidate suggestions. For the misspelling &#8220;lettice&#8221; the query is as follows (split over two lines to make it easier to read):
<pre><code>
start3:let^2.0 end3:ice gram3:let gram3:ett gram3:tti gram3:tic gram3:ice
start4:lett^2.0 end4:tice gram4:lett gram4:etti gram4:ttic gram4:tice
  </code></pre>
<p>The start <i>n</i>-grams are given more weight than the other <i>n</i>-grams in the word; here, they are boosted by a factor of two, signified by the <code>^2.0</code> notation. Another reason to index the start and end <i>n</i>-grams separately is because they are positional, unlike the other <i>n</i>-grams. For example, the words &#8220;eat&#8221; and &#8220;ate&#8221; have the same set of unigrams and bigrams (<code>gram1:e gram1:a gram1:t gram2:ea gram2:at</code>), so they need the start and end fields to distinguish them (<code>start1:e end1:t start2:ea end2:at</code> for &#8220;eat,&#8221; and <code>start1:a end1:e start2:at end2:te</code> for &#8220;ate&#8221;). </p>
<p>Using a Lucene index browser, such as the excellent <a href="http://www.getopt.org/luke/">Luke</a>&#8211;the Lucene Index Toolbox, we can manually run this query against the spell index. Figure 3 shows what we get. </p>
<p><a href="http://today.java.net/images/2005/08/didyoumean_fig3.gif"><img height="175" alt="Figure 3" src="http://today.java.net/images/2005/08/didyoumean_fig3_sm.gif" width="220" vspace="4" border="0"></a><br />Figure 3. Browsing the spell index&#8211;click image for full-size screenshot</p>
<p>But the top hit is &#8220;letting,&#8221; not &#8220;lettuce,&#8221; which the web app presented us with. What&#8217;s going on? The answer is that the Lucene Spell Checker ranks suggestions by edit distance, not by search relevance. The string &#8220;lettice&#8221; differs from &#8220;lettuce&#8221; by a single substitution, whereas &#8220;letting&#8221; is two substitutions away. </p>
<h4>Supporting Composite Queries</h4>
<p><code>SimpleSearchEngine</code> supports composite queries&#8211;that is, queries that are composed of a set of clauses; for example, <code>lettuce parsley</code>, which means &#8220;find documents in which both of the words &#8216;lettuce&#8217; and &#8216;parsley&#8217; appear.&#8221; As noted above, <code>DidYouMeanSearchEngine</code> with <code>SimpleDidYouMeanParser</code> only supports single-word queries, so let&#8217;s see how we can fix it to support composite queries. </p>
<p><code>CompositeDidYouMeanParser</code> is an implementation of <code>DidYouMeanParser</code> for use by <code>DidYouMeanSearchEngine</code> that supports composite queries. Recall that the <code>DidYouMeanParser</code> interface has a <code>parse()</code> method and a <code>suggest()</code> method, both of which take query strings and return Lucene <code>Query</code> objects. The implementation of <code>parse()</code> is simple: it uses Lucene&#8217;s <code>QueryParser</code>, which has built-in support for composite queries. The implementation of <code>suggest()</code> is a little more tricky. It relies on the <code>getFieldQuery()</code> extensibility hook provided by <code>QueryParser</code>, so if a term (or a word in a phrase) is misspelled, then it is replaced with the best suggestion. If no terms (or words in a phrase) in the whole query are misspelled, then <code>suggest()</code> returns <code>null</code>. </p>
<p>Figure 4 is a screenshot for the misspelled composite query &#8220;lettice parslee.&#8221; </p>
<p><img height="250" alt="Figure 4" src="http://today.java.net/images/2005/08/didyoumean_fig4.gif" width="550"><br /><i>Figure 4. Correcting the spelling of multiple query terms</i></p>
<h4>Ensuring High-Quality Suggestions</h4>
<p>Having a clever algorithm for detecting and correcting spelling errors is a good start, but you need a good source of correctly spelled words to ensure the suggestions are of a high quality. So far, we have used the terms in the original index as the source of words (by constructing a <code>LuceneDictionary</code>). There is a downside to this approach: the content that was indexed will almost certainly contain spelling errors, so there is a good chance that certain query suggestions will be misspelled. </p>
<p>You might think that using a compiled <a href="http://wordlist.sourceforge.net/">word list</a> might help. However, even the largest dictionaries fall short in word coverage for proper nouns and newly coined words (e.g., technical phrases), so a correctly spelled query term that is not in the dictionary will be incorrectly marked as a misspelling. The user would then be prompted with a distracting alternative query suggestion. (As a side note, Lucene Spell Checker provides an implementation of <code>Dictionary</code>, <code>PlainTextDictionary</code>, which can read words from a word list such as <em>/usr/dict/words</em> commonly found on Unix systems. Use this to do regular spell checking against a dictionary.) </p>
<p>Lucene Spell Checker provides a mechanism to solve this problem, while still using the original index as the source of words. The <code>suggestSimilar()</code> method of <code>SpellChecker</code> is overloaded to support secondary sorting of the suggested words by document frequency in an index; for example:
<pre><code>
spellChecker.suggestSimilar(queryText, 1, originalIndexReader, defaultField, true);
  </code></pre>
<p>This call restricts suggestions to those words that are more popular (<code>true</code>) in the original index than the query term. On the plausible assumption that across the whole set of documents, misspellings are less common than the correctly spelled instances of the word, this modification will improve the quality of suggestions, even in document collections containing misspellings. </p>
<h6>Zeitgeist</h6>
<p>Large search engines use user queries for the source of suggestions. The logic is: if you don&#8217;t understand what a user is asking for, compare it to what other users ask for, as someone else is likely to have searched for something similar. </p>
<p>To implement this strategy, each user query submitted to the system should be indexed in the spell index in order to provide a proper record of query frequencies. (All of the main search engines publish their <a href="http://searchenginewatch.com/facts/article.php/2156041">most popular search terms</a>, which are ultimately derived from such an index.) Then, by using the overloaded <code>suggestSimilar()</code> method introduced in the previous section, suggestions will be ranked firstly by edit distance and secondly by user popularity. </p>
<h4>Conclusion</h4>
<p>Spell checking users&#8217; search queries is a nice feature, and relatively easy to add to a Lucene-powered search application, as this article has shown. Most of the time, the corrections suggested are good ones, but there is plenty of ongoing research in the information retrieval community on improving spell check algorithms (see &#8220;References,&#8221; below). I think we will continue to see the fruits of such research in open source libraries like Lucene Spell Checker. </p>
<h4>References</h4>
<ul>
<li>Download <a href="http://today.java.net/today/2005/08/09/didyoumean.zip">the code supporting this article</a>. The distribution includes everything you need to get up and running quickly, including a pre-built index that you can unpack on your filesystem, and a WAR file to drop into your servlet container.
<li>I used <a href="http://lucene.apache.org/">Lucene 1.4.3</a> and <a href="http://wiki.apache.org/jakarta-lucene/SpellChecker">Lucene Spell Checker 1.1</a> in this article.
<li>David Spencer, who created Lucene Spell Checker, has an interesting <a href="http://www.searchmorph.com/">website</a> dedicated to search experiments.
<li><a href="http://aspell.sourceforge.net/">Aspell</a> and its Java cousin <a href="http://jazzy.sourceforge.net/">Jazzy</a> are good general-purpose spell checkers.
<li>I leaned heavily on Thomas Risberg&#8217;s thorough &#8220;<a href="http://www.springframework.org/docs/MVC-step-by-step/Spring-MVC-step-by-step.html">Developing a Spring Framework MVC Application Step-by-Step</a>&#8221; for building the Spring Search UI.
<li><i><a href="http://portal.acm.org/citation.cfm?doid=363958.363994">A Technique for Computer Detection and Correction of Spelling Errors</a></i> (<em>Communications of the ACM,</em> 7(3), 171 - 176; 1964), by Fred J. Damerau, is an early paper on spelling correction.
<li><i><a href="http://portal.acm.org/citation.cfm?id=146380&amp;coll=portal&amp;dl=ACM&amp;CFID=30871880&amp;CFTOKEN=81445918">Techniques for Automatically Correcting Words in Text</a></i> (<em>ACM Computing Surveys,</em> 24(4), 377-439; 1992), by Karen Kukich, is the definitive survey article on spelling correction.
<li><a href="http://www-cs-faculty.stanford.edu/~knuth/taocp.html">The Art of Computer Programming, Volume 3, Sorting and Searching</a> (Addison-Wesley; 1998), by Donald E. Knuth, contains the definitive description of the Soundex algorithm.
<li>&#8220;<a href="http://xldb.di.fc.ul.pt/data/Publications_attach/spellcheck.pdf">Spelling Correction for Search Engine Queries</a>,&#8221; by Bruno Martins and Mario J. Silva, solves the same problem as the present article using a set of heuristics to make spelling suggestions.
<li><i><a href="http://acl.ldc.upenn.edu/acl2004/emnlp/pdf/Cucerzan.pdf">Spelling Correction as an Iterative Process that Exploits the Collective Knowledge of Web Users</a></i> (<em>2004 Proceedings of EMNLP</em> 2004 293-300), by S. Cucerzan and E. Brill, is an interesting paper that talks about how spelling correction can be driven from knowledge acquired by a search engine.
<li>Unsurprisingly, <a href="http://labs.google.com/papers.html">Google</a>, <a href="http://research.yahoo.com/publication.shtml">Yahoo</a>, and <a href="http://research.microsoft.com/research/detail.aspx?id=7">Microsoft</a> all have a lot of published information on information retrieval. </li>
</ul>
<p><em><a href="http://today.java.net/pub/au/294">Tom White</a> is lead Java developer at Kizoom, a leading U.K. software company in the delivery of personalized travel information.</em><img height="1" alt="" src="http://sunjnet.112.2O7.net/b/ss/sunjnet,sunglobal/1/G.5-PD-R/s51836214177341?[AQB]&amp;ndh=1&amp;t=8/7/2007%2011%3A24%3A1%203%20-480&amp;pageName=jnet-editorial%3A/lpt/a/211&amp;ch=jnet-editorial%3Atechnical%20articles&amp;h1=jnet-editorial%3Atechnical%20articles&amp;c2=jnet-editorial%3A&amp;g=http%3A//today.java.net/lpt/a/211&amp;r=http%3A//tag.csdn.net/Article/9e704864-8ab3-42b8-b00e-894e0322846b.html&amp;s=1024x768&amp;c=16&amp;j=1.3&amp;v=Y&amp;k=Y&amp;bw=800&amp;bh=342&amp;ct=lan&amp;hp=N&amp;[AQE]" width="1" border="0"></p>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/did-you-mean-lucene/feed</wfw:commentRss>
		</item>
		<item>
		<title>SpellChecker Java Search API</title>
		<link>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/spellchecker-java-search-api</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/spellchecker-java-search-api#comments</comments>
		<pubDate>Wed, 08 Aug 2007 03:16:28 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>SEO</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/spellchecker-java-search-api</guid>
		<description><![CDATA[&#160;
July 9, 2007 on 9:20 pm &#124; InJava&#124;July9,2007on9:20pm&#124;InJava&#124;
在寫程式時，基本上都一定要為錯誤的輸入作檢查或修正。在写程式时，基本上都一定要为错误的输入作检查或修正。 這是基本可以用來檢查一個程式有沒有偷懶/偷工減料的最簡單方法。这是基本可以用来检查一个程式有没有偷懒/偷工减料的最简单方法。
在上電腦的基本課時，應該一定會提到有關 GIGO(garbagein,garbageout; 垃圾輸入, 無用輸出)。在上电脑的基本课时，应该一定会提到有关GIGO(garbagein,garbageout;垃圾输入,无用输出)。 就是說電腦很苯，當輸入的數據是垃圾，輸出就一定只會是垃圾。就是说电脑很苯，当输入的数据是垃圾，输出就一定只会是垃圾。 電腦會出錯，可是人類更易出錯，而且犯的錯誤更多。电脑会出错，可是人类更易出错，而且犯的错误更多。
最基本的，是能在輸入時即時先作出反應和指出錯誤。最基本的，是能在输入时即时先作出反应和指出错误。 最簡單是檢查數據的型態和空白(第一類)，而一個比較像樣的程式都有數字、時間、日期、大小和特定格式 (如 email 或 UUID) 的 Pattern 檢查(第二類)。最简单是检查数据的型态和空白(第一类)，而一个比较像样的程式都有数字、时间、日期、大小和特定格式(如email或UUID)的Pattern检查(第二类)。 造得仔細一點的程式都有會進一步的檢查，就是數據有效性的檢查；例如年月日的組合是否合理，沒有沒串錯字，重復性，在 database 能不能找到相對應的 ID 之類的(第三類)。造得仔细一点的程式都有会进一步的检查，就是数据有效性的检查；例如年月日的组合是否合理，没有没串错字，重复性，在database能不能找到相对应的ID之类的(第三类)。 而最好的則會著重與人的互動關係，清楚的錯誤說明，能在使用者保持集中力的時間內反應(好像大約三秒)，自動的修正、建議(第四類)。而最好的则会着重与人的互动关系，清楚的错误说明，能在使用者保持集中力的时间内反应(好象大约三秒)，自动的修正、建议(第四类)。
實例实例
第一類:Yahoo 字典第一类:Yahoo字典雖然它說 “請輸入單字查詢，中英文皆可” ，可是日文,法文,德文也能過。虽然它说“请输入单字查询，中英文皆可”，可是日文,法文,德文也能过。 假如輸入簡体字或日文漢字它也不會了解。假如输入简体字或日文汉字它也不会了解。
第二類: 一般的網頁上常見的 “E-mail this page” 表格(我一直很好奇誰會用)。第二类:一般的网页上常见的“E-mailthispage”表格(我一直很好奇谁会用)。 例如這頁的 footer。例如这页的footer。 它會要求你依一定的格式輸入 email，可是在都不會知道這個 email 是否正確的。它会要求你依一定的格式输入email，可是在都不会知道这个email是否正确的。
第三類: 現時 forum 的 Signup form。第三类:现时forum的Signupform。 它會以寄出 validation code 的方式檢查你輸入的 email。它会以寄出validationcode的方式检查你输入的email。
第四類: Google Suggest [...]]]></description>
			<content:encoded><![CDATA[<h4>&nbsp;</h4>
<p><small>July 9, 2007 on 9:20 pm | In<a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://hkdennis2k.homeip.net/cat/java/&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN">Java</a>|</small><small>July9,2007on9:20pm|In<a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://hkdennis2k.homeip.net/cat/java/&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN">Java</a>|</small>
<p>在寫程式時，基本上都一定要為錯誤的輸入作檢查或修正。在写程式时，基本上都一定要为错误的输入作检查或修正。 這是基本可以用來檢查一個程式有沒有偷懶/偷工減料的最簡單方法。这是基本可以用来检查一个程式有没有偷懒/偷工减料的最简单方法。
<p>在上電腦的基本課時，應該一定會提到有關 GIGO(garbagein,garbageout; 垃圾輸入, 無用輸出)。在上电脑的基本课时，应该一定会提到有关GIGO(garbagein,garbageout;垃圾输入,无用输出)。 就是說電腦很苯，當輸入的數據是垃圾，輸出就一定只會是垃圾。就是说电脑很苯，当输入的数据是垃圾，输出就一定只会是垃圾。 電腦會出錯，可是人類更易出錯，而且犯的錯誤更多。电脑会出错，可是人类更易出错，而且犯的错误更多。
<p>最基本的，是能在輸入時即時先作出反應和指出錯誤。最基本的，是能在输入时即时先作出反应和指出错误。 最簡單是檢查數據的型態和空白(第一類)，而一個比較像樣的程式都有數字、時間、日期、大小和特定格式 (如 email 或 UUID) 的 Pattern 檢查(第二類)。最简单是检查数据的型态和空白(第一类)，而一个比较像样的程式都有数字、时间、日期、大小和特定格式(如email或UUID)的Pattern检查(第二类)。 造得仔細一點的程式都有會進一步的檢查，就是數據有效性的檢查；例如年月日的組合是否合理，沒有沒串錯字，重復性，在 database 能不能找到相對應的 ID 之類的(第三類)。造得仔细一点的程式都有会进一步的检查，就是数据有效性的检查；例如年月日的组合是否合理，没有没串错字，重复性，在database能不能找到相对应的ID之类的(第三类)。 而最好的則會著重與人的互動關係，清楚的錯誤說明，能在使用者保持集中力的時間內反應(好像大約三秒)，自動的修正、建議(第四類)。而最好的则会着重与人的互动关系，清楚的错误说明，能在使用者保持集中力的时间内反应(好象大约三秒)，自动的修正、建议(第四类)。
<p>實例实例
<p>第一類:<a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://hk.dictionary.yahoo.com/&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN">Yahoo 字典</a>第一类:<a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://hk.dictionary.yahoo.com/&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN">Yahoo字典</a><br />雖然它說 “請輸入單字查詢，中英文皆可” ，可是日文,法文,德文也能過。虽然它说“请输入单字查询，中英文皆可”，可是日文,法文,德文也能过。 假如輸入簡体字或日文漢字它也不會了解。假如输入简体字或日文汉字它也不会了解。
<p>第二類: 一般的網頁上常見的 “E-mail this page” 表格(我一直很好奇誰會用)。第二类:一般的网页上常见的“E-mailthispage”表格(我一直很好奇谁会用)。 例如<a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://www.microsoft.com/hk/&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN#cArea">這頁</a>的 footer。例如<a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://www.microsoft.com/hk/&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN#cArea">这页</a>的footer。 <br />它會要求你依一定的格式輸入 email，可是在都不會知道這個 email 是否正確的。它会要求你依一定的格式输入email，可是在都不会知道这个email是否正确的。
<p>第三類: 現時 forum 的 Signup form。第三类:现时forum的Signupform。 <br />它會以寄出 validation code 的方式檢查你輸入的 email。它会以寄出validationcode的方式检查你输入的email。
<p>第四類: Google Suggest / Gmail第四类:GoogleSuggest/Gmail <br />能在在未按下 sutmit 前給建議，修正，甚至 auto-complete。能在在未按下sutmit前给建议，修正，甚至auto-complete。
<p>以上例子都是 web-application 的原因只是誰也看得到。以上例子都是web-application的原因只是谁也看得到。 事實上 client application 的例子更多。事实上clientapplication的例子更多。 <br />如: Notepad vs UltraEdit vs Microsoft Word vs Eclipse IDE.如:NotepadvsUltraEditvsMicrosoftWordvsEclipseIDE.
<p>好像越說越遠了。好像越说越远了。 回到正題，其中最麻煩，最難實作的是自動化的修正建議。回到正题，其中最麻烦，最难实作的是自动化的修正建议。 因為它的目的不做到 GIGO，這不是和上文所說的電腦很苯相反嗎？因为它的目的不做到GIGO，这不是和上文所说的电脑很苯相反吗？ 沒有矛盾，它是建基在數據當中正確的部份。没有矛盾，它是建基在数据当中正确的部份。
<p>再回到主題，英文串字修正是以沒串錯的部份基礎。再回到主题，英文串字修正是以没串错的部份基础。 (從語言角度上著手也可以，不過這是人類善長的工作，不在本文內容)(从语言角度上着手也可以，不过这是人类善长的工作，不在本文内容) <br />英文是由字母組合而成，而它們的組合次序和方式，則可以提示出正確的建議。英文是由字母组合而成，而它们的组合次序和方式，则可以提示出正确的建议。
<p>用實例來說或會比較易明白： 例如 Monstor (Monster 的誤寫)。用实例来说或会比较易明白：例如Monstor(Monster的误写)。 以 n-Gram 方式拆解的話，就可以得到 mon, ons, nst, sto, tor。以n-Gram方式拆解的话，就可以得到mon,ons,nst,sto,tor。 如果和 Monster 比較(mon, mon, nst, ste, ter)，其中　3/5 * 3/5 都是對的(因為是互相比較, 所以是兩組)。如果和Monster比较(mon,mon,nst,ste,ter)，其中3/5*3/5都是对的(因为是互相比较,所以是两组)。 而如果和 “monsters inc” 比較，則只有 3/5 * 3/8。而如果和“monstersinc”比较，则只有3/5*3/8。 而拿來和 apple 比較，則完全不付合。而拿来和apple比较，则完全不付合。 只要事先為字並建立 index，用這方法可以快速得到幾個相近的詞語。只要事先为字并建立index，用这方法可以快速得到几个相近的词语。
<p>一般，英文只要有 3-gram 和 4-gram 就可以有不錯的結果。一般，英文只要有3-gram和4-gram就可以有不错的结果。 當然啦，這等零件老早就有寫了出來。当然啦，这等零件老早就有写了出来。 如果你是用 Lucene 1.4 的話，花一點心思也可以自己寫出來，而如果用 Lucene 2.0，則已經有現成的 library 可用。如果你是用Lucene1.4的话，花一点心思也可以自己写出来，而如果用Lucene2.0，则已经有现成的library可用。
<p><a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://wiki.apache.org/jakarta-lucene/SpellChecker&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN">參考:&nbsp; SpellChecker - Lucene-java Wiki</a><a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://wiki.apache.org/jakarta-lucene/SpellChecker&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN">参考:SpellChecker-Lucene-javaWiki</a><br /><a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://wiki.apache.org/jakarta-lucene/SpellChecker&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN">參考:&nbsp; Lucene 2.0org.apache.lucene.search.spell</a><a href="http://64.233.179.104/translate_c?hl=zh-CN&amp;u=http://wiki.apache.org/jakarta-lucene/SpellChecker&amp;prev=/search%3Fq%3Dlucene%2BspellChecker%26start%3D10%26complete%3D1%26hl%3Dzh-CN%26newwindow%3D1%26rls%3DGFRI,GFRI:2007-17,GFRI:en%26sa%3DN">参考:Lucene2.0org.apache.lucene.search.spell</a>
<p>就算不用 Lucene，自已利用 php+mysql 也可以寫得到類似的功能，只要依著以上的方式建立 index table 和設計出一句 inner join SQL 就可以。就算不用Lucene，自已利用php+mysql也可以写得到类似的功能，只要依着以上的方式建立indextable和设计出一句innerjoinSQL就可以。
<p>9 July 20079July2007 <br />DennisDennis </p>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/spellchecker-java-search-api/feed</wfw:commentRss>
		</item>
		<item>
		<title>我的一个Java xmlrpc-apache操纵wordPress blog的例子</title>
		<link>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/%e6%88%91%e7%9a%84%e4%b8%80%e4%b8%aajava-xmlrpc-apache%e6%93%8d%e7%ba%b5wordpress-blog%e7%9a%84%e4%be%8b%e5%ad%90</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/%e6%88%91%e7%9a%84%e4%b8%80%e4%b8%aajava-xmlrpc-apache%e6%93%8d%e7%ba%b5wordpress-blog%e7%9a%84%e4%be%8b%e5%ad%90#comments</comments>
		<pubDate>Wed, 01 Aug 2007 14:27:59 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>SEO</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/%e6%88%91%e7%9a%84%e4%b8%80%e4%b8%aajava-xmlrpc-apache%e6%93%8d%e7%ba%b5wordpress-blog%e7%9a%84%e4%be%8b%e5%ad%90</guid>
		<description><![CDATA[package com.enablingtech.rpc;
import java.net.MalformedURLException;import java.util.Hashtable;import java.util.Vector;
import org.apache.xmlrpc.XmlRpc;import org.apache.xmlrpc.XmlRpcClient;import org.apache.xmlrpc.XmlRpcException;
&#160;
public class Test2 {&#160;&#160;&#160; public static void main(String[] args) {&#160;&#160;&#160;&#160;&#160;&#160;&#160; try {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; XmlRpc.setDriver(&#8221;org.apache.xerces.parsers.SAXParser&#8221;);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; XmlRpcClient xmlrpc = new XmlRpcClient(&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#8220;http://网址/xmlrpc.php&#8221;);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Vector params = new Vector();&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; //params.addElement(&#8221;1&#8243;);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; params.addElement(&#8221;776&#8243;);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; params.add(&#8221;用户名&#8221;);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; params.add(&#8221;密码&#8221;);
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Vector mp = (Vector)xmlrpc.execute(&#8221;mt.getRecentPostTitles&#8221;,&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; params);&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(mp.get(0));&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(mp.get(1));&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch (MalformedURLException e) {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(e.toString());&#160;&#160;&#160;&#160;&#160;&#160;&#160; } catch (XmlRpcException e) {&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; System.out.println(e.toString());&#160;&#160;&#160;&#160;&#160;&#160;&#160; } [...]]]></description>
			<content:encoded><![CDATA[<p>package com.enablingtech.rpc;
<p>import java.net.MalformedURLException;<br />import java.util.Hashtable;<br />import java.util.Vector;
<p>import org.apache.xmlrpc.XmlRpc;<br />import org.apache.xmlrpc.XmlRpcClient;<br />import org.apache.xmlrpc.XmlRpcException;
<p>&nbsp;
<p>public class Test2 {<br />&nbsp;&nbsp;&nbsp; public static void main(String[] args) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XmlRpc.setDriver(&#8221;org.apache.xerces.parsers.SAXParser&#8221;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XmlRpcClient xmlrpc = new XmlRpcClient(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;<a href="http://网址/xmlrpc.php&quot;);">http://网址/xmlrpc.php&#8221;);</a><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector params = new Vector();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //params.addElement(&#8221;1&#8243;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params.addElement(&#8221;776&#8243;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params.add(&#8221;用户名&#8221;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params.add(&#8221;密码&#8221;);
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Vector mp = (Vector)xmlrpc.execute(&#8221;mt.getRecentPostTitles&#8221;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; params);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(mp.get(0));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(mp.get(1));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (MalformedURLException e) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e.toString());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (XmlRpcException e) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(e.toString());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception e) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />}</p>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/%e6%88%91%e7%9a%84%e4%b8%80%e4%b8%aajava-xmlrpc-apache%e6%93%8d%e7%ba%b5wordpress-blog%e7%9a%84%e4%be%8b%e5%ad%90/feed</wfw:commentRss>
		</item>
		<item>
		<title>小试XML-RPC（浏览器javascript与服务器java通信）[转]</title>
		<link>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/%e5%b0%8f%e8%af%95xml-rpc%ef%bc%88%e6%b5%8f%e8%a7%88%e5%99%a8javascript%e4%b8%8e%e6%9c%8d%e5%8a%a1%e5%99%a8java%e9%80%9a%e4%bf%a1%ef%bc%89%e8%bd%ac</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/%e5%b0%8f%e8%af%95xml-rpc%ef%bc%88%e6%b5%8f%e8%a7%88%e5%99%a8javascript%e4%b8%8e%e6%9c%8d%e5%8a%a1%e5%99%a8java%e9%80%9a%e4%bf%a1%ef%bc%89%e8%bd%ac#comments</comments>
		<pubDate>Wed, 01 Aug 2007 14:08:26 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>SEO</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/%e5%b0%8f%e8%af%95xml-rpc%ef%bc%88%e6%b5%8f%e8%a7%88%e5%99%a8javascript%e4%b8%8e%e6%9c%8d%e5%8a%a1%e5%99%a8java%e9%80%9a%e4%bf%a1%ef%bc%89%e8%bd%ac</guid>
		<description><![CDATA[From http://www.blogjava.net/mstar/
&#160;&#160; 前些天无意中发现了XML-RPC（不过笑我才发现啊），总想找个机会摆弄摆弄。毕业论文基本上弄完了，所以决定今天把它弄明白。XML-RPC的最大用处，我首先想到的是浏览器在不刷新页面的情况下与服务器通信，请求数据。下面我就说一下我用XML-RPC是怎么实现的。
第一步：选择XML-RPC实现。XML-RPC的一个很大优势就是 它是一个标准，并且各种开发环境下都有实现（酷），这是它能够轻松跨平台的原因。javascript有3个实现。我看了一下最好的应该是jsolait（JavaScript o Lait）的实现了。因为他不仅仅是一个xml-rpc的实现，除此之外还有很多javascript库,详细内容请看这里（http://jsolait.net/）。java的实现就更多了，我当然毫不犹豫地选择apache的。详细内容看这里（http://ws.apache.org/xmlrpc/）
第二步：建立服务。用java建立xml-rpc有两种方式，一种是单独开个端口，一种是用servlet。我们客户端是用javascript，那么服务端用servlet是再好不过的了。如何使用apache的xml-rpc，请详细看apache的资料。（大哥你不会连servlet也不会建吧，那你还是不要往下看了）。代码如下：这是一个sayHello的服务类：
public class&#160;HelloService&#160;{ public&#160;String&#160;sayHello(String&#160;name){ return &#8220;Hello:&#160;&#8221;+name+&#8221;&#160;!&#8221;;&#160;}}
下面是一个Math服务类：
public class&#160;MathService&#160;{ public double&#160;add(Vector&#160;v){ double&#160;a&#160;=&#160;Double.parseDouble((String)v.get(0)); double&#160;b&#160;=&#160;Double.parseDouble((String)v.get(1)); return&#160;a+b;&#160;} public double&#160;mult(Vector&#160;v){ double&#160;a&#160;=&#160;Double.parseDouble((String)v.get(0)); double&#160;b&#160;=&#160;Double.parseDouble((String)v.get(1)); return&#160;a*b;&#160;}}
接着是Servlet啦，作为RPC Server用的，这段代码比较经典，很多资料上都有。
public class&#160;RpcServer&#160;extends&#160;HttpServlet&#160;{ protected void&#160;doPost(HttpServletRequest&#160;request,&#160;&#160;&#160;HttpServletResponse&#160;response)&#160;throws&#160;ServletException,&#160;IOException&#160;{&#160;&#160;XmlRpcServer&#160;xmlrpc&#160;= new&#160;XmlRpcServer();&#160;&#160;xmlrpc.addHandler(&#8221;HelloService&#8221;,&#160;new&#160;HelloService());&#160;&#160;xmlrpc.addHandler(&#8221;MathService&#8221;,new&#160;MathService()); byte[]&#160;result&#160;=&#160;xmlrpc.execute(request.getInputStream());&#160;&#160;response.setContentType(&#8221;text/xml&#8221;);&#160;&#160;response.setContentLength(result.length);&#160;&#160;OutputStream&#160;out =&#160;response.getOutputStream(); out.write(result); out.flush();&#160;}}
主要是这三句：XmlRpcServer xmlrpc = new XmlRpcServer();xmlrpc.addHandler(&#8221;HelloService&#8221;, new HelloService());xmlrpc.addHandler(&#8221;MathService&#8221;,new MathService());一定要记牢Handler的名字，就是第一个参数，因为客户端就靠他来表示要调用的方法呢。
行了现在可以在web.xml中写入配置了：
 &#60;servlet&#62; &#60;servlet-name&#62;RpcServer&#60;/servlet-name&#62; &#60;servlet-class&#62;org.mstar.rpc.RpcServer&#60;/servlet-class&#62; &#60;/servlet&#62; &#60;servlet-mapping&#62; &#60;servlet-name&#62;RpcServer&#60;/servlet-name&#62; &#60;url-pattern&#62;/RpcServer&#60;/url-pattern&#62; &#60;/servlet-mapping&#62;
至此，服务端的工作已经完成，启动应用服务器就行了。
下面是javacript的实现，这也是难点（其实不难理解，只是没有中文材料）。把jsolait的库下来以后解压缩，得到一些js文件，具体我就不说了。
建立一个html文件：
&#60;html&#62;&#60;head&#62;&#60;title&#62;XML-RPC&#60;/title&#62;&#60;script&#160;type=&#8221;text/javascript&#8221;&#160;src=&#8221;./js/init.js&#8221;&#62;&#60;/script&#62;&#60;script&#160;type=&#8221;text/javascript&#8221;&#160;src=&#8221;./js/lib/urllib.js&#8221;&#62;&#60;/script&#62;&#60;script&#160;type=&#8221;text/javascript&#8221;&#160;src=&#8221;./js/lib/xml.js&#8221;&#62;&#60;/script&#62;&#60;script&#160;type=&#8221;text/javascript&#8221;&#160;src=&#8221;./js/lib/xmlrpc.js&#8221;&#62;&#60;/script&#62;&#60;script&#160;type=&#8221;text/javascript&#8221;&#160;src=&#8221;./js/hello.js&#8221;&#62;&#60;/script&#62;&#60;/head&#62;a:&#60;input&#160;type=&#8221;text&#8221;&#160;id=&#8221;a&#8221; /&#62;&#60;br&#62;b:&#60;input&#160;type=&#8221;text&#8221;&#160;id=&#8221;b&#8221; /&#62;&#60;br&#62;&#60;input&#160;type=&#8221;button&#8221;&#160;id=&#8221;do1&#8243;&#160;value=&#8221;a+b&#8221;&#160;onclick=&#8221;add()&#8221;/&#62;&#60;input&#160;type=&#8221;button&#8221;&#160;id=&#8221;do2&#8243;&#160;value=&#8221;say&#8221;&#160;onclick=&#8221;hello()&#8221;/&#62;&#60;input&#160;type=&#8221;text&#8221;&#160;id=&#8221;result&#8221; /&#62;&#60;/html&#62;
注意到前面那一堆javascript的引用吗？就这么写吧。可别把hello.js当成solait的东西啦（看名字也知道啦），你是找不到的。这是我们自己写的：hello.js
hello&#160;= function(){ var&#160;xmlrpc=null; try{ var&#160;xmlrpc&#160;=&#160;importModule(&#8221;xmlrpc&#8221;);&#160;}catch(e){&#160;&#160;&#160;&#160;&#160;reportException(e); throw &#8220;importing&#160;of&#160;xmlrpc&#160;module&#160;failed.&#8221;;&#160;} var&#160;addr&#160;= [...]]]></description>
			<content:encoded><![CDATA[<h4>From <a href="http://www.blogjava.net/mstar/">http://www.blogjava.net/mstar/</a></h4>
<p>&nbsp;&nbsp; 前些天无意中发现了XML-RPC（不过笑我才发现啊<img height="20" src="http://www.cnblogs.com/Emoticons/hitwall.gif" width="25" border="0">），总想找个机会摆弄摆弄。毕业论文基本上弄完了，所以决定今天把它弄明白。<br />XML-RPC的最大用处，我首先想到的是浏览器在不刷新页面的情况下与服务器通信，请求数据。下面我就说一下我用XML-RPC是怎么实现的。
<p><strong>第一步：选择XML-RPC实现。<br /></strong>XML-RPC的一个很大优势就是 它是一个标准，并且各种开发环境下都有实现（酷），这是它能够轻松跨平台的原因。<br />javascript有3个实现。我看了一下最好的应该是jsolait（JavaScript o Lait）的实现了。因为他不仅仅是一个xml-rpc的实现，除此之外还有很多javascript库,详细内容请看这里（<a href="http://jsolait.net/">http://jsolait.net/</a>）。<br />java的实现就更多了，我当然毫不犹豫地选择apache的。详细内容看这里（<a href="http://ws.apache.org/xmlrpc/">http://ws.apache.org/xmlrpc/</a>）
<p>第二步：建立服务。<br />用java建立xml-rpc有两种方式，一种是单独开个端口，一种是用servlet。我们客户端是用javascript，那么服务端用servlet是再好不过的了。<br />如何使用apache的xml-rpc，请详细看apache的资料。（大哥你不会连servlet也不会建吧，那你还是不要往下看了）。<br />代码如下：<br />这是一个sayHello的服务类：
<p><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top">public class&nbsp;HelloService&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"> public&nbsp;String&nbsp;sayHello(String&nbsp;name)<img src="http://www.cnblogs.com/Images/dot.gif">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> return &#8220;Hello:&nbsp;&#8221;+name+&#8221;&nbsp;!&#8221;;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">
<p>下面是一个Math服务类：
<p><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top">public class&nbsp;MathService&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"> public double&nbsp;add(Vector&nbsp;v)<img src="http://www.cnblogs.com/Images/dot.gif">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> double&nbsp;a&nbsp;=&nbsp;Double.parseDouble((String)v.get(0));<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> double&nbsp;b&nbsp;=&nbsp;Double.parseDouble((String)v.get(1));<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> return&nbsp;a+b;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top"> public double&nbsp;mult(Vector&nbsp;v)<img src="http://www.cnblogs.com/Images/dot.gif">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> double&nbsp;a&nbsp;=&nbsp;Double.parseDouble((String)v.get(0));<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> double&nbsp;b&nbsp;=&nbsp;Double.parseDouble((String)v.get(1));<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> return&nbsp;a*b;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}
<p>接着是Servlet啦，作为RPC Server用的，这段代码比较经典，很多资料上都有。
<p><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif" align="top">public class&nbsp;RpcServer&nbsp;extends&nbsp;HttpServlet&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> protected void&nbsp;doPost(HttpServletRequest&nbsp;request,<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img src="http://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;HttpServletResponse&nbsp;response)&nbsp;throws&nbsp;ServletException,&nbsp;IOException&nbsp;<img src="http://www.cnblogs.com/Images/dot.gif">{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;XmlRpcServer&nbsp;xmlrpc&nbsp;= new&nbsp;XmlRpcServer();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;xmlrpc.addHandler(&#8221;HelloService&#8221;,&nbsp;new&nbsp;HelloService());<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;xmlrpc.addHandler(&#8221;MathService&#8221;,new&nbsp;MathService());<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> byte[]&nbsp;result&nbsp;=&nbsp;xmlrpc.execute(request.getInputStream());<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;response.setContentType(&#8221;text/xml&#8221;);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;response.setContentLength(result.length);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;OutputStream&nbsp;out =&nbsp;response.getOutputStream();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> out.write(result);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif" align="top"> out.flush();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}
<p>主要是这三句：<br />XmlRpcServer xmlrpc = new XmlRpcServer();<br />xmlrpc.addHandler(&#8221;HelloService&#8221;, new HelloService());<br />xmlrpc.addHandler(&#8221;MathService&#8221;,new MathService());<br />一定要记牢Handler的名字，就是第一个参数，因为客户端就靠他来表示要调用的方法呢。
<p>行了现在可以在web.xml中写入配置了：
<p><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> &lt;servlet&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> &lt;servlet-name&gt;RpcServer&lt;/servlet-name&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> &lt;servlet-class&gt;org.mstar.rpc.RpcServer&lt;/servlet-class&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> &lt;/servlet&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> &lt;servlet-mapping&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> &lt;servlet-name&gt;RpcServer&lt;/servlet-name&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> &lt;url-pattern&gt;/RpcServer&lt;/url-pattern&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> &lt;/servlet-mapping&gt;
<p>至此，服务端的工作已经完成，启动应用服务器就行了。
<p>下面是javacript的实现，这也是难点（其实不难理解，只是没有中文材料）。<br />把jsolait的库下来以后解压缩，得到一些js文件，具体我就不说了。
<p>建立一个html文件：
<p><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;html&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;head&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;title&gt;XML-RPC&lt;/title&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;script&nbsp;type=&#8221;text/javascript&#8221;&nbsp;src=&#8221;./js/init.js&#8221;&gt;&lt;/script&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;script&nbsp;type=&#8221;text/javascript&#8221;&nbsp;src=&#8221;./js/lib/urllib.js&#8221;&gt;&lt;/script&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;script&nbsp;type=&#8221;text/javascript&#8221;&nbsp;src=&#8221;./js/lib/xml.js&#8221;&gt;&lt;/script&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;script&nbsp;type=&#8221;text/javascript&#8221;&nbsp;src=&#8221;./js/lib/xmlrpc.js&#8221;&gt;&lt;/script&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;script&nbsp;type=&#8221;text/javascript&#8221;&nbsp;src=&#8221;./js/hello.js&#8221;&gt;&lt;/script&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;/head&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">a:&lt;input&nbsp;type=&#8221;text&#8221;&nbsp;id=&#8221;a&#8221; /&gt;&lt;br&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">b:&lt;input&nbsp;type=&#8221;text&#8221;&nbsp;id=&#8221;b&#8221; /&gt;&lt;br&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;input&nbsp;type=&#8221;button&#8221;&nbsp;id=&#8221;do1&#8243;&nbsp;value=&#8221;a+b&#8221;&nbsp;onclick=&#8221;add()&#8221;/&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;input&nbsp;type=&#8221;button&#8221;&nbsp;id=&#8221;do2&#8243;&nbsp;value=&#8221;say&#8221;&nbsp;onclick=&#8221;hello()&#8221;/&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;input&nbsp;type=&#8221;text&#8221;&nbsp;id=&#8221;result&#8221; /&gt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&lt;/html&gt;
<p>注意到前面那一堆javascript的引用吗？就这么写吧。可别把hello.js当成solait的东西啦（看名字也知道啦），你是找不到的。这是我们自己写的：<br />hello.js
<p><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">hello&nbsp;= function(){<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;xmlrpc=null;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> try{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;xmlrpc&nbsp;=&nbsp;importModule(&#8221;xmlrpc&#8221;);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;}catch(e){<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reportException(e);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> throw &#8220;importing&nbsp;of&nbsp;xmlrpc&nbsp;module&nbsp;failed.&#8221;;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;addr&nbsp;= &#8220;http://localhost:8080/Rpc/RpcServer&#8221;;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;methods&nbsp;=&nbsp;[&#8221;HelloService.sayHello&#8221;];<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;rslt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> try{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;service&nbsp;= new&nbsp;xmlrpc.ServiceProxy(addr,&nbsp;methods);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rslt&nbsp;=&nbsp;service.HelloService.sayHello(&#8221;MTY&#8221;);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;}catch(e){<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;em;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> if(e.toTraceString){<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;em&nbsp;=&nbsp;e.toTraceString();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;em&nbsp;=&nbsp;e.message;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rslt&nbsp;= &#8220;Error&nbsp;trace:&nbsp;\n\n&#8221; +&nbsp;em;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;document.getElementById(&#8221;result&#8221;).value=rslt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">add&nbsp;= function(){<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;xmlrpc=null;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;a&nbsp;=&nbsp;document.getElementById(&#8221;a&#8221;).value;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;b&nbsp;=&nbsp;document.getElementById(&#8221;b&#8221;).value;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;params&nbsp;= new&nbsp;Array();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;params[0]&nbsp;=&nbsp;a;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;params[1]&nbsp;=&nbsp;b;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> try{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;xmlrpc&nbsp;=&nbsp;importModule(&#8221;xmlrpc&#8221;);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;}catch(e){<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reportException(e);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> throw &#8220;importing&nbsp;of&nbsp;xmlrpc&nbsp;module&nbsp;failed.&#8221;;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;addr&nbsp;= &#8220;http://localhost:8080/Rpc/RpcServer&#8221;;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;methods&nbsp;=&nbsp;[&#8221;HelloService.sayHello&#8221;,&#8221;MathService.add&#8221;];<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;rslt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> try{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;service&nbsp;= new&nbsp;xmlrpc.ServiceProxy(addr,&nbsp;methods);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rslt&nbsp;=&nbsp;service.MathService.add(params);<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;}catch(e){<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> var&nbsp;em;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"> if(e.toTraceString){<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;em&nbsp;=&nbsp;e.toTraceString();<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}else{<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;em&nbsp;=&nbsp;e.message;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rslt&nbsp;= &#8220;Error&nbsp;trace:&nbsp;\n\n&#8221; +&nbsp;em;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">&nbsp;document.getElementById(&#8221;result&#8221;).value=rslt;<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">}<br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top"><br /><img src="http://www.cnblogs.com/Images/OutliningIndicators/None.gif" align="top">
<p>这个js文件中有两个函数，一个负责从sayhello，一个负责加法运算。<br />这里需要一些解释的地方：<br />1、<br />&nbsp;var xmlrpc=null;<br />&nbsp;try{<br />&nbsp;&nbsp;&nbsp; &nbsp;var xmlrpc = importModule(&#8221;xmlrpc&#8221;);<br />&nbsp;}catch(e){<br />&nbsp;&nbsp;&nbsp; &nbsp;reportException(e);<br />&nbsp;&nbsp;&nbsp; &nbsp;throw &#8220;importing of xmlrpc module failed.&#8221;;<br />&nbsp;}<br />这里是把xmlrpc模块引进来,你也就这么写吧，我也不知道为什么。<br />2、<br />&nbsp;var addr = &#8220;<a href="http://localhost:8080/Rpc/RpcServer">http://localhost:8080/Rpc/RpcServer</a>&#8220;;<br />&nbsp;var methods = [&#8221;HelloService.sayHello&#8221;];<br />定义服务地址和要用的方法名。规则大概你也能看懂：Handler名.方法名。这里的Handler名就是你在xmlrpcServer中注册名，就是我上面让你记住的那个。方法名就是那个类自己的方法名。注意，methods是一个数组，所以可以写多个方法，如第二个例子。var methods = [&#8221;HelloService.sayHello&#8221;,&#8221;MathService.add&#8221;];<br />3、<br />&nbsp;&nbsp;&nbsp; try{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var service = new xmlrpc.ServiceProxy(addr, methods);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rslt = service.HelloService.sayHello(&#8221;MTY&#8221;);<br />&nbsp;&nbsp;&nbsp; }catch(e){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var em;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(e.toTraceString){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; em = e.toTraceString();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }else{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; em = e.message;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rslt = &#8220;Error trace: \n\n&#8221; + em;<br />&nbsp;&nbsp;&nbsp; }<br />通过new xmlrpc.ServiceProxy(addr, methods);得到服务代理。<br />然后调用服务的方法就行了，方法就是代理.Handler名.方法名（参数）。好像参数只能有一个，在第二个例子中我开始有两个参数a,b会发生错误。怎么办？没办法，在javascript用Array传参数，在java用Vector接参数（为什么用Vector，因为xml-rpc规范中的 Array，apache使用Vector实现的，为什么javascript不用Vector，因为js没有Vector，且js的的Array是可变长的）。当然这就需要很多java端类型转换工作，js是弱类型的就不用转换了。</p>
No Tags]]></content:encoded>
			<wfw:commentRss>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/%e5%b0%8f%e8%af%95xml-rpc%ef%bc%88%e6%b5%8f%e8%a7%88%e5%99%a8javascript%e4%b8%8e%e6%9c%8d%e5%8a%a1%e5%99%a8java%e9%80%9a%e4%bf%a1%ef%bc%89%e8%bd%ac/feed</wfw:commentRss>
		</item>
		<item>
		<title>Apache xml-rpc (转)</title>
		<link>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/apache-xml-rpc-%e8%bd%ac</link>
		<comments>http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/apache-xml-rpc-%e8%bd%ac#comments</comments>
		<pubDate>Wed, 01 Aug 2007 11:12:44 +0000</pubDate>
		<dc:creator>micas</dc:creator>
		
	<dc:subject>SEO</dc:subject>
		<guid isPermaLink="false">http://blog.enabling-tech.com/enabling-tech/%e6%90%9c%e7%b4%a2%e6%8a%80%e6%9c%af/apache-xml-rpc-%e8%bd%ac</guid>
		<description><![CDATA[&#160;
由于最近做的一个项目需要，使用了apache xml-rpc，顺便整理一下使用的方法。
&#160;&#160;&#160; xml-rpc是一套允许运行在不同操作系统、不同环境的程序实现基于internet过程调用的规范和一系列的实现。这种远程过程调用使用http作为传输协议，xml作为传送信息的编码格式。xml-rpc的定义尽可能的保持了简单，但同时能