﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-SIMONE-随笔分类-JAVA</title><link>http://www.blogjava.net/wangxinsh55/category/9223.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 24 Oct 2016 16:49:20 GMT</lastBuildDate><pubDate>Mon, 24 Oct 2016 16:49:20 GMT</pubDate><ttl>60</ttl><item><title>java keytool证书工具使用小结</title><link>http://www.blogjava.net/wangxinsh55/archive/2016/10/20/431905.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Thu, 20 Oct 2016 03:20:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/10/20/431905.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/431905.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/10/20/431905.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/431905.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/431905.html</trackback:ping><description><![CDATA[<br /><div>http://www.micmiu.com/lang/java/keytool-start-guide/</div><br /><div><h2>java keytool证书工具使用小结</h2></div><br /><div><p>Keytool 是一个Java数据证书的管理工具  ,Keytool将密钥（key）和证书（certificates）存在一个称为keystore的文件中在keystore里，包含两种数据:密钥实体（Key  entity）-密钥（secret key）或者是私钥和配对公钥（采用非对称加密）可信任的证书实体（trusted certificate  entries）-只包含公钥.<br /> <span style="color: #0000ff;">JDK中keytool常用参数说明（<span style="color: #ff0000;">不同版本有差异，详细可参见【附录】中的官方文档链接</span>）:</span></p> <ul><li>-genkey 在用户主目录中创建一个默认文件&#8221;.keystore&#8221;,还会产生一个mykey的别名，mykey中包含用户的公钥、私钥和证书(在没有指定生成位置的情况下,keystore会存在用户系统默认目录)</li><li>-alias 产生别名 每个keystore都关联这一个独一无二的alias，这个alias通常不区分大小写</li><li>-keystore 指定密钥库的名称(产生的各类信息将不在.keystore文件中)</li><li>-keyalg 指定密钥的算法 (如 RSA DSA，默认值为：DSA)</li><li>-validity 指定创建的证书有效期多少天(默认 90)</li><li>-keysize 指定密钥长度 （默认 1024）</li><li>-storepass 指定密钥库的密码(获取keystore信息所需的密码)</li><li>-keypass 指定别名条目的密码(私钥的密码)</li><li>-dname 指定证书发行者信息 其中： &#8220;CN=名字与姓氏,OU=组织单位名称,O=组织名称,L=城市或区域名 称,ST=州或省份名称,C=单位的两字母国家代码&#8221;</li><li>-list 显示密钥库中的证书信息 keytool -list -v -keystore 指定keystore -storepass 密码</li><li>-v 显示密钥库中的证书详细信息</li><li>-export 将别名指定的证书导出到文件 keytool -export -alias 需要导出的别名 -keystore 指定keystore -file 指定导出的证书位置及证书名称 -storepass 密码</li><li>-file 参数指定导出到文件的文件名</li><li>-delete 删除密钥库中某条目 keytool -delete -alias 指定需删除的别 -keystore 指定keystore &#8211; storepass 密码</li><li>-printcert 查看导出的证书信息 keytool -printcert -file g:\sso\michael.crt</li><li>-keypasswd 修改密钥库中指定条目口令 keytool -keypasswd -alias 需修改的别名 -keypass 旧密码 -new 新密码 -storepass keystore密码 -keystore sage</li><li>-storepasswd 修改keystore口令 keytool -storepasswd -keystore  g:\sso\michael.keystore(需修改口令的keystore) -storepass pwdold(原始密码) -new  pwdnew(新密码)</li><li>-import 将已签名数字证书导入密钥库 keytool -import -alias 指定导入条目的别名 -keystore 指定keystore -file 需导入的证书</li></ul> <div><strong><span style="line-height: 18px;">目录说明：</span></strong></div> <div> <ol><li><span style="line-height: 19px;">生成证书</span></li><li><span style="line-height: 19px;">查看证书</span></li><li><span style="line-height: 19px;">证书导出</span></li><li><span style="line-height: 19px;">附录资料</span></li></ol> </div> <div><span style="color: #0000ff;">一、生成证书</span></div> <div>&nbsp;按win键+R，弹出运行窗口，输入 cmd 回车，打开命令行窗户，输入如下命令：</div> <div>   		<div id="crayon-5806e9cc4d76c170187796" crayon-theme-solarized-dark="" crayon-font-monaco="" crayon-os-pc="" print-yes=""  notranslate"="" data-settings=" minimize scroll-mouseover" style="margin-top: 12px; margin-bottom: 12px; font-size: 12px ! important; line-height: 15px ! important; height: auto;"> 		 			<div data-settings=" show" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"> 			</div> 			 			<div><textarea print-no"="" data-settings="dblclick" readonly="readonly" style="-moz-tab-size: 4; font-size: 12px ! important; line-height: 15px ! important; z-index: 0; opacity: 0; overflow: hidden;" wrap="soft">keytool -genkey -alias michaelkey -keyalg RSA -keysize 1024 -keypass michaelpwd -validity 365 -keystore g:\sso\michael.keystore -storepass michaelpwd2</textarea></div> 			<div style="position: relative; z-index: 1; overflow: hidden;"> 				<table> 					<tbody><tr> 				<td "="" data-settings="show"> 					<div style="font-size: 12px !important; line-height: 15px !important;"><div data-line="crayon-5806e9cc4d76c170187796-1">1</div></div> 				</td> 						<td><div style="font-size: 12px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><div id="crayon-5806e9cc4d76c170187796-1">keytool -genkey -alias michaelkey -keyalg RSA -keysize 1024 -keypass michaelpwd -validity 365 -keystore g:\sso\michael.keystore -storepass michaelpwd2</div></div></td> 					</tr> 				</tbody></table> 			</div> 		</div>   </div> <div>截图如下：</div> <div><a href="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-01.jpg"><img size-full=""  wp-image-600"="" title="keytool-01" src="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-01.jpg" alt="" height="286" width="647" /></a></div> <div><span style="color: #0000ff;">二、查看证书</span></div> <div> <p>缺省情况下，-list&nbsp;命令打印证书的&nbsp;MD5&nbsp;指纹。而如果指定了&nbsp;-v&nbsp;选项，将以可读格式打印证书，如果指定了&nbsp;-rfc&nbsp;选项，将以可打印的编码格式输出证书。</p> </div> <div><span style="color: #0000ff;">-v 命令如下：</span></div> <div>   		<div id="crayon-5806e9cc4d78c797748914" crayon-theme-solarized-dark="" crayon-font-monaco="" crayon-os-pc="" print-yes=""  notranslate"="" data-settings=" minimize scroll-mouseover" style="margin-top: 12px; margin-bottom: 12px; font-size: 12px ! important; line-height: 15px ! important; height: auto;"> 		 			<div data-settings=" show" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"> 			</div> 			 			<div><textarea print-no"="" data-settings="dblclick" readonly="readonly" style="-moz-tab-size: 4; font-size: 12px ! important; line-height: 15px ! important; z-index: 0; opacity: 0; overflow: hidden;" wrap="soft">keytool -list  -v -keystore g:\sso\michael.keystore -storepass michaelpwd2</textarea></div> 			<div style="position: relative; z-index: 1; overflow: hidden;"> 				<table> 					<tbody><tr> 				<td "="" data-settings="show"> 					<div style="font-size: 12px !important; line-height: 15px !important;"><div data-line="crayon-5806e9cc4d78c797748914-1">1</div></div> 				</td> 						<td><div style="font-size: 12px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><div id="crayon-5806e9cc4d78c797748914-1">keytool -list&nbsp;&nbsp;-v -keystore g:\sso\michael.keystore -storepass michaelpwd2</div></div></td> 					</tr> 				</tbody></table> 			</div> 		</div>   </div> <div>回车看到的信息如下：</div> <div><a href="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-02.jpg"><img size-full=""  wp-image-601"="" title="keytool-02" src="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-02.jpg" alt="" height="429" width="647" /></a></div> <div><span style="color: #0000ff;">-rfc 命令如下：</span></div> <div>   		<div id="crayon-5806e9cc4d79f689847244" crayon-theme-solarized-dark="" crayon-font-monaco="" crayon-os-pc="" print-yes=""  notranslate"="" data-settings=" minimize scroll-mouseover" style="margin-top: 12px; margin-bottom: 12px; font-size: 12px ! important; line-height: 15px ! important; height: auto;"> 		 			<div data-settings=" show" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"> 			</div> 			 			<div><textarea print-no"="" data-settings="dblclick" readonly="readonly" style="-moz-tab-size: 4; font-size: 12px ! important; line-height: 15px ! important; z-index: 0; opacity: 0; overflow: hidden;" wrap="soft">keytool -list -rfc -keystore g:\sso\michael.keystore -storepass michaelpwd2</textarea></div> 			<div style="position: relative; z-index: 1; overflow: hidden;"> 				<table> 					<tbody><tr> 				<td "="" data-settings="show"> 					<div style="font-size: 12px !important; line-height: 15px !important;"><div data-line="crayon-5806e9cc4d79f689847244-1">1</div></div> 				</td> 						<td><div style="font-size: 12px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><div id="crayon-5806e9cc4d79f689847244-1">keytool -list -rfc -keystore g:\sso\michael.keystore -storepass michaelpwd2</div></div></td> 					</tr> 				</tbody></table> 			</div> 		</div>   </div> <div>回车看到的信息如下：</div> <div><a href="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-03.jpg"><img size-full=""  wp-image-602"="" title="keytool-03" src="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-03.jpg" alt="" height="491" width="649" /></a></div> <div><span style="color: #0000ff;">三、证书的导出和查看：</span></div> <div><span style="color: #ff0000;">导出证书命令</span>：</div> <div>   		<div id="crayon-5806e9cc4d7b3204187001" crayon-theme-solarized-dark="" crayon-font-monaco="" crayon-os-pc="" print-yes=""  notranslate"="" data-settings=" minimize scroll-mouseover" style="margin-top: 12px; margin-bottom: 12px; font-size: 12px ! important; line-height: 15px ! important; height: auto;"> 		 			<div data-settings=" show" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"> 			</div> 			 			<div><textarea print-no"="" data-settings="dblclick" readonly="readonly" style="-moz-tab-size: 4; font-size: 12px ! important; line-height: 15px ! important; z-index: 0; opacity: 0; overflow: hidden;" wrap="soft">keytool -export -alias michaelkey -keystore g:\sso\michael.keystore -file g:\sso\michael.crt -storepass michaelpwd2</textarea></div> 			<div style="position: relative; z-index: 1; overflow: hidden;"> 				<table> 					<tbody><tr> 				<td "="" data-settings="show"> 					<div style="font-size: 12px !important; line-height: 15px !important;"><div data-line="crayon-5806e9cc4d7b3204187001-1">1</div></div> 				</td> 						<td><div style="font-size: 12px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><div id="crayon-5806e9cc4d7b3204187001-1">keytool -export -alias michaelkey -keystore g:\sso\michael.keystore -file g:\sso\michael.crt -storepass michaelpwd2</div></div></td> 					</tr> 				</tbody></table> 			</div> 		</div>   </div> <div>回车如下：</div> <div><a href="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-04.jpg"><img size-full=""  wp-image-604"="" title="keytool-04" src="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-04.jpg" alt="" height="80" width="645" /></a></div> <div><span style="color: #ff0000;">查看导出的证书信息</span>：</div> <div>   		<div id="crayon-5806e9cc4d7c5981815595" crayon-theme-solarized-dark="" crayon-font-monaco="" crayon-os-pc="" print-yes=""  notranslate"="" data-settings=" minimize scroll-mouseover" style="margin-top: 12px; margin-bottom: 12px; font-size: 12px ! important; line-height: 15px ! important; height: auto;"> 		 			<div data-settings=" show" style="font-size: 12px !important;height: 18px !important; line-height: 18px !important;"> 			</div> 			 			<div><textarea print-no"="" data-settings="dblclick" readonly="readonly" style="-moz-tab-size: 4; font-size: 12px ! important; line-height: 15px ! important; z-index: 0; opacity: 0; overflow: hidden;" wrap="soft">keytool -printcert -file g:\sso\michael.crt</textarea></div> 			<div style="position: relative; z-index: 1; overflow: hidden;"> 				<table> 					<tbody><tr> 				<td "="" data-settings="show"> 					<div style="font-size: 12px !important; line-height: 15px !important;"><div data-line="crayon-5806e9cc4d7c5981815595-1">1</div></div> 				</td> 						<td><div style="font-size: 12px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><div id="crayon-5806e9cc4d7c5981815595-1">keytool -printcert -file g:\sso\michael.crt</div></div></td> 					</tr> 				</tbody></table> 			</div> 		</div>   </div> <div>回车看到信息如下：</div> <div><a href="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-05.jpg"><img size-full=""  wp-image-603"="" title="keytool-05" src="http://www.micmiu.com/wp-content/uploads/2012/05/keytool-05.jpg" alt="" height="181" width="642" /></a></div> <div><span style="color: #0000ff;">四：附录</span></div> <div>官方有关keytool命令的介绍文档：</div> <div> <ul><li><span style="line-height: 19px;">jdk1.4.2 ：http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/keytool.html</span></li><li><span style="line-height: 19px;">jdk1.6 &nbsp; &nbsp;：http://docs.oracle.com/javase/6/docs/technotes/tools/windows/keytool.html</span></li><li><span style="line-height: 19px;">jdk1.7 &nbsp; &nbsp;：http://docs.oracle.com/javase/7/docs/technotes/tools/windows/keytool.html</span></li></ul> </div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/431905.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-10-20 11:20 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/10/20/431905.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java 和 HTTP 的那些事（二） 使用代理</title><link>http://www.blogjava.net/wangxinsh55/archive/2016/08/02/431421.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 02 Aug 2016 06:11:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/08/02/431421.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/431421.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/08/02/431421.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/431421.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/431421.html</trackback:ping><description><![CDATA[<div>http://www.aneasystone.com/archives/2015/12/java-and-http-using-proxy.html</div><br /><div><p>在上一篇博客<a href="http://www.aneasystone.com/archives/2015/12/java-and-http-one.html">《模拟 HTTP 请求》</a>中，我们分别介绍了两种方法来进行 HTTP 的模拟请求：<code>HttpURLConnection</code> 和 <code>HttpClient</code>  ，到目前为止这两种方法都工作的很好，基本上可以实现我们需要的 GET/POST 方法的模拟。对于一个爬虫来说，能发送 HTTP  请求，能获取页面数据，能解析网页内容，这相当于已经完成 80% 的工作了。只不过对于剩下的这 20% 的工作，还得花费我们另外 80% 的时间  :-)</p> <p>在这篇博客里，我们将介绍剩下 20% 的工作中最为重要的一项：如何在 Java 中使用 HTTP  代理，代理也是爬虫技术中的重要一项。你如果要大规模的爬别人网页上的内容，必然会对人家的网站造成影响，如果你太拼了，就会遭人查封。要防止别人查封我 们，我们要么将自己的程序分布到大量机器上去，但是对于资金和资源有限的我们来说这是很奢侈的；要么就使用代理技术，从网上捞一批代理，免费的也好收费的 也好，或者购买一批廉价的 VPS  来搭建自己的代理服务器。关于如何搭建自己的代理服务器，后面有时间的话我再写一篇关于这个话题的博客。现在有了一大批代理服务器之后，就可以使用我们这 篇博客所介绍的技术了。</p> <h2>一、简单的 HTTP 代理</h2> <p>我们先从最简单的开始，网上有很多免费代理，直接上百度搜索 &#8220;免费代理&#8221; 或者 &#8220;HTTP 代理&#8221; 就能找到很多（虽然网上能找到大量的免费代理，但它们的安全性已经有很多文章讨论过了，也有专门的文章对此进行调研的，譬如<a href="http://www.freebuf.com/news/70733.html">这篇文章</a>，我在这里就不多作说明，如果你的爬虫爬取的信息并没有什么特别的隐私问题，可以忽略之，如果你的爬虫涉及一些例如模拟登录之类的功能，考虑到安全性，我建议你还是不要使用网上公开的免费代理，而是搭建自己的代理服务器比较靠谱）。</p> <h4>1.1 HttpURLConnection 使用代理</h4> <p>HttpURLConnection 的 <code>openConnection()</code> 方法可以传入一个 Proxy 参数，如下：</p> <div><div id="highlighter_961651"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">Proxy proxy = </code><code keyword"="">new</code> <code plain"="">Proxy(Proxy.Type.HTTP, </code><code keyword"="">new</code> <code plain"="">InetSocketAddress(</code><code string"="">"127.0.0.1"</code><code plain"="">, </code><code value"="">9876</code><code plain"="">));</code></div><div number2="" index1=""  alt1"=""><code plain"="">URL obj = </code><code keyword"="">new</code> <code plain"="">URL(url);</code></div><div number3="" index2=""  alt2"=""><code plain"="">HttpURLConnection con = (HttpURLConnection) obj.openConnection(proxy);</code></div></div></td></tr></tbody></table></div></div> <p>OK 了，就这么简单！</p> <p>不仅如此，我们注意到 Proxy 构造函数的第一个参数为枚举类型 <code>Proxy.Type.HTTP</code> ，那么很显然，如果将其修改为 <code>Proxy.Type.SOCKS</code> 即可以使用 SOCKS 代理。</p> <h4>1.2 HttpClient 使用代理</h4> <p>由于 <code>HttpClient</code> 非常灵活，使用 HttpClient 来连接代理有很多不同的方法。最简单的方法莫过于下面这样：</p> <div><div id="highlighter_384787"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">HttpHost proxy = </code><code keyword"="">new</code> <code plain"="">HttpHost(</code><code string"="">"127.0.0.1"</code><code plain"="">, </code><code value"="">9876</code><code plain"="">, </code><code string"="">"HTTP"</code><code plain"="">);</code></div><div number2="" index1=""  alt1"=""><code plain"="">CloseableHttpClient httpclient = HttpClients.createDefault();</code></div><div number3="" index2=""  alt2"=""><code plain"="">HttpGet request = </code><code keyword"="">new</code> <code plain"="">HttpGet(url);</code></div><div number4="" index3=""  alt1"=""><code plain"="">CloseableHttpResponse response = httpclient.execute(proxy, request);</code></div></div></td></tr></tbody></table></div></div> <p>和上一篇中使用 HttpClient 发送请求的代码几乎一样，只是 <code>httpclient.execute()</code> 方法多加了一个参数，第一参数为 <code>HttpHost</code> 类型，我们这里设置成我们的代理即可。</p> <p>这里要注意一点的是，虽然这里的 <code>new HttpHost()</code> 和上面的 <code>new Proxy()</code> 一样，也是可以指定协议类型的，但是遗憾的是 HttpClient 默认是不支持 SOCKS 协议的，如果我们使用下面的代码：</p> <div><div id="highlighter_676139"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">HttpHost proxy = </code><code keyword"="">new</code> <code plain"="">HttpHost(</code><code string"="">"127.0.0.1"</code><code plain"="">, </code><code value"="">1080</code><code plain"="">, </code><code string"="">"SOCKS"</code><code plain"="">);</code></div></div></td></tr></tbody></table></div></div> <p>将会直接报协议不支持异常：</p> <blockquote> <p>org.apache.http.conn.UnsupportedSchemeException: socks protocol is not supported</p> </blockquote> <p>如果希望 HttpClient 支持 SOCKS 代理，可以参看这里：<a href="http://stackoverflow.com/questions/22937983/how-to-use-socks-5-proxy-with-apache-http-client-4">How to use Socks 5 proxy with Apache HTTP Client 4?</a> 通过 HttpClient 提供的 ConnectionSocketFactory 类来实现。</p> <p>虽然使用这种方式很简单，只需要加个参数就可以了，但是其实看 HttpClient 的代码注释，如下：</p> <div><div id="highlighter_710103"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div></td><td><div><div number1="" index0=""  alt2"=""><code comments"="">/*</code></div><div number2="" index1=""  alt1"=""><code comments"="">* @param target&nbsp;&nbsp;&nbsp; the target host for the request.</code></div><div number3="" index2=""  alt2"=""><code comments"="">*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Implementations may accept &lt;code&gt;null&lt;/code&gt;</code></div><div number4="" index3=""  alt1"=""><code comments"="">*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if they can still determine a route, for example</code></div><div number5="" index4=""  alt2"=""><code comments"="">*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to a default target or by inspecting the request.</code></div><div number6="" index5=""  alt1"=""><code comments"="">* @param request&nbsp;&nbsp; the request to execute</code></div><div number7="" index6=""  alt2"=""><code comments"="">*/</code></div></div></td></tr></tbody></table></div></div> <p>可以看到第一个参数 target 并不是代理，它的真实作用是 <strong>执行请求的目标主机</strong>，这个解释有点模糊，什么叫做 <strong>执行请求的目标主机</strong>？代理算不算<strong>执行请求的目标主机</strong>呢？因为按常理来讲，<strong>执行请求的目标主机</strong> 应该是要请求 URL 对应的站点才对。如果不算的话，为什么这里将 target 设置成代理也能正常工作？这个我也不清楚，还需要进一步研究下 HttpClient 的源码来深入了解下。</p> <p>除了上面介绍的这种方式（自己写的，不推荐使用）来使用代理之外，HttpClient 官网还提供了几个示例，我将其作为推荐写法记录在此。</p> <p>第一种写法是使用 <a href="http://hc.apache.org/httpcomponents-client-ga/httpclient/examples/org/apache/http/examples/client/ClientExecuteProxy.java">RequestConfig 类</a>，如下：</p> <div><div id="highlighter_305592"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div><div number8="" index7=""  alt1"="">8</div><div number9="" index8=""  alt2"="">9</div><div number10="" index9=""  alt1"="">10</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">CloseableHttpClient httpclient = HttpClients.createDefault();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code></div><div number2="" index1=""  alt1"=""><code plain"="">HttpGet request = </code><code keyword"="">new</code> <code plain"="">HttpGet(url);</code></div><div number3="" index2=""  alt2"="">&nbsp;</div><div number4="" index3=""  alt1"=""><code plain"="">request.setConfig(</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">RequestConfig.custom()</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">.setProxy(</code><code keyword"="">new</code> <code plain"="">HttpHost(</code><code string"="">"45.32.21.237"</code><code plain"="">, </code><code value"="">8888</code><code plain"="">, </code><code string"="">"HTTP"</code><code plain"="">))</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">.build()</code></div><div number8="" index7=""  alt1"=""><code plain"="">);</code></div><div number9="" index8=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code>&nbsp;</div><div number10="" index9=""  alt1"=""><code plain"="">CloseableHttpResponse response = httpclient.execute(request);</code></div></div></td></tr></tbody></table></div></div> <p>第二种写法是使用 <a href="http://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/connmgmt.html#d5e485">RoutePlanner 类</a>，如下：</p> <div><div id="highlighter_875054"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">HttpHost proxy = </code><code keyword"="">new</code> <code plain"="">HttpHost(</code><code string"="">"127.0.0.1"</code><code plain"="">, </code><code value"="">9876</code><code plain"="">, </code><code string"="">"HTTP"</code><code plain"="">);</code></div><div number2="" index1=""  alt1"=""><code plain"="">DefaultProxyRoutePlanner routePlanner = </code><code keyword"="">new</code> <code plain"="">DefaultProxyRoutePlanner(proxy); </code></div><div number3="" index2=""  alt2"=""><code plain"="">CloseableHttpClient httpclient = HttpClients.custom()</code></div><div number4="" index3=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">.setRoutePlanner(routePlanner)</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">.build();</code></div><div number6="" index5=""  alt1"=""><code plain"="">HttpGet request = </code><code keyword"="">new</code> <code plain"="">HttpGet(url);</code></div><div number7="" index6=""  alt2"=""><code plain"="">CloseableHttpResponse response = httpclient.execute(request);</code></div></div></td></tr></tbody></table></div></div> <h2>二、使用系统代理配置</h2> <p>我们在调试 HTTP 爬虫程序时，常常需要切换代理来测试，有时候直接使用系统自带的代理配置将是一种简单的方法。以前在做 .Net  项目时，程序默认使用 Internet 网络设置中配的代理，遗憾的是，我这里说的系统代理配置指的 JVM  系统，而不是操作系统，我还没找到简单的方法来让 Java 程序直接使用 Windows 系统下的代理配置。</p> <p>尽管如此，系统代理使用起来还是很简单的。一般有下面两种方式可以设置 JVM 的代理配置：</p> <h4>2.1 System.setProperty</h4> <p>Java 中的 <code>System</code> 类不仅仅是用来给我们 <code>System.out.println()</code> 打印信息的，它其实还有很多静态方法和属性可以用。其中 <code>System.setProperty()</code> 就是比较常用的一个。</p> <p>可以通过下面的方式来分别设置 HTTP 代理，HTTPS 代理和 SOCKS 代理：</p> <div><div id="highlighter_319495"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div><div number8="" index7=""  alt1"="">8</div><div number9="" index8=""  alt2"="">9</div><div number10="" index9=""  alt1"="">10</div><div number11="" index10=""  alt2"="">11</div><div number12="" index11=""  alt1"="">12</div></td><td><div><div number1="" index0=""  alt2"=""><code comments"="">// HTTP 代理，只能代理 HTTP 请求</code></div><div number2="" index1=""  alt1"=""><code plain"="">System.setProperty(</code><code string"="">"http.proxyHost"</code><code plain"="">, </code><code string"="">"127.0.0.1"</code><code plain"="">);</code></div><div number3="" index2=""  alt2"=""><code plain"="">System.setProperty(</code><code string"="">"http.proxyPort"</code><code plain"="">, </code><code string"="">"9876"</code><code plain"="">);</code></div><div number4="" index3=""  alt1"="">&nbsp;</div><div number5="" index4=""  alt2"=""><code comments"="">// HTTPS 代理，只能代理 HTTPS 请求</code></div><div number6="" index5=""  alt1"=""><code plain"="">System.setProperty(</code><code string"="">"https.proxyHost"</code><code plain"="">, </code><code string"="">"127.0.0.1"</code><code plain"="">);</code></div><div number7="" index6=""  alt2"=""><code plain"="">System.setProperty(</code><code string"="">"https.proxyPort"</code><code plain"="">, </code><code string"="">"9876"</code><code plain"="">);</code></div><div number8="" index7=""  alt1"="">&nbsp;</div><div number9="" index8=""  alt2"=""><code comments"="">// SOCKS 代理，支持 HTTP 和 HTTPS 请求</code></div><div number10="" index9=""  alt1"=""><code comments"="">// 注意：如果设置了 SOCKS 代理就不要设 HTTP/HTTPS 代理</code></div><div number11="" index10=""  alt2"=""><code plain"="">System.setProperty(</code><code string"="">"socksProxyHost"</code><code plain"="">, </code><code string"="">"127.0.0.1"</code><code plain"="">);</code></div><div number12="" index11=""  alt1"=""><code plain"="">System.setProperty(</code><code string"="">"socksProxyPort"</code><code plain"="">, </code><code string"="">"1080"</code><code plain"="">);</code></div></div></td></tr></tbody></table></div></div> <p>这里有三点要说明：</p> <ol><li>系统默认先使用 HTTP/HTTPS 代理，如果既设置了 HTTP/HTTPS 代理，又设置了 SOCKS 代理，SOCKS 代理会起不到作用</li><li>由于历史原因，注意 <code>socksProxyHost</code> 和 <code>socksProxyPort</code> 中间没有小数点</li><li>HTTP 和 HTTPS 代理可以合起来缩写，如下：</li></ol> <div><div id="highlighter_705545"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div></td><td><div><div number1="" index0=""  alt2"=""><code comments"="">// 同时支持代理 HTTP/HTTPS 请求</code></div><div number2="" index1=""  alt1"=""><code plain"="">System.setProperty(</code><code string"="">"proxyHost"</code><code plain"="">, </code><code string"="">"127.0.0.1"</code><code plain"="">);</code></div><div number3="" index2=""  alt2"=""><code plain"="">System.setProperty(</code><code string"="">"proxyPort"</code><code plain"="">, </code><code string"="">"9876"</code><code plain"="">);</code></div></div></td></tr></tbody></table></div></div> <h4>2.2 JVM 命令行参数</h4> <p>可以使用 <code>System.setProperty()</code> 方法来设置系统代理，也可以直接将这些参数通过 JVM 的命令行参数来指定。如果你使用的是 Eclipse ，可以按下面的步骤来设置：</p> <ol><li>按顺序打开：Window -&gt; Preferences -&gt; Java -&gt; Installed JREs -&gt; Edit</li><li>在 Default VM arguments 中填写参数： <code>-DproxyHost=127.0.0.1 -DproxyPort=9876</code></li></ol> <p><img src="http://www.aneasystone.com/usr/uploads/2015/12/946315741.jpg" alt="jvm-arguments.jpg" /></p> <h4>2.3 使用系统代理</h4> <p>上面两种方法都可以设置系统，下面要怎么在程序中自动使用系统代理呢？</p> <p>对于 <code>HttpURLConnection</code> 类来说，程序不用做任何变动，它会默认使用系统代理。但是 <code>HttpClient</code> 默认是不使用系统代理的，如果想让它默认使用系统代理，可以通过 <code>SystemDefaultRoutePlanner</code> 和 <code>ProxySelector</code> 来设置。示例代码如下：</p> <div><div id="highlighter_319464"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">SystemDefaultRoutePlanner routePlanner = </code><code keyword"="">new</code> <code plain"="">SystemDefaultRoutePlanner(ProxySelector.getDefault());</code></div><div number2="" index1=""  alt1"=""><code plain"="">CloseableHttpClient httpclient = HttpClients.custom()</code></div><div number3="" index2=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">.setRoutePlanner(routePlanner)</code></div><div number4="" index3=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">.build();</code></div><div number5="" index4=""  alt2"=""><code plain"="">HttpGet request = </code><code keyword"="">new</code> <code plain"="">HttpGet(url);&nbsp;&nbsp;&nbsp;&nbsp; </code></div><div number6="" index5=""  alt1"=""><code plain"="">CloseableHttpResponse response = httpclient.execute(request);</code></div></div></td></tr></tbody></table></div></div> <h2>参考</h2> <ol><li><a href="http://hc.apache.org/httpcomponents-client-ga/tutorial/html/">HttpClient Tutorial</a></li><li><a href="http://www.freebuf.com/news/70733.html">评测告诉你：那些免费代理悄悄做的龌蹉事儿</a></li><li><a href="http://stackoverflow.com/questions/22937983/how-to-use-socks-5-proxy-with-apache-http-client-4">How to use Socks 5 proxy with Apache HTTP Client 4?</a></li><li><a href="http://book.51cto.com/art/200809/89230.htm">使用ProxySelector选择代理服务器</a></li><li><a href="http://docs.oracle.com/javase/7/docs/technotes/guides/net/proxies.html">Java Networking and Proxies</a></li></ol></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/431421.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-08-02 14:11 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/08/02/431421.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 使用embeded tomcat进行嵌入式javaee开发－启动tomcat</title><link>http://www.blogjava.net/wangxinsh55/archive/2016/07/18/431229.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 18 Jul 2016 06:42:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/07/18/431229.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/431229.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/07/18/431229.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/431229.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/431229.html</trackback:ping><description><![CDATA[<div>https://www.iflym.com/index.php/code/use-embeded-tomcat-to-javaee-start-tomcat.html</div><br /><div>昨天在网上研究了下关于将tomcat嵌入到主程序中进行运行，而不是像以前将一个web项目copy到tomcat中进行运行。之所以这样做的原 因，即是因为项目部署到客户方，在进行更新的时候，需要手动地进行更新，再把相应代码copy到tomcat，然后再运行。运用embeded  tomcat就可以将项目与tomcat分开，在进行更新时，先使用自定义的程序进行自动化更新，待更新完毕之后，再启动tomcat（或其它 javaee容器）进行项目运行。 <p> </p><p> 	 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这样做的最终效果就是修改了项目的运行方式。原先的运行方式是以tomcat为中心，由tomcat来启动和终止项目，现在是由我们的启动程序 为中心，由启动程序来负责启动和终止项目。就相当于现在流行的cs程序一样，有单独的启动脚本，在启动时进行环境预初始化，更新程序以及其它操作，待完成 之后再进行最终的项目启动。</p> <p> 	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这篇主要讲解如何使用embeded  tomcat在代码中进行启动和终止。网上的一般文章均为tomca5.x来做，这里使用了最新的tomcat7，因为tomcat7为embeded开 发，单独发布了org.apache.tomcat.embed包，以进行独立的embed开发。以下是相应的maven包</p> <div><div id="highlighter_270301"  xml"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">01</div><div number2="" index1=""  alt1"="">02</div><div number3="" index2=""  alt2"="">03</div><div number4="" index3=""  alt1"="">04</div><div number5="" index4=""  alt2"="">05</div><div number6="" index5=""  alt1"="">06</div><div number7="" index6=""  alt2"="">07</div><div number8="" index7=""  alt1"="">08</div><div number9="" index8=""  alt2"="">09</div><div number10="" index9=""  alt1"="">10</div><div number11="" index10=""  alt2"="">11</div><div number12="" index11=""  alt1"="">12</div><div number13="" index12=""  alt2"="">13</div><div number14="" index13=""  alt1"="">14</div><div number15="" index14=""  alt2"="">15</div><div number16="" index15=""  alt1"="">16</div><div number17="" index16=""  alt2"="">17</div><div number18="" index17=""  alt1"="">18</div><div number19="" index18=""  alt2"="">19</div><div number20="" index19=""  alt1"="">20</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">&lt;</code><code keyword"="">dependency</code><code plain"="">&gt;</code></div><div number2="" index1=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">groupId</code><code plain"="">&gt;org.apache.tomcat.embed&lt;/</code><code keyword"="">groupId</code><code plain"="">&gt;</code></div><div number3="" index2=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">artifactId</code><code plain"="">&gt;tomcat-embed-core&lt;/</code><code keyword"="">artifactId</code><code plain"="">&gt;</code></div><div number4="" index3=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">version</code><code plain"="">&gt;7.0.2&lt;/</code><code keyword"="">version</code><code plain"="">&gt;</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;/</code><code keyword"="">dependency</code><code plain"="">&gt;</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">dependency</code><code plain"="">&gt;</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">groupId</code><code plain"="">&gt;org.apache.tomcat&lt;/</code><code keyword"="">groupId</code><code plain"="">&gt;</code></div><div number8="" index7=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">artifactId</code><code plain"="">&gt;tomcat-util&lt;/</code><code keyword"="">artifactId</code><code plain"="">&gt;</code></div><div number9="" index8=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">version</code><code plain"="">&gt;7.0.2&lt;/</code><code keyword"="">version</code><code plain"="">&gt;</code></div><div number10="" index9=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;/</code><code keyword"="">dependency</code><code plain"="">&gt;</code></div><div number11="" index10=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">dependency</code><code plain"="">&gt;</code></div><div number12="" index11=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">groupId</code><code plain"="">&gt;org.apache.tomcat.embed&lt;/</code><code keyword"="">groupId</code><code plain"="">&gt;</code></div><div number13="" index12=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">artifactId</code><code plain"="">&gt;tomcat-embed-jasper&lt;/</code><code keyword"="">artifactId</code><code plain"="">&gt;</code></div><div number14="" index13=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">version</code><code plain"="">&gt;7.0.2&lt;/</code><code keyword"="">version</code><code plain"="">&gt;</code></div><div number15="" index14=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;/</code><code keyword"="">dependency</code><code plain"="">&gt;</code></div><div number16="" index15=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">dependency</code><code plain"="">&gt;</code></div><div number17="" index16=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">groupId</code><code plain"="">&gt;org.apache.tomcat.embed&lt;/</code><code keyword"="">groupId</code><code plain"="">&gt;</code></div><div number18="" index17=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">artifactId</code><code plain"="">&gt;tomcat-embed-logging-juli&lt;/</code><code keyword"="">artifactId</code><code plain"="">&gt;</code></div><div number19="" index18=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;</code><code keyword"="">version</code><code plain"="">&gt;7.0.2&lt;/</code><code keyword"="">version</code><code plain"="">&gt;</code></div><div number20="" index19=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">&lt;/</code><code keyword"="">dependency</code><code plain"="">&gt;</code></div></div></td></tr></tbody></table></div></div> <p> 	&nbsp;&nbsp;&nbsp;&nbsp;使用了embed包中的core包，以及用于编译jsp的jasper包，然后是工具类以及进行上场记录的logging-juli包。开始写代码：</p> <div><div id="highlighter_885343"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div></td><td><div><div number1="" index0=""  alt2"=""><code comments"="">//设置工作目录</code></div><div number2="" index1=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">String catalina_home = </code><code string"="">"d:/"</code><code plain"="">;</code></div><div number3="" index2=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">Tomcat tomcat = </code><code keyword"="">new</code> <code plain"="">Tomcat();</code></div><div number4="" index3=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">tomcat.setHostname(</code><code string"="">"localhost"</code><code plain"="">);</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">tomcat.setPort(startPort);</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">//设置工作目录,其实没什么用,tomcat需要使用这个目录进行写一些东西</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">tomcat.setBaseDir(catalina_home);</code></div></div></td></tr></tbody></table></div></div> <p> 	 &nbsp;&nbsp;&nbsp;&nbsp;上面使用了Tomcat类来进行启动类，在tomcat7以前均是使用一个叫Embed类来进行启动，在tomcat7之后，embed类被不建 议使用，而建议使用新的Tomcat类来进行启动了。然后设置主机名，端口，再设置一个工作目录。这个工作目录可以是任意目录，主要是tomcat需要这 个目录来记录一些东西，比如记录word信息，日志信息（如果配置了日志的话），以及临时文件存储等。</p> <div><div id="highlighter_758113"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div><div number8="" index7=""  alt1"="">8</div></td><td><div><div number1="" index0=""  alt2"=""><code comments"="">//设置程序的目录信息</code></div><div number2="" index1=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">tomcat.getHost().setAppBase(</code><code string"="">"e:/"</code><code plain"="">);</code></div><div number3="" index2=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">// Add AprLifecycleListener</code></div><div number4="" index3=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">StandardServer server = (StandardServer) tomcat.getServer();</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">AprLifecycleListener listener = </code><code keyword"="">new</code> <code plain"="">AprLifecycleListener();</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">server.addLifecycleListener(listener);</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">//注册关闭端口以进行关闭</code></div><div number8="" index7=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">tomcat.getServer().setPort(shutdownPort);</code></div></div></td></tr></tbody></table></div></div> <p> 	 &nbsp;&nbsp;&nbsp;&nbsp;上面的代码，首先设置我们的项目程序所在的appbase，即放项目代码的地方。在通常的tomcat配置中，这个目录一般是webapps。接 着设置一个listener，这个listener主要是负责启动一些比如html  native支持程序以及ipv6等信息配置（可以忽略）。接着是配置一个关闭的注册端口，当向这个端口发送信息时，就可以达到关闭tomcat的目的 （后面会讲）。</p> <div><div id="highlighter_58990"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div><div number8="" index7=""  alt1"="">8</div><div number9="" index8=""  alt2"="">9</div></td><td><div><div number1="" index0=""  alt2"=""><code comments"="">//加载上下文</code></div><div number2="" index1=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">StandardContext standardContext = </code><code keyword"="">new</code> <code plain"="">StandardContext();</code></div><div number3="" index2=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">standardContext.setPath(</code><code string"="">"/aa"</code><code plain"="">);</code><code comments"="">//contextPath</code></div><div number4="" index3=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">standardContext.setDocBase(</code><code string"="">"aa"</code><code plain"="">);</code><code comments"="">//文件目录位置</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">standardContext.addLifecycleListener(</code><code keyword"="">new</code> <code plain"="">Tomcat.DefaultWebXmlListener());</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">//保证已经配置好了。</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">standardContext.addLifecycleListener(</code><code keyword"="">new</code> <code plain"="">Tomcat.FixContextListener());</code></div><div number8="" index7=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">standardContext.setSessionCookieName(</code><code string"="">"t-session"</code><code plain"="">);</code></div><div number9="" index8=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">tomcat.getHost().addChild(standardContext);</code></div></div></td></tr></tbody></table></div></div> <p> 	 &nbsp;&nbsp;&nbsp;&nbsp;我们单独使用了一个Context来为这个host添加上下文，tomcat本身提供一个方法tomcat.addWeb方法来添加项目包，不过 由于这里需要单独设置一个tomcat的sessionName，所以使用与与tomcat.addWeb实现类似的方法来添加一个项目包。<br /> 	 &nbsp;&nbsp;&nbsp;&nbsp;以上代码中有两个需要注意的listener，一个是DefaultWebXmlListener，这个是由tomcat加载一些默认的配置信 息，比如jspServlet，以及一些繁复的mime/type信息；加上这个，就不需要我们自己去写这么多的配置，因为每个项目都需要这些。这个配置 与tomcat目录下的conf/web.xml中的配置一样，只不过这里是代码化了。第二个是FixContextListener，这个主要是在项目 部署完后，将这个上下文设置为configured，表示已经配置好了（不然，tomcat启动时会报错，即相应上下文还未配置好）。<br /> 	&nbsp;&nbsp;&nbsp;&nbsp;配置OK了之后，就是启动tomcat了：</p> <div><div id="highlighter_710437"  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">tomcat.start();</code></div><div number2="" index1=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">tomcat.getServer().await();</code></div></div></td></tr></tbody></table></div></div> <p> 	&nbsp;&nbsp;&nbsp;&nbsp;启动tomcat，并让tomcat在关闭端口上监听。如果没有最后一句，程序将直接结束，保证监听之后，tomcat将一直监听关闭事件，待有关闭事件之后才结束当前程序。所以如果想要关闭当前的tomcat，只需要向关闭端口发送一些信息即可：</p> <div><div id="highlighter_515098" java=""  "=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div><div number3="" index2=""  alt2"="">3</div><div number4="" index3=""  alt1"="">4</div><div number5="" index4=""  alt2"="">5</div><div number6="" index5=""  alt1"="">6</div><div number7="" index6=""  alt2"="">7</div><div number8="" index7=""  alt1"="">8</div><div number9="" index8=""  alt2"="">9</div></td><td><div><div number1="" index0=""  alt2"=""><code keyword"="">private</code> <code keyword"="">static</code> <code keyword"="">void</code> <code plain"="">shutdown() </code><code keyword"="">throws</code> <code plain"="">Exception {</code></div><div number2="" index1=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">Socket socket = </code><code keyword"="">new</code> <code plain"="">Socket(</code><code string"="">"localhost"</code><code plain"="">, shutdownPort);</code></div><div number3="" index2=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">OutputStream stream = socket.getOutputStream();</code></div><div number4="" index3=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">for</code><code plain"="">(</code><code keyword"="">int</code> <code plain"="">i = </code><code value"="">0</code><code plain"="">;i &lt; shutdown.length();i++)</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">stream.write(shutdown.charAt(i));</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">stream.flush();</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">stream.close();</code></div><div number8="" index7=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">socket.close();</code></div><div number9="" index8=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div></div></td></tr></tbody></table></div></div> <p> 	&nbsp;&nbsp;&nbsp;&nbsp;这样即可达到关闭tomcat的目的。</p> <p> 	 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;实际上看整个项目代码，项目代码的运行，就是一个配置一个基础的server.xml（即tomcat目录下的 conf/server.xml)，先配置运行端口，关闭监听端口；然后配置运行的host以及添加一个上下文context，最后就开始运行并开始监 听。对照这个程序，再看一下server.xml中的配置信息，就很容易明白以上这段代码了。</p></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/431229.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-07-18 14:42 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/07/18/431229.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java修改static final常量值  </title><link>http://www.blogjava.net/wangxinsh55/archive/2016/06/28/431031.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 28 Jun 2016 09:32:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/06/28/431031.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/431031.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/06/28/431031.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/431031.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/431031.html</trackback:ping><description><![CDATA[<div>http://ljhzzyx.blog.163.com/blog/static/3838031220141011111435161/</div><br /><div>java中，final标识的变量是不可修改的，但是通过反射的方式达到修改的目的。修改的示例也很简单，在这里 http://stackoverflow.com/questions/2474017/using-reflection-to-change-static-final-file-separatorchar-for-unit-testing<div fc05="" fc11="" nbw-blog=""  ztag"=""><wbr><div><div>public class EverythingIsTrue {</div><div>&nbsp; &nbsp; static void setFinalStatic(Field field, Object newValue) throws Exception {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; field.setAccessible(true);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; Field modifiersField = Field.class.getDeclaredField("modifiers");</div><div>&nbsp; &nbsp; &nbsp; &nbsp; modifiersField.setAccessible(true);</div><div>&nbsp; &nbsp; &nbsp; &nbsp; modifiersField.setInt(field, field.getModifiers() &amp; ~Modifier.FINAL);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; field.set(null, newValue);</div><div>&nbsp; &nbsp; }</div><div>&nbsp; &nbsp; public static void main(String args[]) throws Exception {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; setFinalStatic(Boolean.class.getField("FALSE"), true);</div><div></div><div>&nbsp; &nbsp; &nbsp; &nbsp; System.out.format("Everything is %s", false); // "Everything is true"</div><div>&nbsp; &nbsp; }</div><div>}</div></div><div></div><div>&nbsp; &nbsp; 关键点在于<span style="line-height: 28px;">.setAccessible(true)，并且修改</span><span style="line-height: 28px;">modifiers去除final属性。获得修饰符的方式可以通过</span>java.lang.reflect.Modifier，详细说明在这里</div><div>http://blog.csdn.net/xiao__gui/article/details/8141216</div><div><div>通过Modifier的isPublic、isPrivate、isStatic等方法，可以判断是否包含某些修饰符</div><div>boolean isStatic = Modifier.isStatic(field.getModifiers());</div><div>if(isStatic) {</div><div>&nbsp; &nbsp; System.out.println(field.get(null).toString());</div><div>}</div></div><div>这里的<span style="line-height: 28px;">field是静态类型的，因此</span><span style="line-height: 28px;">field.get(null)方法的参数，可以是null，也可以是A.class这样的目标类，不用提供实例对象。查看</span><span style="line-height: 28px;">java.lang.reflect.Modifier的代码，可以知道对修饰符的定义是通过二进制位来实现的。上面文章中有举例</span></div><div><p style="color: #362e2b; font-family: Arial; font-size: 14px; line-height: 26px;" align="left">public static，对应的整数就是二进制的：1001，也就是9。如下：</p><table style="color: #362e2b; font-family: Arial; font-size: 14px; line-height: 26px;" border="1" cellpadding="0" cellspacing="0"><tbody><tr><td valign="top"><p align="center">&#8230;&#8230;</p></td><td valign="top"><p align="center">native</p></td><td valign="top"><p align="center">transient</p></td><td valign="top"><p align="center">volatile</p></td><td valign="top"><p align="center">synchronized</p></td><td valign="top"><p align="center">final</p></td><td valign="top"><p align="center">static</p></td><td valign="top"><p align="center">protected</p></td><td valign="top"><p align="center">private</p></td><td valign="top"><p align="center">public</p></td></tr><tr><td valign="top"><p align="center">&nbsp;</p></td><td valign="top"><p align="center">0</p></td><td valign="top"><p align="center">0</p></td><td valign="top"><p align="center">0</p></td><td valign="top"><p align="center">0</p></td><td valign="top"><p align="center">0</p></td><td valign="top"><p align="center">1</p></td><td valign="top"><p align="center">0</p></td><td valign="top"><p align="center">0</p></td><td valign="top"><p align="center">1</p></td></tr></tbody></table></div><div><span style="line-height: 28px;"><br /></span></div><div><span style="line-height: 28px;">源码中的完整定义如下</span></div><div><div>public static final int PUBLIC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = 0x00000001;</div><div>public static final int PRIVATE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= 0x00000002;</div><div>public static final int PROTECTED &nbsp; &nbsp; &nbsp; &nbsp;= 0x00000004;</div><div>public static final int STATIC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = 0x00000008;</div><div>public static final int FINAL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= 0x00000010;</div><div>public static final int SYNCHRONIZED &nbsp; &nbsp; = 0x00000020;</div><div>public static final int VOLATILE &nbsp; &nbsp; &nbsp; &nbsp; = 0x00000040;</div><div>public static final int TRANSIENT &nbsp; &nbsp; &nbsp; &nbsp;= 0x00000080;</div><div>public static final int NATIVE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = 0x00000100;</div><div>public static final int INTERFACE &nbsp; &nbsp; &nbsp; &nbsp;= 0x00000200;</div><div>public static final int ABSTRACT &nbsp; &nbsp; &nbsp; &nbsp; = 0x00000400;</div><div>public static final int STRICT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; = 0x00000800;</div><div></div><div>根据数值，得到完整的顺序是这样的</div><div>strict,abstract,interface,native,transient,volatile,synchronized,final,static,protected,private,public</div></div><div>&nbsp; &nbsp; &nbsp; 由此就可以了解<span style="line-height: 28px;">field.getModifiers() &amp; ~Modifier.FINAL这部分的含义的，先</span><span style="line-height: 28px;">~Modifier.FINAL将final所在的位设置为0，其他所有位设置为1。</span><span style="line-height: 28px;">field.getModifiers() &amp; ~Modifier.FINAL与的操作，就是将</span><span style="line-height: 28px;">field的</span><span style="line-height: 28px;">modifiers属性修饰符中final给去除掉。</span></div><div></div><div>&nbsp; &nbsp; &nbsp; 但是在自己尝试的过程中，发现一个问题。设置final变量的方法是<span style="line-height: 28px;">field.set()，如果在这个方法之前调用了</span><span style="line-height: 28px;">field.get()方法，顺序如下面这样</span></div><div><div>field.get(null).toString();</div><div>...</div><div>field.set(null, newValue);</div></div><div>这时<span style="line-height: 28px;">对final变量的赋值就会报错，就算</span><span style="line-height: 28px;">.setAccessible(true);也是没有用的。具体原因尚不清楚，估计需要跟踪源码才能查清楚。</span></div><br /><div>&nbsp; &nbsp; &nbsp; 需要注意的是，对于int、long、boolean以及String等基本类型，由于编译器优化的原因，很多使用常量的地方的值还是原来的数值。如</div><div><div>if (index &gt; maxFormatRecordsIndex) {</div><div>&nbsp; &nbsp; index &nbsp;= &nbsp;maxFormatRecordsIndex;</div><div>}</div><div><span style="line-height: 28px;">maxFormatRecordsIndex为final，则被编译器改成这样</span></div><div>if (index &gt; 100) {</div><div>&nbsp; &nbsp; index = 100;</div><div>}</div><div></div><div>System.out.println(Bean.INT_VALUE);</div><div>//编译时会被优化成下面这样：</div><div>System.out.println(100);</div></div><div>所以正常的使用方式还是获取原来的值，获得修改后的final常量的值需要用field.get(null)这样的方式。</div><div></div><div>&nbsp; &nbsp; &nbsp; 总体来讲，改基本类型的final常量的用处还是不大，如果是非基本类型常量，则有实际意义。</div></div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/431031.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-06-28 17:32 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/06/28/431031.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Max MQTT connections</title><link>http://www.blogjava.net/wangxinsh55/archive/2016/06/01/430732.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Wed, 01 Jun 2016 08:15:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/06/01/430732.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/430732.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/06/01/430732.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/430732.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/430732.html</trackback:ping><description><![CDATA[<div>http://stackoverflow.com/questions/29358313/max-mqtt-connections?answertab=votes#tab-top<br /><br /><br /><div data-questionid="29358313" id="question" style="margin: 0px; border: 0px; font-size: 13px; clear: both; color: #242729; font-family: Arial, &quot;Helvetica Neue&quot;, Helvetica, sans-serif; line-height: 16.9px; background-color: #ffffff;"><table style="margin: 0px; padding: 0px; border: 0px; font-size: 13px; border-spacing: 0px; border-collapse: collapse;"><tbody style="margin: 0px; padding: 0px; border: 0px;"><tr style="margin: 0px; padding: 0px; border: 0px;"><td style="margin: 0px; padding: 0px 15px 0px 0px; border: 0px; vertical-align: top;"><div style="margin: 0px; border: 0px; text-align: center; min-width: 46px;"><span itemprop="upvoteCount"  "="" style="margin: 8px 0px; padding: 0px; border: 0px; font-size: 20px; display: block; color: #6a737c;">4</span><a title="This question does not show any research effort; it is unclear or not useful" style="margin: 0px auto 10px; padding: 0px; border: 0px; font-size: 1px; color: #0077cc; cursor: pointer; overflow: hidden; display: block; text-indent: -9999em; width: 40px; height: 30px; background-image: url(&quot;img/sprites.svg?v=8c1c8cba242e&quot;), none; background-size: initial; background-position: 0px -220px; background-repeat: no-repeat;">down vote</a><a href="http://stackoverflow.com/questions/29358313/max-mqtt-connections?answertab=votes#" style="margin: 0px auto 2px; padding: 0px; border: 0px; font-size: 1px; color: #0077cc; text-decoration: none; cursor: pointer; overflow: hidden; display: block; text-indent: -9999em; width: 40px; height: 30px; background-image: url(&quot;img/sprites.svg?v=8c1c8cba242e&quot;), none; background-size: initial; background-position: 0px -120px; background-repeat: no-repeat;">favorite</a><div style="margin: 0px; border: 0px;"><span style="margin: 0px; padding: 0px; border: 0px; color: #6a737c;">3</span></div></div></td><td style="margin: 0px; padding: 0px; border: 0px; vertical-align: top;"><div style="margin: 0px; border: 0px;"><div itemprop="text" style="margin: 0px 0px 5px; border: 0px; font-size: 15px; width: 660px; word-wrap: break-word; line-height: 1.3;"><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">I have a need to create a server farm that can handle 5+ million connections, 5+ million topics (one per client), process 300k messages/sec.</p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">I tried to see what various message brokers were capable so I am currently using two RHEL EC2 instances (r3.4xlarge) to make lots of available resources. So you do not need to look it up, it has 16vCPU, 122GB RAM. I am nowhere near that limit in usage.</p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;"><strong style="margin: 0px; padding: 0px; border: 0px;">I am unable to pass the 600k connections limit. Since there doesn't seem to be any O/S limitation (plenty of RAM/CPU/etc.) on either the client nor the server what is limiting me?</strong></p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">I have edited /etc/security/limits.conf as follows:</p><pre style="margin-top: 0px; margin-bottom: 1em; padding: 5px; border: 0px; font-size: 13px; width: auto; max-height: 600px; overflow: auto; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; word-wrap: normal; background-color: #eff0f1;"><code style="margin: 0px; padding: 0px; border: 0px; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; white-space: inherit;">* soft  nofile  20000000 * hard  nofile  20000000  * soft  nproc  20000000 * hard  nproc  20000000  root  soft  nofile 20000000 root  hard  nofile 20000000 </code></pre><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">I have edited /etc/sysctl.conf as follows:</p><pre style="margin-top: 0px; margin-bottom: 1em; padding: 5px; border: 0px; font-size: 13px; width: auto; max-height: 600px; overflow: auto; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; word-wrap: normal; background-color: #eff0f1;"><code style="margin: 0px; padding: 0px; border: 0px; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; white-space: inherit;">net.ipv4.ip_local_port_range = 1024 65535   net.ipv4.tcp_tw_reuse = 1  net.ipv4.tcp_mem = 5242880  5242880 5242880  net.ipv4.tcp_tw_recycle = 1  fs.file-max = 20000000  fs.nr_open = 20000000  net.ipv4.tcp_syncookies = 0  net.ipv4.tcp_max_syn_backlog = 10000  net.ipv4.tcp_synack_retries = 3  net.core.somaxconn=65536  net.core.netdev_max_backlog=100000  net.core.optmem_max = 20480000 </code></pre><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">For Apollo: export APOLLO_ULIMIT=20000000</p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">For ActiveMQ:</p><pre style="margin-top: 0px; margin-bottom: 1em; padding: 5px; border: 0px; font-size: 13px; width: auto; max-height: 600px; overflow: auto; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; word-wrap: normal; background-color: #eff0f1;"><code style="margin: 0px; padding: 0px; border: 0px; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; white-space: inherit;">ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS -Dorg.apache.activemq.UseDedicatedTaskRunner=false" ACTIVEMQ_OPTS_MEMORY="-Xms50G -Xmx115G" </code></pre><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">I created 20 additional private addresses for eth0 on the client, then assigned them: ip addr add 11.22.33.44/24 dev eth0</p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">I am FULLY aware of the 65k port limits which is why I did the above.</p><ul style="margin: 0px 0px 1em 30px; padding: 0px; border: 0px;"><li style="margin: 0px 0px 0.5em; padding: 0px; border: 0px; word-wrap: break-word;">For ActiveMQ I got to: 574309</li><li style="margin: 0px 0px 0.5em; padding: 0px; border: 0px; word-wrap: break-word;">For Apollo I got to: 592891</li><li style="margin: 0px 0px 0.5em; padding: 0px; border: 0px; word-wrap: break-word;">For Rabbit I got to 90k but logging was awful and couldn't figure out what to do to go higher although I know its possible.</li><li style="margin: 0px 0px 0.5em; padding: 0px; border: 0px; word-wrap: break-word;">For Hive I got to trial limit of 1000. Awaiting a license</li><li style="margin: 0px; padding: 0px; border: 0px; word-wrap: break-word;">IBM wants to trade the cost of my house to use them - nah!</li></ul></div><div style="margin: 0px 0px 10px; border: 0px; clear: both;"><a href="http://stackoverflow.com/questions/tagged/activemq" title="show questions tagged 'activemq'" rel="tag" style="margin: 2px 2px 2px 0px; padding: 0.4em 0.5em; border: 1px solid transparent; font-size: 12px; color: #39739d; text-decoration: none; cursor: pointer; position: relative; display: inline-block; line-height: 1; white-space: nowrap; text-align: center; border-radius: 0px; transition: all 0.15s ease-in-out; background-color: #e1ecf4;">activemq</a>&nbsp;<a href="http://stackoverflow.com/questions/tagged/tcp-ip" title="show questions tagged 'tcp-ip'" rel="tag" style="margin: 2px 2px 2px 0px; padding: 0.4em 0.5em; border: 1px solid transparent; font-size: 12px; color: #39739d; text-decoration: none; cursor: pointer; position: relative; display: inline-block; line-height: 1; white-space: nowrap; text-align: center; border-radius: 0px; transition: all 0.15s ease-in-out; background-color: #e1ecf4;">tcp-ip</a>&nbsp;<a href="http://stackoverflow.com/questions/tagged/mqtt" title="show questions tagged 'mqtt'" rel="tag" style="margin: 2px 2px 2px 0px; padding: 0.4em 0.5em; border: 1px solid transparent; font-size: 12px; color: #39739d; text-decoration: none; cursor: pointer; position: relative; display: inline-block; line-height: 1; white-space: nowrap; text-align: center; border-radius: 0px; transition: all 0.15s ease-in-out; background-color: #e1ecf4;">mqtt</a>&nbsp;<a href="http://stackoverflow.com/questions/tagged/apollo" title="show questions tagged 'apollo'" rel="tag" style="margin: 2px 2px 2px 0px; padding: 0.4em 0.5em; border: 1px solid transparent; font-size: 12px; color: #39739d; text-decoration: none; cursor: pointer; position: relative; display: inline-block; line-height: 1; white-space: nowrap; text-align: center; border-radius: 0px; transition: all 0.15s ease-in-out; background-color: #e1ecf4;">apollo</a>&nbsp;<a href="http://stackoverflow.com/questions/tagged/hivemq" title="show questions tagged 'hivemq'" rel="tag" style="margin: 2px 2px 2px 0px; padding: 0.4em 0.5em; border: 1px solid transparent; font-size: 12px; color: #39739d; text-decoration: none; cursor: pointer; position: relative; display: inline-block; line-height: 1; white-space: nowrap; text-align: center; border-radius: 0px; transition: all 0.15s ease-in-out; background-color: #e1ecf4;">hivemq</a></div><table style="margin: 0px 0px 4px; padding: 0px; border: 0px; font-size: 13px; border-spacing: 0px; border-collapse: collapse; width: 660px;"><tbody style="margin: 0px; padding: 0px; border: 0px;"><tr style="margin: 0px; padding: 0px; border: 0px;"><td style="margin: 0px; padding: 0px; border: 0px; vertical-align: top;"><div style="margin: 0px; padding-top: 2px; border: 0px;"><a href="http://stackoverflow.com/q/29358313" title="short permalink to this question" id="link-post-29358313" style="margin: 0px; padding: 0px 3px 2px; border: 0px; color: #848d95; text-decoration: none; cursor: pointer; display: inline-block;">share</a><a href="http://stackoverflow.com/posts/29358313/edit" title="" style="margin: 0px; padding: 0px 3px 2px; border: 0px; color: #848d95; text-decoration: none; cursor: pointer; display: inline-block;">improve this question</a></div></td><td owner"="" style="margin: 0px; padding: 0px; border: 0px; vertical-align: top; width: 200px; background-color: #e0eaf1;"><div "="" style="margin: 0px; padding: 5px 6px 7px 7px; border: 0px; box-sizing: border-box; width: 200px; color: #6a737c;"><div style="margin: 1px 0px 4px; border: 0px; font-size: 12px; white-space: nowrap;">asked&nbsp;<span title="2015-03-30 23:52:01Z" style="margin: 0px; padding: 0px; border: 0px;">Mar 30 '15 at 23:52</span></div><div style="margin: 0px; border: 0px; float: left; width: 32px; height: 32px; border-radius: 1px;"><a href="http://stackoverflow.com/users/2101240/redboy" style="margin: 0px; padding: 0px; border: 0px; color: #0077cc; text-decoration: none; cursor: pointer;"><div style="margin: 0px; border: 0px; overflow: hidden; width: 32px; height: 32px;"><img src="https://www.gravatar.com/avatar/6fb997a0f370b1fbc3b171b0ae6b78be?s=32&amp;d=identicon&amp;r=PG" alt="" width="32" height="32" style="margin: 0px auto; padding: 0px; border: 0px; width: 32px; height: 32px; border-radius: 1px;" /></div></a></div><div style="margin: 0px 0px 0px 8px; border: 0px; line-height: 17px; word-wrap: break-word; float: left; width: calc(100% - 40px);"><a href="http://stackoverflow.com/users/2101240/redboy" style="margin: 0px; padding: 0px; border: 0px; color: #0077cc; text-decoration: none; cursor: pointer;">redboy</a><div style="margin: 0px; border: 0px;"><span title="reputation score " dir="ltr" style="margin: 0px 2px 0px 0px; padding: 0px; border: 0px; font-size: 12px; font-weight: bold;">103</span><span title="11 bronze badges" style="margin: 0px 3px 0px 2px; padding: 0px; border: 0px;"><span style="margin: 0px; padding: 0px; border: 0px; font-size: 12px;">11</span></span></div></div></div></td></tr></tbody></table></div></td></tr><tr style="margin: 0px; padding: 0px; border: 0px;"><td style="margin: 0px; padding: 0px 15px 0px 0px; border: 0px; vertical-align: top;"></td><td style="margin: 0px; padding: 0px; border: 0px;"><div id="comments-29358313"  "="" style="margin: 10px 0px 0px; padding-bottom: 10px; border-width: 1px 0px 0px; border-top-style: solid; border-top-color: #e4e6e8; width: 660px; -webkit-tap-highlight-color: rgba(255, 255, 255, 0);"><table style="margin: 0px; padding: 0px; border: 0px; font-size: 13px; border-spacing: 0px; border-collapse: collapse; width: 660px;"><tbody data-remaining-comments-count="0" data-canpost="false" data-cansee="true" data-comments-unavailable="false" data-addlink-disabled="true" style="margin: 0px; padding: 0px; border: 0px;"><tr id="comment-46910195"  "="" style="margin: 0px; padding: 0px; border: 0px;"><td style="margin: 0px; padding: 6px 6px 6px 0px; border-top-width: 0px; border-right-width: 0px; border-left-width: 0px; border-bottom-style: solid; border-bottom-color: #eff0f1; vertical-align: top; line-height: 1.3;"><table style="margin: 0px; padding: 0px; border: 0px; font-size: 13px; border-spacing: 0px; border-collapse: collapse;"><tbody style="margin: 0px; padding: 0px; border: 0px;"><tr style="margin: 0px; padding: 0px; border: 0px;"><td comment-score"="" style="margin: 0px; padding: 0px; border: 0px;">&nbsp;&nbsp;</td><td style="margin: 0px; padding: 0px; border: 0px;">&nbsp;</td></tr></tbody></table></td><td style="margin: 0px; padding: 6px 6px 6px 0px; border-top-width: 0px; border-right-width: 0px; border-left-width: 0px; border-bottom-style: solid; border-bottom-color: #eff0f1; vertical-align: top; line-height: 1.3;"><div style="margin: 0px; border: 0px;"><span style="margin: 0px; padding: 0px; border: 0px;">Can't really tell how to increase the throughput. However, checkout&nbsp;<a href="http://kafka.apache.org/" rel="nofollow" style="margin: 0px; padding: 0px; border: 0px; color: #005999; text-decoration: none; cursor: pointer;">kafka.apache.org</a>&nbsp;. Not sure about the MQTT support, but it seems capable of extrem throughput / # clients.</span>&nbsp;&#8211;&nbsp;<a href="http://stackoverflow.com/users/412763/petter-nordlander" title="14,568 reputation" style="margin: 0px; padding: 0px; border: 0px; color: #0077cc; text-decoration: none; cursor: pointer; white-space: nowrap;">Petter Nordlander</a>&nbsp;<span dir="ltr" style="margin: 0px; padding: 0px; border-top-width: 0px; border-right-width: 0px; border-left-width: 0px; border-bottom-style: none; border-color: initial; color: #9199a1;"><span title="2015-03-31 07:52:08Z" style="margin: 0px; padding: 0px; border: 0px;">Mar 31 '15 at 7:52</span></span></div></td></tr><tr id="comment-46989804"  "="" style="margin: 0px; padding: 0px; border: 0px;"><td style="margin: 0px; padding: 6px 6px 6px 0px; border-top-width: 0px; border-right-width: 0px; border-left-width: 0px; border-bottom-style: solid; border-bottom-color: #eff0f1; vertical-align: top; line-height: 1.3;"><table style="margin: 0px; padding: 0px; border: 0px; font-size: 13px; border-spacing: 0px; border-collapse: collapse;"><tbody style="margin: 0px; padding: 0px; border: 0px;"><tr style="margin: 0px; padding: 0px; border: 0px;"><td comment-score"="" style="margin: 0px; padding: 0px; border: 0px;">&nbsp;&nbsp;</td><td style="margin: 0px; padding: 0px; border: 0px;">&nbsp;</td></tr></tbody></table></td><td style="margin: 0px; padding: 6px 6px 6px 0px; border-top-width: 0px; border-right-width: 0px; border-left-width: 0px; border-bottom-style: solid; border-bottom-color: #eff0f1; vertical-align: top; line-height: 1.3;"><div style="margin: 0px; border: 0px;"><span style="margin: 0px; padding: 0px; border: 0px;">did you try mosquitto? (<a href="http://mosquitto.org/" rel="nofollow" style="margin: 0px; padding: 0px; border: 0px; color: #005999; text-decoration: none; cursor: pointer;">mosquitto.org</a>)</span>&nbsp;&#8211;&nbsp;<a href="http://stackoverflow.com/users/1972909/aleksey-izmailov" title="10,077 reputation" style="margin: 0px; padding: 0px; border: 0px; color: #0077cc; text-decoration: none; cursor: pointer; white-space: nowrap;">Aleksey Izmailov</a>&nbsp;<span dir="ltr" style="margin: 0px; padding: 0px; border-top-width: 0px; border-right-width: 0px; border-left-width: 0px; border-bottom-style: none; border-color: initial; color: #9199a1;"><span title="2015-04-02 08:02:29Z" style="margin: 0px; padding: 0px; border: 0px;">Apr 2 '15 at 8:02</span></span></div></td></tr><tr id="comment-47017819"  "="" style="margin: 0px; padding: 0px; border: 0px;"><td style="margin: 0px; padding: 6px 6px 6px 0px; border-top-width: 0px; border-right-width: 0px; border-left-width: 0px; border-bottom-style: solid; border-bottom-color: #eff0f1; vertical-align: top; line-height: 1.3;"><table style="margin: 0px; padding: 0px; border: 0px; font-size: 13px; border-spacing: 0px; border-collapse: collapse;"><tbody style="margin: 0px; padding: 0px; border: 0px;"><tr style="margin: 0px; padding: 0px; border: 0px;"><td comment-score"="" style="margin: 0px; padding: 0px; border: 0px;">&nbsp;&nbsp;</td><td style="margin: 0px; padding: 0px; border: 0px;">&nbsp;</td></tr></tbody></table></td><td style="margin: 0px; padding: 6px 6px 6px 0px; border-top-width: 0px; border-right-width: 0px; border-left-width: 0px; border-bottom-style: solid; border-bottom-color: #eff0f1; vertical-align: top; line-height: 1.3;"><div style="margin: 0px; border: 0px;"><span style="margin: 0px; padding: 0px; border: 0px;">Trying Hive, Apollo, Mosquito, Active, Rabbit, mosquito</span>&nbsp;&#8211;&nbsp;<a href="http://stackoverflow.com/users/2101240/redboy" title="103 reputation"  owner"="" style="margin: 0px; padding: 1px 5px; border: 0px; color: #0077cc; text-decoration: none; cursor: pointer; white-space: nowrap; background-color: #e0eaf1;">redboy</a>&nbsp;<span dir="ltr" style="margin: 0px; padding: 0px; border-top-width: 0px; border-right-width: 0px; border-left-width: 0px; border-bottom-style: none; border-color: initial; color: #9199a1;"><span title="2015-04-02 21:58:28Z" style="margin: 0px; padding: 0px; border: 0px;">Apr 2 '15 at 21:58</span></span></div></td></tr></tbody></table></div><div id="comments-link-29358313" data-rep="50" data-anon="true" style="margin: 0px; border: 0px;"><a comments-link="" disabled-link=""  "="" title="Use comments to ask for more information or suggest improvements. Avoid answering questions in comments." style="margin: 0px; padding: 0px 3px 2px; border: 0px; color: #848d95; cursor: pointer; opacity: 0.6;">add a comment</a></div></td></tr></tbody></table></div><div id="answers" style="margin: 0px; padding-top: 10px; border: 0px; font-size: 13px; clear: both; width: 728px; color: #242729; font-family: Arial, &quot;Helvetica Neue&quot;, Helvetica, sans-serif; line-height: 16.9px; background-color: #ffffff;"><a name="tab-top" style="margin: 0px; padding: 0px; border: 0px; color: rgb(0, 119, 204); cursor: pointer;"></a><div id="answers-header" style="margin: 10px 0px 0px; border: 0px; width: 728px;"><div answers-subheader"="" style="margin: 0px 0px 10px; border-width: 0px 0px 1px; border-bottom-style: solid; border-bottom-color: #e4e6e8; clear: both; height: 40px;"><h2>1 Answer</h2><div style="margin: 0px; border: 0px;"><div id="tabs" style="margin: 0px; border: 0px; float: right;"><a href="http://stackoverflow.com/questions/29358313/max-mqtt-connections?answertab=active#tab-top" data-nav-xhref="" title="Answers with the latest activity first" data-value="active" data-shortcut="A" style="margin: 0px 8px 0px 0px; padding: 13px 10px; border: 1px solid transparent; font-size: 12px; color: #848d95; text-decoration: none; cursor: pointer; float: left; line-height: 1; transition: all 0.15s ease-in-out; position: relative;">active</a><a href="http://stackoverflow.com/questions/29358313/max-mqtt-connections?answertab=oldest#tab-top" data-nav-xhref="" title="Answers in the order they were provided" data-value="oldest" data-shortcut="O" style="margin: 0px 8px 0px 0px; padding: 13px 10px; border: 1px solid transparent; font-size: 12px; color: #848d95; text-decoration: none; cursor: pointer; float: left; line-height: 1; transition: all 0.15s ease-in-out; position: relative;">oldest</a><a href="http://stackoverflow.com/questions/29358313/max-mqtt-connections?answertab=votes#tab-top" data-nav-xhref="" title="Answers with the highest score first" data-value="votes" data-shortcut="V" style="margin: 0px; padding: 13px 10px 14px; border-width: 1px; border-style: solid; border-color: #e4e6e8 #e4e6e8 transparent; font-size: 12px; color: #242729; text-decoration: none; cursor: pointer; float: left; line-height: 1; transition: all 0.15s ease-in-out; position: relative;">votes</a></div></div></div></div><a name="29399780" style="margin: 0px; padding: 0px; border: 0px; color: rgb(0, 119, 204); cursor: pointer;"></a><div id="answer-29399780"  accepted-answer"="" data-answerid="29399780" itemscope="" itemtype="http://schema.org/Answer" itemprop="acceptedAnswer" style="margin: 0px; padding-top: 20px; padding-bottom: 20px; border-width: 0px 0px 1px; border-bottom-style: solid; border-bottom-color: #e4e6e8; width: 728px;"><table style="margin: 0px; padding: 0px; border: 0px; font-size: 13px; border-spacing: 0px; border-collapse: collapse;"><tbody style="margin: 0px; padding: 0px; border: 0px;"><tr style="margin: 0px; padding: 0px; border: 0px;"><td style="margin: 0px; padding: 0px 15px 0px 0px; border: 0px; vertical-align: top;"><div style="margin: 0px; border: 0px; text-align: center; min-width: 46px;"><a title="This answer is useful" style="margin: 0px auto 2px; padding: 0px; border: 0px; font-size: 1px; color: #0077cc; cursor: pointer; overflow: hidden; display: block; text-indent: -9999em; width: 40px; height: 30px; background-image: url(&quot;img/sprites.svg?v=8c1c8cba242e&quot;), none; background-size: initial; background-position: 0px -170px; background-repeat: no-repeat;">up vote</a><span itemprop="upvoteCount"  "="" style="margin: 8px 0px; padding: 0px; border: 0px; font-size: 20px; display: block; color: #6a737c;">2</span><a title="This answer is not useful" style="margin: 0px auto 10px; padding: 0px; border: 0px; font-size: 1px; color: #0077cc; cursor: pointer; overflow: hidden; display: block; text-indent: -9999em; width: 40px; height: 30px; background-image: url(&quot;img/sprites.svg?v=8c1c8cba242e&quot;), none; background-size: initial; background-position: 0px -220px; background-repeat: no-repeat;">down vote</a><span load-accepted-answer-date"="" title="loading when this answer was accepted..." style="margin: 0px auto 10px; padding: 0px; border: 0px; font-size: 1px; overflow: hidden; display: block; text-indent: -9999em; width: 40px; height: 40px; color: #6a737c; background-image: url(&quot;img/sprites.svg?v=8c1c8cba242e&quot;), none; background-size: initial; background-position: -40px -270px; background-repeat: no-repeat;">accepted</span></div></td><td style="margin: 0px; padding: 0px; border: 0px; vertical-align: top;"><div itemprop="text" style="margin: 0px 0px 5px; border: 0px; font-size: 15px; width: 660px; word-wrap: break-word; line-height: 1.3;"><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;"><strong style="margin: 0px; padding: 0px; border: 0px;">ANSWER:</strong>&nbsp;While doing this I realized that I had a misspelling in my client setting within /etc/sysctl.conf file for: net.ipv4.ip_local_port_range</p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">I am now able to connect 956,591 MQTT clients to my Apollo server in 188sec.</p><hr style="border: 0px; color: #d6d9dc; height: 1px; margin-bottom: 20px; background-color: #d6d9dc;" /><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">More info: Trying to isolate if this is an O/S connection limitation or a Broker, I decided to write a simple Client/Server.</p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">The server:</p><pre style="margin-top: 0px; margin-bottom: 1em; padding: 5px; border: 0px; font-size: 13px; width: auto; max-height: 600px; overflow: auto; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; word-wrap: normal; background-color: #eff0f1;"><code style="margin: 0px; padding: 0px; border: 0px; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; white-space: inherit;">    Socket client = null;     server = new ServerSocket(1884);     while (true) {         client = server.accept();         clients.add(client);     } </code></pre><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">The Client:</p><pre style="margin-top: 0px; margin-bottom: 1em; padding: 5px; border: 0px; font-size: 13px; width: auto; max-height: 600px; overflow: auto; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; word-wrap: normal; background-color: #eff0f1;"><code style="margin: 0px; padding: 0px; border: 0px; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; white-space: inherit;">    while (true) {         InetAddress clientIPToBindTo = getNextClientVIP();         Socket client = new Socket(hostname, 1884, clientIPToBindTo, 0);         clients.add(client);     } </code></pre><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">With 21 IPs, I would expect 65535-1024*21 = 1354731 to be the boundary. In reality I am able to achieve 1231734</p><pre style="margin-top: 0px; margin-bottom: 1em; padding: 5px; border: 0px; font-size: 13px; width: auto; max-height: 600px; overflow: auto; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; word-wrap: normal; background-color: #eff0f1;"><code style="margin: 0px; padding: 0px; border: 0px; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; white-space: inherit;">[root@ip ec2-user]# cat /proc/net/sockstat sockets: used 1231734 TCP: inuse 5 orphan 0 tw 0 alloc 1231307 mem 2 UDP: inuse 4 mem 1 UDPLITE: inuse 0 RAW: inuse 0 FRAG: inuse 0 memory 0 </code></pre><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">So the socket/kernel/io stuff is worked out.</p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">I am STILL unable to achieve this using any broker.</p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">Again just after my client/server test this is the kernel settings.</p><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">Client:</p><pre style="margin-top: 0px; margin-bottom: 1em; padding: 5px; border: 0px; font-size: 13px; width: auto; max-height: 600px; overflow: auto; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; word-wrap: normal; background-color: #eff0f1;"><code style="margin: 0px; padding: 0px; border: 0px; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; white-space: inherit;">[root@ip ec2-user]# sysctl -p net.ipv4.ip_local_port_range = 1024     65535 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_mem = 5242880      5242880 15242880 net.ipv4.tcp_tw_recycle = 1 fs.file-max = 20000000 fs.nr_open = 20000000  [root@ip ec2-user]# cat /etc/security/limits.conf * soft  nofile  2000000 * hard  nofile  2000000     root  soft  nofile 2000000 root  hard  nofile 2000000 </code></pre><p style="margin: 0px 0px 1em; padding: 0px; border: 0px; clear: both;">Server:</p><pre style="margin-top: 0px; margin-bottom: 1em; padding: 5px; border: 0px; font-size: 13px; width: auto; max-height: 600px; overflow: auto; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; word-wrap: normal; background-color: #eff0f1;"><code style="margin: 0px; padding: 0px; border: 0px; font-family: Consolas, Menlo, Monaco, &quot;Lucida Console&quot;, &quot;Liberation Mono&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Courier New&quot;, monospace, sans-serif; white-space: inherit;">[root@ ec2-user]# sysctl -p net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_mem = 5242880      5242880 5242880 net.ipv4.tcp_tw_recycle = 1 fs.file-max = 20000000 fs.nr_open = 20000000 net.ipv4.tcp_syncookies = 0 net.ipv4.tcp_max_syn_backlog = 1000000 net.ipv4.tcp_synack_retries = 3 net.core.somaxconn = 65535 net.core.netdev_max_backlog = 1000000 net.core.optmem_max = 20480000 </code></pre></div><table style="margin: 0px 0px 4px; padding: 0px; border: 0px; font-size: 13px; border-spacing: 0px; border-collapse: collapse; width: 660px;"><tbody style="margin: 0px; padding: 0px; border: 0px;"><tr style="margin: 0px; padding: 0px; border: 0px;"><td style="margin: 0px; padding: 0px; border: 0px; vertical-align: top;"><div style="margin: 0px; padding-top: 2px; border: 0px;"><a href="http://stackoverflow.com/a/29399780" title="short permalink to this answer" id="link-post-29399780" style="margin: 0px; padding: 0px 3px 2px; border: 0px; color: #848d95; text-decoration: none; cursor: pointer; display: inline-block;">share</a><a href="http://stackoverflow.com/posts/29399780/edit" title="" style="margin: 0px; padding: 0px 3px 2px; border: 0px; color: #848d95; text-decoration: none; cursor: pointer; display: inline-block;">improve this answer</a></div></td></tr></tbody></table></td></tr></tbody></table></div></div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/430732.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-06-01 16:15 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/06/01/430732.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HDFS配置Kerberos认证 </title><link>http://www.blogjava.net/wangxinsh55/archive/2016/05/31/430718.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 31 May 2016 09:24:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/05/31/430718.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/430718.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/05/31/430718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/430718.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/430718.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://blog.csdn.net/wulantian/article/details/42173023HDFS配置Kerberos认证 2014.11.04  本文主要记录 CDH Hadoop 集群上配置 HDFS 集成 Kerberos 的过程，包括 Kerberos 的安装和 Hadoop 相关配置修改说明。   注意：  下面第一、二部分内容，摘抄自《Hadoop的kerberos...&nbsp;&nbsp;<a href='http://www.blogjava.net/wangxinsh55/archive/2016/05/31/430718.html'>阅读全文</a><img src ="http://www.blogjava.net/wangxinsh55/aggbug/430718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-05-31 17:24 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/05/31/430718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Benchmarking Apache Kafka: 2 Million Writes Per Second (On Three Cheap Machines)</title><link>http://www.blogjava.net/wangxinsh55/archive/2016/05/26/430663.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Thu, 26 May 2016 05:53:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/05/26/430663.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/430663.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/05/26/430663.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/430663.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/430663.html</trackback:ping><description><![CDATA[<div>https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines</div><br /><br /><div><div style="margin: 0px; padding: 0px; line-height: 20px; color: #888888; font-family: Arial, Helvetica, sans-serif; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff;"><div parsys"="" style="margin: 0px; padding: 0px;"><div section"="" style="margin: 0px; padding: 0px;"><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">wrote a&nbsp;<a href="http://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying" style="color: #0077b5; text-decoration: none;">blog post</a>&nbsp;about how LinkedIn uses&nbsp;<a href="http://kafka.apache.org/" style="color: #0077b5; text-decoration: none;">Apache Kafka</a>&nbsp;as a central publish-subscribe log for integrating data between applications, stream processing, and Hadoop data ingestion.</p><img src="https://content.linkedin.com/content/dam/engineering/en-us/blog/migrated/kafka-logo-no-text.png" style="border: 0px; max-width: 100%; height: auto; display: block; margin: 0px auto; width: 200px;"  alt="" /><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">To actually make this work, though, this "universal log" has to be a cheap abstraction. If you want to use a system as a central data hub it has to be fast, predictable, and easy to scale so you can dump all your data onto it. My experience has been that systems that are fragile or expensive inevitably develop a wall of protective process to prevent people from using them; a system that scales easily often ends up as a key architectural building block just because using it is the easiest way to get things built.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">I've always liked the benchmarks of Cassandra that show it doing a million writes per second on three hundred machines on<a href="http://techblog.netflix.com/2011/11/benchmarking-cassandra-scalability-on.html" style="color: #0077b5; text-decoration: none;">EC2</a>&nbsp;and&nbsp;<a href="http://googlecloudplatform.blogspot.com/2014/03/cassandra-hits-one-million-writes-per-second-on-google-compute-engine.html" style="color: #0077b5; text-decoration: none;">Google Compute Engine</a>. I'm not sure why, maybe it is a&nbsp;<a href="http://en.wikipedia.org/wiki/Dr._Evil" style="color: #0077b5; text-decoration: none;">Dr. Evil</a>&nbsp;thing, but doing&nbsp;<a href="https://engineering.linkedin.com/voldemort/announcing-voldemort-160-open-source-release" style="color: #0077b5; text-decoration: none;">a million</a>&nbsp;of anything per second is fun.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">In any case, one of the nice things about a Kafka log is that, as we'll see, it is cheap. A million writes per second isn't a particularly big thing. This is because a log is a much simpler thing than a database or key-value store. Indeed our production clusters take tens of millions of reads and writes per second all day long and they do so on pretty modest hardware.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">But let's do some benchmarking and take a look.</p><h2>Kafka in 30 seconds</h2><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">To help understand the benchmark, let me give a quick review of what Kafka is and a few details about how it works. Kafka is a distributed messaging system originally built at LinkedIn and now part of the&nbsp;<a href="https://www.apache.org/" style="color: #0077b5; text-decoration: none;">Apache Software Foundation</a>&nbsp;and&nbsp;<a href="http://kafka.apache.org/documentation.html#uses" style="color: #0077b5; text-decoration: none;">used</a>&nbsp;by a&nbsp;<a href="https://cwiki.apache.org/confluence/display/KAFKA/Powered+By" style="color: #0077b5; text-decoration: none;">variety of companies</a>.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">The general setup is quite simple. Producers send records to the cluster which holds on to these records and hands them out to consumers:</p><div style="margin: 0px; padding: 0px;"><img src="https://content.linkedin.com/content/dam/engineering/en-us/blog/migrated/producer_consumer.png" style="border: 0px; max-width: 100%; height: auto; display: block; margin: 0px auto; width: 400px;"  alt="" /></div><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">The key abstraction in Kafka is the topic. Producers publish their records to a topic, and consumers subscribe to one or more topics. A Kafka topic is just a sharded write-ahead log. Producers append records to these logs and consumers subscribe to changes. Each record is a key/value pair. The key is used for assigning the record to a log partition (unless the publisher specifies the partition directly).</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Here is a simple example of a single producer and consumer reading and writing from a two-partition topic.</p><div style="margin: 0px; padding: 0px;"><img src="https://content.linkedin.com/content/dam/engineering/en-us/blog/migrated/partitioned_log_0.png" style="border: 0px; max-width: 100%; height: auto; display: block; margin: 0px auto; width: 500px;"  alt="" /></div><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">This picture shows a producer process appending to the logs for the two partitions, and a consumer reading from the same logs. Each record in the log has an associated entry number that we call the offset. This offset is used by the consumer to describe it's position in each of the logs.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">These partitions are spread across a cluster of machines, allowing a topic to hold more data than can fit on any one machine.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Note that unlike most messaging systems the log is always persistent. Messages are immediately written to the filesystem when they are received. Messages are not deleted when they are read but retained with some configurable SLA (say a few days or a week). This allows usage in situations where the consumer of data may need to reload data. It also makes it possible to support space-efficient publish-subscribe as there is a single shared log no matter how many consumers; in traditional messaging systems there is usually a queue per consumer, so adding a consumer doubles your data size. This makes Kafka a good fit for things outside the bounds of normal messaging systems such as acting as a pipeline for offline data systems such as Hadoop. These offline systems may load only at intervals as part of a periodic ETL cycle, or may go down for several hours for maintenance, during which time Kafka is able to buffer even TBs of unconsumed data if needed.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Kafka also replicates its logs over multiple servers for fault-tolerance. One important architectural aspect of our&nbsp;<a href="http://kafka.apache.org/documentation.html#replication" style="color: #0077b5; text-decoration: none;">replication implementation</a>, in contrast to other messaging systems, is that replication is not an exotic bolt-on that requires complex configuration, only to be used in very specialized cases. Instead replication is assumed to be the default: we treat un-replicated data as a special case where the replication factor happens to be one.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Producers get an acknowledgement back when they publish a message containing the record's offset. The first record published to a partition is given the offset 0, the second record 1, and so on in an ever-increasing sequence. Consumers consume data from a position specified by an offset, and they save their position in a log by committing periodically: saving this offset in case that consumer instance crashes and another instance needs to resume from it's position.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Okay, hopefully that all made sense (if not, you can read a more complete introduction to Kafka&nbsp;<a href="http://kafka.apache.org/documentation.html" style="color: #0077b5; text-decoration: none;">here</a>).</p><h2>This Benchmark</h2><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">This test is against trunk, as I made some improvements to the performance tests for this benchmark. But nothing too substantial has changed since the last full release, so you should see similar results with&nbsp;<a href="http://kafka.apache.org/downloads.html" style="color: #0077b5; text-decoration: none;">0.8.1</a>. I am also using our newly re-written&nbsp;<a href="http://bit.ly/1l6ZPjl" style="color: #0077b5; text-decoration: none;">Java producer</a>, which offers much improved throughput over the previous producer client.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">I've followed the basic template of this very nice&nbsp;<a href="http://www.rabbitmq.com/blog/2012/04/25/rabbitmq-performance-measurements-part-2/" style="color: #0077b5; text-decoration: none;">RabbitMQ benchmark</a>, but I covered scenarios and options that were more relevant to Kafka.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">One quick philosophical note on this benchmark. For benchmarks that are going to be publicly reported, I like to follow a style I call "lazy benchmarking". When you work on a system, you generally have the know-how to tune it to perfection for any particular use case. This leads to a kind of benchmarketing where you heavily tune your configuration to your benchmark or worse have a different tuning for each scenario you test. I think the real test of a system is not how it performs when perfectly tuned, but rather how it performs "off the shelf". This is particularly true for systems that run in a multi-tenant setup with dozens or hundreds of use cases where tuning for each use case would be not only impractical but impossible. As a result, I have pretty much stuck with default settings, both for the server and the clients. I will point out areas where I suspect the result could be improved with a little tuning, but I have tried to resist the temptation to do any fiddling myself to improve the results.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">I have posted&nbsp;<a href="https://gist.github.com/jkreps/c7ddb4041ef62a900e6c" style="color: #0077b5; text-decoration: none;">my exact configurations and commands</a>, so it should be possible to replicate results on your own gear if you are interested.</p><h2>The Setup</h2><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">For these tests, I had six machines each has the following specs</p><ul style="margin: 20px 0px 16px; padding: 0px; list-style: square inside; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;"><li style="margin: 0px 0px 10px 30px; padding: 0px 0px 0px 3px; list-style-position: outside; list-style-type: disc;">Intel Xeon 2.5 GHz processor with six cores</li><li style="margin: 0px 0px 10px 30px; padding: 0px 0px 0px 3px; list-style-position: outside; list-style-type: disc;">Six 7200 RPM SATA drives</li><li style="margin: 0px 0px 10px 30px; padding: 0px 0px 0px 3px; list-style-position: outside; list-style-type: disc;">32GB of RAM</li><li style="margin: 0px 0px 10px 30px; padding: 0px 0px 0px 3px; list-style-position: outside; list-style-type: disc;">1Gb Ethernet</li></ul><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">The Kafka cluster is set up on three of the machines. The six drives are directly mounted with no RAID (JBOD style). The remaining three machines I use for Zookeeper and for generating load.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">A three machine cluster isn't very big, but since we will only be testing up to a replication factor of three, it is all we need. As should be obvious, we can always add more partitions and spread data onto more machines to scale our cluster horizontally.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">This hardware is actually not LinkedIn's normal Kafka hardware. Our Kafka machines are more closely tuned to running Kafka, but are less in the spirit of "off-the-shelf" I was aiming for with these tests. Instead, I borrowed these from one of our Hadoop clusters, which runs on probably the cheapest gear of any of our persistent systems. Hadoop usage patterns are pretty similar to Kafka's, so this is a reasonable thing to do.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Okay, without further ado, the results!</p><h2>Producer Throughput</h2><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">These tests will stress the throughput of the producer. No consumers are run during these tests, so all messages are persisted but not read (we'll test cases with both producer and consumer in a bit). Since we have recently rewritten our producer, I am testing this new code.</p><h3>Single producer thread, no replication</h3><table style="border-collapse: collapse; border-spacing: 0px; font-size: 11px;"><tbody><tr><td style="margin: 0px; padding: 2px 5px;">821,557 records/sec</td></tr><tr><td style="margin: 0px; padding: 2px 5px;">(78.3 MB/sec)</td></tr></tbody></table><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">For this first test I create a topic with six partitions and no replication. Then I produce 50 million small (100 byte) records as quickly as possible from a single thread.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">The reason for focusing on small records in these tests is that it is the harder case for a messaging system (generally). It is easy to get good throughput in MB/sec if the messages are large, but much harder to get good throughput when the messages are small, as the overhead of processing each message dominates.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Throughout this benchmark, when I am reporting MB/sec, I am reporting just the value size of the record times the request per second, none of the other overhead of the request is included. So the actually network usage is higher than what is reported. For example with a 100 byte message we would also transmit about 22 bytes of overhead per message (for an optional key, size delimiting, a message CRC, the record offset, and attributes flag), as well as some overhead for the request (including the topic, partition, required acknowledgements, etc). This makes it a little harder to see where we hit the limits of the NIC, but this seems a little more reasonable then including our own overhead bytes in throughput numbers. So, in the above result, we are likely saturating the 1 gigabit NIC on the client machine.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">One immediate observation is that the raw numbers here are much higher than people expect, especially for a persistent storage system. If you are used to random-access data systems, like a database or key-value store, you will generally expect maximum throughput around 5,000 to 50,000 queries-per-second, as this is close to the speed that a good RPC layer can do remote requests. We exceed this due to two key design principles:</p><ol style="margin: 20px 0px 16px; padding: 0px; list-style: decimal inside; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;"><li style="margin: 0px 0px 10px 30px; padding: 0px 0px 0px 3px; list-style-position: outside; list-style-type: decimal;">We work hard to ensure we do linear disk I/O. The six cheap disks these servers have gives an aggregate throughput of 822 MB/sec of linear disk I/O. This is actually well beyond what we can make use of with only a 1 gigabit network card. Many messaging systems treat persistence as an expensive add-on that decimates performance and should be used only sparingly, but this is because they are not able to do linear I/O.</li><li style="margin: 0px 0px 10px 30px; padding: 0px 0px 0px 3px; list-style-position: outside; list-style-type: decimal;">At each stage we work on batching together small bits of data into larger network and disk I/O operations. For example, in the new producer we use a "group commit"-like mechanism to ensure that any record sends initiated while another I/O is in progress get grouped together. For more on understanding the importance of batching, check out this presentation by David Patterson on why&nbsp;<a href="http://www.ll.mit.edu/HPEC/agendas/proc04/invited/patterson_keynote.pdf" style="color: #0077b5; text-decoration: none;">"Latency Lags Bandwidth"</a>.</li></ol><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">If you are interested in the details you can read a little more about this in our&nbsp;<a href="http://kafka.apache.org/documentation.html#design" style="color: #0077b5; text-decoration: none;">design documents</a>.</p><h3>Single producer thread, 3x asynchronous replication</h3><table style="border-collapse: collapse; border-spacing: 0px; font-size: 11px;"><tbody><tr><td style="margin: 0px; padding: 2px 5px;">786,980 records/sec</td></tr><tr><td style="margin: 0px; padding: 2px 5px;">(75.1 MB/sec)</td></tr></tbody></table><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">This test is exactly the same as the previous one except that now each partition has three replicas (so the total data written to network or disk is three times higher). Each server is doing both writes from the producer for the partitions for which it is a master, as well as fetching and writing data for the partitions for which it is a follower.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Replication in this test is asynchronous. That is, the server acknowledges the write as soon as it has written it to its local log without waiting for the other replicas to also acknowledge it. This means, if the master were to crash, it would likely lose the last few messages that had been written but not yet replicated. This makes the message acknowledgement latency a little better at the cost of some risk in the case of server failure.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">The key take away I would like people to have from this is that replication can be fast. The total cluster write capacity is, of course, 3x less with 3x replication (since each write is done three times), but the throughput is still quite good per client. High performance replication comes in large part from the efficiency of our consumer (the replicas are really nothing more than a specialized consumer) which I will discuss in the consumer section.</p><h3>Single producer thread, 3x synchronous replication</h3><table style="border-collapse: collapse; border-spacing: 0px; font-size: 11px;"><tbody><tr><td style="margin: 0px; padding: 2px 5px;">421,823 records/sec</td></tr><tr><td style="margin: 0px; padding: 2px 5px;">(40.2 MB/sec)</td></tr></tbody></table><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">This test is the same as above except that now the master for a partition waits for acknowledgement from the full set of in-sync replicas before acknowledging back to the producer. In this mode, we guarantee that messages will not be lost as long as one in-sync replica remains.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Synchronous replication in Kafka is not fundamentally very different from asynchronous replication. The leader for a partition always tracks the progress of the follower replicas to monitor their liveness, and we never give out messages to consumers until they are fully acknowledged by replicas. With synchronous replication we just wait to respond to the producer request until the followers have replicated it.</p>This additional latency does seem to affect our throughput. Since the code path on the server is very similar, we could probably ameliorate this impact by tuning the batching to be a bit more aggressive and allowing the client to buffer more outstanding requests. However, in spirit of avoiding special case tuning, I have avoided this.<h3>Three producers, 3x async replication</h3><table style="border-collapse: collapse; border-spacing: 0px; font-size: 11px;"><tbody><tr><td style="margin: 0px; padding: 2px 5px;">2,024,032 records/sec</td></tr><tr><td style="margin: 0px; padding: 2px 5px;">(193.0 MB/sec)</td></tr></tbody></table><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Our single producer process is clearly not stressing our three node cluster. To add a little more load, I'll now repeat the previous async replication test, but now use three producer load generators running on three different machines (running more processes on the same machine won't help as we are saturating the NIC). Then we can look at the aggregate throughput across these three producers to get a better feel for the cluster's aggregate capacity.</p><h2>Producer Throughput Versus Stored Data</h2><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">One of the hidden dangers of many messaging systems is that they work well only as long as the data they retain fits in memory. Their throughput falls by an order of magnitude (or more) when data backs up and isn't consumed (and hence needs to be stored on disk). This means things may be running fine as long as your consumers keep up and the queue is empty, but as soon as they lag, the whole messaging layer backs up with unconsumed data. The backup causes data to go to disk which in turns causes performance to drop to a rate that means messaging system can no longer keep up with incoming data and either backs up or falls over. This is pretty terrible, as in many cases the whole purpose of the queue was to handle such a case gracefully.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Since Kafka always persists messages the performance is O(1) with respect to unconsumed data volume.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">To test this experimentally, let's run our throughput test over an extended period of time and graph the results as the stored dataset grows:</p><div style="margin: 0px; padding: 0px;"><img src="https://content.linkedin.com/content/dam/engineering/en-us/blog/migrated/throughput_vs_size_0.png" style="border: 0px; max-width: 100%; height: auto; display: block; margin: 0px auto; width: 600px;"  alt="" /></div><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">This graph actually does show some variance in performance, but no impact due to data size: we perform just as well after writing a TB of data, as we do for the first few hundred MBs.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">The variance seems to be due to Linux's I/O management facilities that batch data and then flush it periodically. This is something we have tuned for a little better on our production Kafka setup. Some notes on tuning I/O are available&nbsp;<a href="http://kafka.apache.org/documentation.html#hwandos" style="color: #0077b5; text-decoration: none;">here</a>.</p><h2>Consumer Throughput</h2><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Okay now let's turn our attention to consumer throughput.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Note that the replication factor will not effect the outcome of this test as the consumer only reads from one replica regardless of the replication factor. Likewise, the acknowledgement level of the producer also doesn't matter as the consumer only ever reads fully acknowledged messages, (even if the producer doesn't wait for full acknowledgement). This is to ensure that any message the consumer sees will always be present after a leadership handoff (if the current leader fails).</p><h3>Single Consumer</h3><table style="border-collapse: collapse; border-spacing: 0px; font-size: 11px;"><tbody><tr><td style="margin: 0px; padding: 2px 5px;">940,521 records/sec</td></tr><tr><td style="margin: 0px; padding: 2px 5px;">(89.7 MB/sec)</td></tr></tbody></table><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">For the first test, we will consume 50 million messages in a single thread from our 6 partition 3x replicated topic.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Kafka's consumer is very efficient. It works by fetching chunks of log directly from the filesystem. It uses the&nbsp;<a href="http://www.ibm.com/developerworks/library/j-zerocopy/" style="color: #0077b5; text-decoration: none;">sendfile API</a>&nbsp;to transfer this directly through the operating system without the overhead of copying this data through the application. This test actually starts at the beginning of the log, so it is doing real read I/O. In a production setting, though, the consumer reads almost exclusively out of the OS pagecache, since it is reading data that was just written by some producer (so it is still cached). In fact, if you run I/O stat on a production server you actually see that there are no physical reads at all even though a great deal of data is being consumed.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Making consumers cheap is important for what we want Kafka to do. For one thing, the replicas are themselves consumers, so making the consumer cheap makes replication cheap. In addition, this makes handling out data an inexpensive operation, and hence not something we need to tightly control for scalability reasons.</p><h3>Three Consumers</h3><table style="border-collapse: collapse; border-spacing: 0px; font-size: 11px;"><tbody><tr><td style="margin: 0px; padding: 2px 5px;">2,615,968 records/sec</td></tr><tr><td style="margin: 0px; padding: 2px 5px;">(249.5 MB/sec)</td></tr></tbody></table><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Let's repeat the same test, but run three parallel consumer processes, each on a different machine, and all consuming the same topic.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">As expected, we see near linear scaling (not surprising because consumption in our model is so simple).</p><h3>Producer and Consumer</h3><table style="border-collapse: collapse; border-spacing: 0px; font-size: 11px;"><tbody><tr><td style="margin: 0px; padding: 2px 5px;">795,064 records/sec</td></tr><tr><td style="margin: 0px; padding: 2px 5px;">(75.8 MB/sec)</td></tr></tbody></table><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">The above tests covered just the producer and the consumer running in isolation. Now let's do the natural thing and run them together. Actually, we have technically already been doing this, since our replication works by having the servers themselves act as consumers.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">All the same, let's run the test. For this test we'll run one producer and one consumer on a six partition 3x replicated topic that begins empty. The producer is again using async replication. The throughput reported is the consumer throughput (which is, obviously, an upper bound on the producer throughput).</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">As we would expect, the results we get are basically the same as we saw in the producer only case&#8212;the consumer is fairly cheap.</p><h2>Effect of Message Size</h2><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">I have mostly shown performance on small 100 byte messages. Smaller messages are the harder problem for a messaging system as they magnify the overhead of the bookkeeping the system does. We can show this by just graphing throughput in both records/second and MB/second as we vary the record size.</p><div style="margin: 0px; padding: 0px;"><img src="https://content.linkedin.com/content/dam/engineering/en-us/blog/migrated/size_vs_record_throughput.png" style="border: 0px; max-width: 100%; height: auto; display: block; margin: 0px auto; width: 500px;"  alt="" /></div>So, as we would expect, this graph shows that the raw count of records we can send per second decreases as the records get bigger. But if we look at MB/second, we see that the total byte throughput of real user data increases as messages get bigger:<div style="margin: 0px; padding: 0px;"><img src="https://content.linkedin.com/content/dam/engineering/en-us/blog/migrated/size_vs_mb_throughput.png" style="border: 0px; max-width: 100%; height: auto; display: block; margin: 0px auto; width: 500px;"  alt="" /></div><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">We can see that with the 10 byte messages we are actually CPU bound by just acquiring the lock and enqueuing the message for sending&#8212;we are not able to actually max out the network. However, starting with 100 bytes, we are actually seeing network saturation (though the MB/sec continues to increase as our fixed-size bookkeeping bytes become an increasingly small percentage of the total bytes sent).</p><h2>End-to-end Latency</h2><table style="border-collapse: collapse; border-spacing: 0px; font-size: 11px;"><tbody><tr><td style="margin: 0px; padding: 2px 5px;">2 ms (median)</td></tr><tr><td style="margin: 0px; padding: 2px 5px;">3 ms (99th percentile)</td></tr><tr><td style="margin: 0px; padding: 2px 5px;">14 ms (99.9th percentile)</td></tr></tbody></table><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">We have talked a lot about throughput, but what is the latency of message delivery? That is, how long does it take a message we send to be delivered to the consumer? For this test, we will create producer and consumer and repeatedly time how long it takes for a producer to send a message to the kafka cluster and then be received by our consumer.</p><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">Note that, Kafka only gives out messages to consumers when they are acknowledged by the full in-sync set of replicas. So this test will give the same results regardless of whether we use sync or async replication, as that setting only affects the acknowledgement to the producer.</p><h2>Replicating this test</h2><p style="margin: 20px 0px 16px; padding: 0px; color: #888888; font-family: Helvetica, Arial, sans-serif; font-size: 16px; line-height: 24px;">If you want to try out these benchmarks on your own machines, you can. As I said, I mostly just used our pre-packaged performance testing tools that ship with Kafka and mostly stuck with the default configs both for the server and for the clients. However, you can see more details of the configuration and commands&nbsp;<a href="https://gist.github.com/jkreps/c7ddb4041ef62a900e6c" style="color: #0077b5; text-decoration: none;">here</a>.</p></div></div></div><section style="font-family: avenir-regular, arial, sans-serif; color: #000000; position: relative; margin-top: 20px; font-size: 15px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 22px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 1; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: #ffffff;"><br /></section></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/430663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-05-26 13:53 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/05/26/430663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Kafka 高性能吞吐揭秘</title><link>http://www.blogjava.net/wangxinsh55/archive/2016/05/26/430662.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Thu, 26 May 2016 05:52:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/05/26/430662.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/430662.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/05/26/430662.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/430662.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/430662.html</trackback:ping><description><![CDATA[<div>http://umeng.baijia.baidu.com/article/227913</div><br /><div><div id="page" style="margin: 0px 0px 60px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;"><div style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; letter-spacing: 0.5px;"><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">本文将针对Kafka性能方面进行简单分析，首先简单介绍一下Kafka的架构和涉及到的名词：</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">1.&nbsp;&nbsp;&nbsp; Topic：用于划分Message的逻辑概念，一个Topic可以分布在多个Broker上。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">2.&nbsp;&nbsp;&nbsp; Partition：是Kafka中横向扩展和一切并行化的基础，每个Topic都至少被切分为1个Partition。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">3.&nbsp;&nbsp;&nbsp; Offset：消息在Partition中的编号，编号顺序不跨Partition。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">4.&nbsp;&nbsp;&nbsp; Consumer：用于从Broker中取出/消费Message。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">5.&nbsp;&nbsp;&nbsp; Producer：用于往Broker中发送/生产Message。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">6.&nbsp;&nbsp;&nbsp; Replication：Kafka支持以Partition为单位对Message进行冗余备份，每个Partition都可以配置至少1个Replication(当仅1个Replication时即仅该Partition本身)。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">7.&nbsp;&nbsp;&nbsp; Leader：每个Replication集合中的Partition都会选出一个唯一的Leader，所有的读写请求都由Leader处理。其他Replicas从Leader处把数据更新同步到本地，过程类似大家熟悉的MySQL中的Binlog同步。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">8.&nbsp;&nbsp;&nbsp; Broker：Kafka中使用Broker来接受Producer和Consumer的请求，并把Message持久化到本地磁盘。每个Cluster当中会选举出一个Broker来担任Controller，负责处理Partition的Leader选举，协调Partition迁移等工作。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">9.&nbsp;&nbsp;&nbsp; ISR(In-Sync Replica)：是Replicas的一个子集，表示目前Alive且与Leader能够&#8220;Catch-up&#8221;的Replicas集合。由于读写都是首先落到Leader上，所以一般来说通过同步机制从Leader上拉取数据的Replica都会和Leader有一些延迟(包括了延迟时间和延迟条数两个维度)，任意一个超过阈值都会把该Replica踢出ISR。每个Partition都有它自己独立的ISR。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">以上几乎是我们在使用Kafka的过程中可能遇到的所有名词，同时也无一不是最核心的概念或组件，感觉到从设计本身来说，Kafka还是足够简洁的。这次本文围绕Kafka优异的吞吐性能，逐个介绍一下其设计与实现当中所使用的各项&#8220;黑科技&#8221;。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;"><strong style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: 800; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;">Broker</strong></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">不同于Redis和MemcacheQ等内存消息队列，Kafka的设计是把所有的Message都要写入速度低容量大的硬盘，以此来换取更强的存储能力。实际上，Kafka使用硬盘并没有带来过多的性能损失，&#8220;规规矩矩&#8221;的抄了一条&#8220;近道&#8221;。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">首先，说&#8220;规规矩矩&#8221;是因为Kafka在磁盘上只做Sequence I/O，由于消息系统读写的特殊性，这并不存在什么问题。关于磁盘I/O的性能，引用一组Kafka官方给出的测试数据(Raid-5，7200rpm)：</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">Sequence I/O: 600MB/s</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">Random I/O: 100KB/s</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">所以通过只做Sequence I/O的限制，规避了磁盘访问速度低下对性能可能造成的影响。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">接下来我们再聊一聊Kafka是如何&#8220;抄近道的&#8221;。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">首先，Kafka重度依赖底层操作系统提供的PageCache功能。当上层有写操作时，操作系统只是将数据写入PageCache，同时标记Page属性为Dirty。当读操作发生时，先从PageCache中查找，如果发生缺页才进行磁盘调度，最终返回需要的数据。实际上PageCache是把尽可能多的空闲内存都当做了磁盘缓存来使用。同时如果有其他进程申请内存，回收PageCache的代价又很小，所以现代的OS都支持PageCache。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">使用PageCache功能同时可以避免在JVM内部缓存数据，JVM为我们提供了强大的GC能力，同时也引入了一些问题不适用与Kafka的设计。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果在Heap内管理缓存，JVM的GC线程会频繁扫描Heap空间，带来不必要的开销。如果Heap过大，执行一次Full GC对系统的可用性来说将是极大的挑战。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所有在在JVM内的对象都不免带有一个Object Overhead(千万不可小视)，内存的有效空间利用率会因此降低。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所有的In-Process Cache在OS中都有一份同样的PageCache。所以通过将缓存只放在PageCache，可以至少让可用缓存空间翻倍。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果Kafka重启，所有的In-Process Cache都会失效，而OS管理的PageCache依然可以继续使用。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">PageCache还只是第一步，Kafka为了进一步的优化性能还采用了Sendfile技术。在解释Sendfile之前，首先介绍一下传统的网络I/O操作流程，大体上分为以下4步。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">1.&nbsp;&nbsp;&nbsp; OS 从硬盘把数据读到内核区的PageCache。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">2.&nbsp;&nbsp;&nbsp; 用户进程把数据从内核区Copy到用户区。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">3.&nbsp;&nbsp;&nbsp; 然后用户进程再把数据写入到Socket，数据流入内核区的Socket Buffer上。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">4.&nbsp;&nbsp;&nbsp; OS 再把数据从Buffer中Copy到网卡的Buffer上，这样完成一次发送。</p><p style="margin: 0px 0px 20px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;"><img src="http://d.hiphotos.baidu.com/news/w%3D638/sign=1cbe97e976cf3bc7e800ceefe901babd/5366d0160924ab18ec9c8ad333fae6cd7a890b4f.jpg" style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; display: inline-block; max-width: 680px;"  alt="" /></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">整个过程共经历两次Context Switch，四次System Call。同一份数据在内核Buffer与用户Buffer之间重复拷贝，效率低下。其中2、3两步没有必要，完全可以直接在内核区完成数据拷贝。这也正是Sendfile所解决的问题，经过Sendfile优化后，整个I/O过程就变成了下面这个样子。</p><p style="margin: 0px 0px 20px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;"><img src="http://h.hiphotos.baidu.com/news/w%3D638/sign=a1dfd456bf014a90813e45be91753971/1c950a7b02087bf4b5193c0df4d3572c10dfcf59.jpg" style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; display: inline-block; max-width: 680px;"  alt="" /></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">通过以上的介绍不难看出，Kafka的设计初衷是尽一切努力在内存中完成数据交换，无论是对外作为一整个消息系统，或是内部同底层操作系统的交互。如果Producer和Consumer之间生产和消费进度上配合得当，完全可以实现数据交换零I/O。这也就是我为什么说Kafka使用&#8220;硬盘&#8221;并没有带来过多性能损失的原因。下面是我在生产环境中采到的一些指标。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">(20 Brokers, 75 Partitions per Broker, 110k msg/s)</p><p style="margin: 0px 0px 20px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;"><img src="http://e.hiphotos.baidu.com/news/w%3D638/sign=64b42cda0af3d7ca0cf63c75ca1ebe3c/3b87e950352ac65cecae0d97fdf2b21192138aaf.jpg" style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; display: inline-block; max-width: 680px;"  alt="" /></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">此时的集群只有写，没有读操作。10M/s左右的Send的流量是Partition之间进行Replicate而产生的。从recv和writ的速率比较可以看出，写盘是使用Asynchronous+Batch的方式，底层OS可能还会进行磁盘写顺序优化。而在有Read Request进来的时候分为两种情况，第一种是内存中完成数据交换。</p><p style="margin: 0px 0px 20px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;"><img src="http://e.hiphotos.baidu.com/news/w%3D638/sign=1615143928738bd4c421b132998a876c/f603918fa0ec08fa9d9c78435fee3d6d54fbdab2.jpg" style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; display: inline-block; max-width: 680px;"  alt="" /></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">Send流量从平均10M/s增加到了到平均60M/s，而磁盘Read只有不超过50KB/s。PageCache降低磁盘I/O效果非常明显。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">接下来是读一些收到了一段时间，已经从内存中被换出刷写到磁盘上的老数据。</p><p style="margin: 0px 0px 20px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;"><img src="http://f.hiphotos.baidu.com/news/w%3D638/sign=00fc6907d339b6004dce0cb4d1513526/2fdda3cc7cd98d1014db66d5273fb80e7aec90c2.jpg" style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; display: inline-block; max-width: 680px;"  alt="" /></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">其他指标还是老样子，而磁盘Read已经飚高到40+MB/s。此时全部的数据都已经是走硬盘了(对硬盘的顺序读取OS层会进行Prefill PageCache的优化)。依然没有任何性能问题。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;"><strong style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: 800; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;">Tips</strong></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">1.&nbsp;&nbsp;&nbsp; Kafka官方并不建议通过Broker端的log.flush.interval.messages和log.flush.interval.ms来强制写盘，认为数据的可靠性应该通过Replica来保证，而强制Flush数据到磁盘会对整体性能产生影响。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">2.&nbsp;&nbsp;&nbsp; 可以通过调整/proc/sys/vm/dirty_background_ratio和/proc/sys/vm/dirty_ratio来调优性能。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">a.&nbsp;&nbsp;&nbsp; 脏页率超过第一个指标会启动pdflush开始Flush Dirty PageCache。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">b.&nbsp;&nbsp;&nbsp; 脏页率超过第二个指标会阻塞所有的写操作来进行Flush。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">c.&nbsp;&nbsp;&nbsp; 根据不同的业务需求可以适当的降低dirty_background_ratio和提高dirty_ratio。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;"><strong style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: 800; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;">Partition</strong></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">Partition是Kafka可以很好的横向扩展和提供高并发处理以及实现Replication的基础。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">扩展性方面。首先，Kafka允许Partition在集群内的Broker之间任意移动，以此来均衡可能存在的数据倾斜问题。其次，Partition支持自定义的分区算法，例如可以将同一个Key的所有消息都路由到同一个Partition上去。 同时Leader也可以在In-Sync的Replica中迁移。由于针对某一个Partition的所有读写请求都是只由Leader来处理，所以Kafka会尽量把Leader均匀的分散到集群的各个节点上，以免造成网络流量过于集中。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">并发方面。任意Partition在某一个时刻只能被一个Consumer Group内的一个Consumer消费(反过来一个Consumer则可以同时消费多个Partition)，Kafka非常简洁的Offset机制最小化了Broker和Consumer之间的交互，这使Kafka并不会像同类其他消息队列一样，随着下游Consumer数目的增加而成比例的降低性能。此外，如果多个Consumer恰巧都是消费时间序上很相近的数据，可以达到很高的PageCache命中率，因而Kafka可以非常高效的支持高并发读操作，实践中基本可以达到单机网卡上限。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">不过，Partition的数量并不是越多越好，Partition的数量越多，平均到每一个Broker上的数量也就越多。考虑到Broker宕机(Network Failure, Full GC)的情况下，需要由Controller来为所有宕机的Broker上的所有Partition重新选举Leader，假设每个Partition的选举消耗10ms，如果Broker上有500个Partition，那么在进行选举的5s的时间里，对上述Partition的读写操作都会触发LeaderNotAvailableException。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">再进一步，如果挂掉的Broker是整个集群的Controller，那么首先要进行的是重新任命一个Broker作为Controller。新任命的Controller要从Zookeeper上获取所有Partition的Meta信息，获取每个信息大概3-5ms，那么如果有10000个Partition这个时间就会达到30s-50s。而且不要忘记这只是重新启动一个Controller花费的时间，在这基础上还要再加上前面说的选举Leader的时间 -_-!!!!!!</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">此外，在Broker端，对Producer和Consumer都使用了Buffer机制。其中Buffer的大小是统一配置的，数量则与Partition个数相同。如果Partition个数过多，会导致Producer和Consumer的Buffer内存占用过大。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;"><strong style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: 800; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;">Tips</strong></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">1.&nbsp;&nbsp;&nbsp; Partition的数量尽量提前预分配，虽然可以在后期动态增加Partition，但是会冒着可能破坏Message Key和Partition之间对应关系的风险。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">2.&nbsp;&nbsp;&nbsp; Replica的数量不要过多，如果条件允许尽量把Replica集合内的Partition分别调整到不同的Rack。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">3.&nbsp;&nbsp;&nbsp; 尽一切努力保证每次停Broker时都可以Clean Shutdown，否则问题就不仅仅是恢复服务所需时间长，还可能出现数据损坏或其他很诡异的问题。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;"><strong style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: 800; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;">Producer</strong></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">Kafka的研发团队表示在0.8版本里用Java重写了整个Producer，据说性能有了很大提升。我还没有亲自对比试用过，这里就不做数据对比了。本文结尾的扩展阅读里提到了一套我认为比较好的对照组，有兴趣的同学可以尝试一下。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">其实在Producer端的优化大部分消息系统采取的方式都比较单一，无非也就化零为整、同步变异步这么几种。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">Kafka系统默认支持MessageSet，把多条Message自动地打成一个Group后发送出去，均摊后拉低了每次通信的RTT。而且在组织MessageSet的同时，还可以把数据重新排序，从爆发流式的随机写入优化成较为平稳的线性写入。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">此外，还要着重介绍的一点是，Producer支持End-to-End的压缩。数据在本地压缩后放到网络上传输，在Broker一般不解压(除非指定要Deep-Iteration)，直至消息被Consume之后在客户端解压。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">当然用户也可以选择自己在应用层上做压缩和解压的工作(毕竟Kafka目前支持的压缩算法有限，只有GZIP和Snappy)，不过这样做反而会意外的降低效率！！！！ Kafka的End-to-End压缩与MessageSet配合在一起工作效果最佳，上面的做法直接割裂了两者间联系。至于道理其实很简单，压缩算法中一条基本的原理&#8220;重复的数据量越多，压缩比越高&#8221;。无关于消息体的内容，无关于消息体的数量，大多数情况下输入数据量大一些会取得更好的压缩比。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">不过Kafka采用MessageSet也导致在可用性上一定程度的妥协。每次发送数据时，Producer都是send()之后就认为已经发送出去了，但其实大多数情况下消息还在内存的MessageSet当中，尚未发送到网络，这时候如果Producer挂掉，那就会出现丢数据的情况。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">为了解决这个问题，Kafka在0.8版本的设计借鉴了网络当中的ack机制。如果对性能要求较高，又能在一定程度上允许Message的丢失，那就可以设置request.required.acks=0 来关闭ack，以全速发送。如果需要对发送的消息进行确认，就需要设置request.required.acks为1或-1，那么1和-1又有什么区别呢？这里又要提到前面聊的有关Replica数量问题。如果配置为1，表示消息只需要被Leader接收并确认即可，其他的Replica可以进行异步拉取无需立即进行确认，在保证可靠性的同时又不会把效率拉得很低。如果设置为-1，表示消息要Commit到该Partition的ISR集合中的所有Replica后，才可以返回ack，消息的发送会更安全，而整个过程的延迟会随着Replica的数量正比增长，这里就需要根据不同的需求做相应的优化。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;"><strong style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: 800; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;">Tips</strong></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">1.&nbsp;&nbsp;&nbsp; Producer的线程不要配置过多，尤其是在Mirror或者Migration中使用的时候，会加剧目标集群Partition消息乱序的情况(如果你的应用场景对消息顺序很敏感的话)。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">2.&nbsp;&nbsp;&nbsp; 0.8版本的request.required.acks默认是0(同0.7)。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;"><strong style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: 800; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;">Consumer</strong></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">Consumer端的设计大体上还算是比较常规的。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过Consumer Group，可以支持生产者消费者和队列访问两种模式。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Consumer API分为High level和Low level两种。前一种重度依赖Zookeeper，所以性能差一些且不自由，但是超省心。第二种不依赖Zookeeper服务，无论从自由度和性能上都有更好的表现，但是所有的异常(Leader迁移、Offset越界、Broker宕机等)和Offset的维护都需要自行处理。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">&#183;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 大家可以关注下不日发布的0.9 Release。开发人员又用Java重写了一套Consumer。把两套API合并在一起，同时去掉了对Zookeeper的依赖。据说性能有大幅度提升哦~~</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;"><strong style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: 800; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;">Tips</strong></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">强烈推荐使用Low level API，虽然繁琐一些，但是目前只有这个API可以对Error数据进行自定义处理，尤其是处理Broker异常或由于Unclean Shutdown导致的Corrupted Data时，否则无法Skip只能等着&#8220;坏消息&#8221;在Broker上被Rotate掉，在此期间该Replica将会一直处于不可用状态。</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;"><strong style="margin: 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: 800; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased;">扩展阅读</strong></p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">Sendfile: https://www.ibm.com/developerworks/cn/java/j-zerocopy/</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">So what&#8217;s wrong with 1975 programming: https://www.varnish-cache.org/trac/wiki/ArchitectNotes</p><p style="margin: 25px 0px; padding: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: 14px; line-height: 24px; font-family: inherit; vertical-align: baseline; -webkit-font-smoothing: antialiased; text-indent: 28px; color: #333333;">Benchmarking: https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines</p></div></div><br /> </div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/430662.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-05-26 13:52 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/05/26/430662.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA实现gif图片缩放与剪切功能</title><link>http://www.blogjava.net/wangxinsh55/archive/2016/05/23/430621.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 23 May 2016 06:40:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/05/23/430621.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/430621.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/05/23/430621.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/430621.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/430621.html</trackback:ping><description><![CDATA[<div>http://www.open-open.com/lib/view/open1394859355853.html</div><br /><div>package com.pinker.util;<br />import java.awt.Color;<br />import java.awt.Graphics;<br />import java.awt.Image;<br />import java.awt.image.BufferedImage;<br />import java.io.File;<br />import java.io.IOException;<br />import java.util.Arrays;<br />import java.util.Iterator;<br /><br />import javax.imageio.IIOImage;<br />import javax.imageio.ImageIO;<br />import javax.imageio.ImageReader;<br />import javax.imageio.ImageWriter;<br />import javax.imageio.stream.ImageInputStream;<br />import javax.imageio.stream.ImageOutputStream;<br />&nbsp;<br />/**<br />&nbsp;* 图像裁剪以及压缩处理工具类<br />&nbsp;*<br />&nbsp;* 主要针对动态的GIF格式图片裁剪之后，只出现一帧动态效果的现象提供解决方案<br />&nbsp;*<br />&nbsp;* 提供依赖三方包解决方案（针对GIF格式数据特征一一解析，进行编码解码操作）<br />&nbsp;* 提供基于JDK Image I/O 的解决方案(JDK探索失败)<br />&nbsp;*/<br />public class ImageUtil2 {<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; public enum IMAGE_FORMAT{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BMP("bmp"),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JPG("jpg"),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WBMP("wbmp"),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JPEG("jpeg"),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PNG("png"),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GIF("gif");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private String value;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IMAGE_FORMAT(String value){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.value = value;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public String getValue() {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return value;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void setValue(String value) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.value = value;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 获取图片格式<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param file&nbsp;&nbsp; 图片文件<br />&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp; 图片格式<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static String getImageFormatName(File file)throws IOException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String formatName = null;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageInputStream iis = ImageIO.createImageInputStream(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator&lt;ImageReader&gt; imageReader =&nbsp; ImageIO.getImageReaders(iis);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(imageReader.hasNext()){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageReader reader = imageReader.next();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; formatName = reader.getFormatName();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return formatName;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /*************************&nbsp; 基于三方包解决方案&nbsp;&nbsp;&nbsp; *****************************/<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 剪切图片<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param source&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 待剪切图片路径<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param targetPath&nbsp;&nbsp;&nbsp; 裁剪后保存路径（默认为源路径）<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 起始横坐标<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 起始纵坐标<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 剪切宽度<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param height&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 剪切高度&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * @returns&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 裁剪后保存路径（图片后缀根据图片本身类型生成）&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws IOException<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static String cutImage(String sourcePath , String targetPath , int x , int y , int width , int height) throws IOException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File file = new File(sourcePath);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!file.exists()) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IOException("not found the image：" + sourcePath);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(null == targetPath || targetPath.isEmpty()) targetPath = sourcePath;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String formatName = getImageFormatName(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(null == formatName) return targetPath;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; formatName = formatName.toLowerCase();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 防止图片后缀与图片本身类型不一致的情况<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String pathPrefix = getPathWithoutSuffix(targetPath);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; targetPath = pathPrefix + formatName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // GIF需要特殊处理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(IMAGE_FORMAT.GIF.getValue() == formatName){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GifDecoder decoder = new GifDecoder(); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int status = decoder.read(sourcePath); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (status != GifDecoder.STATUS_OK) { &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IOException("read image " + sourcePath + " error!"); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AnimatedGifEncoder encoder = new AnimatedGifEncoder();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.start(targetPath);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.setRepeat(decoder.getLoopCount()); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; decoder.getFrameCount(); i ++) { &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.setDelay(decoder.getDelay(i)); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage childImage = decoder.getFrame(i);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage image = childImage.getSubimage(x, y, width, height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.addFrame(image); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.finish();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }else{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage image = ImageIO.read(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; image = image.getSubimage(x, y, width, height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageIO.write(image, formatName, new File(targetPath));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //普通图片<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage image = ImageIO.read(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; image = image.getSubimage(x, y, width, height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageIO.write(image, formatName, new File(targetPath));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return targetPath;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 压缩图片<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param sourcePath&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 待压缩的图片路径<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param targetPath&nbsp;&nbsp;&nbsp; 压缩后图片路径（默认为初始路径）<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 压缩宽度<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param height&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 压缩高度<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * @returns&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 裁剪后保存路径（图片后缀根据图片本身类型生成）&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws IOException<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static String zoom(String sourcePath , String targetPath, int width , int height) throws IOException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File file = new File(sourcePath);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!file.exists()) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IOException("not found the image ：" + sourcePath);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(null == targetPath || targetPath.isEmpty()) targetPath = sourcePath;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String formatName = getImageFormatName(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(null == formatName) return targetPath;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; formatName = formatName.toLowerCase();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 防止图片后缀与图片本身类型不一致的情况<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String pathPrefix = getPathWithoutSuffix(targetPath);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; targetPath = pathPrefix + formatName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // GIF需要特殊处理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(IMAGE_FORMAT.GIF.getValue() == formatName){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GifDecoder decoder = new GifDecoder(); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int status = decoder.read(sourcePath); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (status != GifDecoder.STATUS_OK) { &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IOException("read image " + sourcePath + " error!"); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AnimatedGifEncoder encoder = new AnimatedGifEncoder();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.start(targetPath);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.setRepeat(decoder.getLoopCount()); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; decoder.getFrameCount(); i ++) { &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.setDelay(decoder.getDelay(i)); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage image = zoom(decoder.getFrame(i), width , height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.addFrame(image); &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; encoder.finish();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }else{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage image = ImageIO.read(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage zoomImage = zoom(image , width , height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageIO.write(zoomImage, formatName, new File(targetPath));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage image = ImageIO.read(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage zoomImage = zoom(image , width , height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageIO.write(zoomImage, formatName, new File(targetPath));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return targetPath;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /*********************** 基于JDK 解决方案&nbsp;&nbsp;&nbsp;&nbsp; ********************************/<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 读取图片<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param file 图片文件<br />&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp;&nbsp; 图片数据<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws IOException<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static BufferedImage[] readerImage(File file) throws IOException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage sourceImage = ImageIO.read(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage[] images = null;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageInputStream iis = ImageIO.createImageInputStream(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator&lt;ImageReader&gt; imageReaders = ImageIO.getImageReaders(iis);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(imageReaders.hasNext()){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageReader reader = imageReaders.next();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reader.setInput(iis);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int imageNumber = reader.getNumImages(true);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; images = new BufferedImage[imageNumber];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; imageNumber; i++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage image = reader.read(i);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(sourceImage.getWidth() &gt; image.getWidth() || sourceImage.getHeight() &gt; image.getHeight()){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; image = zoom(image, sourceImage.getWidth(), sourceImage.getHeight());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; images[i] = image;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; reader.dispose();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; iis.close();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return images;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 根据要求处理图片<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param images&nbsp;&nbsp;&nbsp; 图片数组<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 横向起始位置<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 纵向起始位置<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 宽度&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param height&nbsp;&nbsp;&nbsp; 宽度<br />&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 处理后的图片数组<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static BufferedImage[] processImage(BufferedImage[] images , int x , int y , int width , int height) throws Exception{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(null == images){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return images;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage[] oldImages = images;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; images = new BufferedImage[images.length];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; oldImages.length; i++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage image = oldImages[i];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; images[i] = image.getSubimage(x, y, width, height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return images;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 写入处理后的图片到file<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * 图片后缀根据图片格式生成<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param images&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 处理后的图片数据<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param formatName&nbsp;&nbsp;&nbsp;&nbsp; 图片格式<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param file&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 写入文件对象<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static void writerImage(BufferedImage[] images ,&nbsp; String formatName , File file) throws Exception{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Iterator&lt;ImageWriter&gt; imageWriters = ImageIO.getImageWritersByFormatName(formatName);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(imageWriters.hasNext()){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageWriter writer = imageWriters.next();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String fileName = file.getName();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int index = fileName.lastIndexOf(".");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(index &gt; 0){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fileName = fileName.substring(0, index + 1) + formatName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String pathPrefix = getFilePrefixPath(file.getPath());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File outFile = new File(pathPrefix + fileName);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageOutputStream ios = ImageIO.createImageOutputStream(outFile);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.setOutput(ios);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(writer.canWriteSequence()){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.prepareWriteSequence(null);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; images.length; i++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage childImage = images[i];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IIOImage image = new IIOImage(childImage, null , null);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.writeToSequence(image, null);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.endWriteSequence();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }else{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; images.length; i++) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.write(images[i]);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writer.dispose();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ios.close();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 剪切格式图片<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * 基于JDK Image I/O解决方案<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param sourceFile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 待剪切图片文件对象<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param destFile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 裁剪后保存文件对象<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 剪切横向起始位置<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 剪切纵向起始位置<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 剪切宽度&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param height&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 剪切宽度<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static void cutImage(File sourceFile , File destFile, int x , int y , int width , int height) throws Exception{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 读取图片信息<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage[] images = readerImage(sourceFile);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 处理图片<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; images = processImage(images, x, y, width, height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 获取文件后缀<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String formatName = getImageFormatName(sourceFile);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; destFile = new File(getPathWithoutSuffix(destFile.getPath()) + formatName);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 写入处理后的图片到文件<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writerImage(images, formatName , destFile);<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 获取系统支持的图片格式<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static void getOSSupportsStandardImageFormat(){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] readerFormatName = ImageIO.getReaderFormatNames();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] readerSuffixName = ImageIO.getReaderFileSuffixes();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] readerMIMEType = ImageIO.getReaderMIMETypes();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("========================= OS supports reader ========================");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("OS supports reader format name :&nbsp; " + Arrays.asList(readerFormatName));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("OS supports reader suffix name :&nbsp; " + Arrays.asList(readerSuffixName));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("OS supports reader MIME type :&nbsp; " + Arrays.asList(readerMIMEType));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] writerFormatName = ImageIO.getWriterFormatNames();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] writerSuffixName = ImageIO.getWriterFileSuffixes();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String[] writerMIMEType = ImageIO.getWriterMIMETypes();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("========================= OS supports writer ========================");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("OS supports writer format name :&nbsp; " + Arrays.asList(writerFormatName));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("OS supports writer suffix name :&nbsp; " + Arrays.asList(writerSuffixName));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("OS supports writer MIME type :&nbsp; " + Arrays.asList(writerMIMEType));<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 压缩图片<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param sourceImage&nbsp;&nbsp;&nbsp; 待压缩图片<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param width&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 压缩图片高度<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param heigt&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 压缩图片宽度<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; private static BufferedImage zoom(BufferedImage sourceImage , int width , int height){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage zoomImage = new BufferedImage(width, height, sourceImage.getType());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Image image = sourceImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Graphics gc = zoomImage.getGraphics();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gc.setColor(Color.WHITE);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; gc.drawImage( image , 0, 0, null);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return zoomImage;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 获取某个文件的前缀路径<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * 不包含文件名的路径<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param file&nbsp;&nbsp; 当前文件对象<br />&nbsp;&nbsp;&nbsp;&nbsp; * @return<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws IOException<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static String getFilePrefixPath(File file) throws IOException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String path = null;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!file.exists()) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IOException("not found the file !" );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String fileName = file.getName();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; path = file.getPath().replace(fileName, "");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return path;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 获取某个文件的前缀路径<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * 不包含文件名的路径<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param path&nbsp;&nbsp; 当前文件路径<br />&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不包含文件名的路径<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static String getFilePrefixPath(String path) throws Exception{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(null == path || path.isEmpty()) throw new Exception("文件路径为空！");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int index = path.lastIndexOf(File.separator);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(index &gt; 0){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; path = path.substring(0, index + 1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return path;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 获取不包含后缀的文件路径<br />&nbsp;&nbsp;&nbsp;&nbsp; *<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param src<br />&nbsp;&nbsp;&nbsp;&nbsp; * @return<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static String getPathWithoutSuffix(String src){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String path = src;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int index = path.lastIndexOf(".");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(index &gt; 0){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; path = path.substring(0, index + 1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return path;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * 获取文件名<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param filePath&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 文件路径<br />&nbsp;&nbsp;&nbsp;&nbsp; * @return&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 文件名<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws IOException<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static String getFileName(String filePath) throws IOException{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File file = new File(filePath);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(!file.exists()) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new IOException("not found the file !" );<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return file.getName();<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; /**<br />&nbsp;&nbsp;&nbsp;&nbsp; * @param args<br />&nbsp;&nbsp;&nbsp;&nbsp; * @throws Exception<br />&nbsp;&nbsp;&nbsp;&nbsp; */<br />&nbsp;&nbsp;&nbsp; public static void main(String[] args) throws Exception {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 获取系统支持的图片格式<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //ImageCutterUtil.getOSSupportsStandardImageFormat();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 起始坐标，剪切大小<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int x = 100;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int y = 75;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int width = 100;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int height = 100;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 参考图像大小<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int clientWidth = 300;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int clientHeight = 250;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File file = new File("C:\\1.jpg");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BufferedImage image = ImageIO.read(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double destWidth = image.getWidth();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double destHeight = image.getHeight();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(destWidth &lt; width || destHeight &lt; height)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new Exception("源图大小小于截取图片大小!");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double widthRatio = destWidth / clientWidth;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double heightRatio = destHeight / clientHeight;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x = Double.valueOf(x * widthRatio).intValue();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; y = Double.valueOf(y * heightRatio).intValue();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; width = Double.valueOf(width * widthRatio).intValue();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; height = Double.valueOf(height * heightRatio).intValue();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("裁剪大小&nbsp; x:" + x + ",y:" + y + ",width:" + width + ",height:" + height);<br />&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /************************ 基于三方包解决方案 *************************/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String formatName = getImageFormatName(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String pathSuffix = "." + formatName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String pathPrefix = getFilePrefixPath(file);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String targetPath = pathPrefix&nbsp; + System.currentTimeMillis() + pathSuffix;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; targetPath = ImageUtil2.cutImage(file.getPath(), targetPath, x , y , width, height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String bigTargetPath = pathPrefix&nbsp; + System.currentTimeMillis() + pathSuffix;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageUtil2.zoom(targetPath, bigTargetPath, 100, 100);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String smallTargetPath = pathPrefix&nbsp; + System.currentTimeMillis() + pathSuffix;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageUtil2.zoom(targetPath, smallTargetPath, 50, 50);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /************************ 基于JDK Image I/O 解决方案(JDK探索失败) *************************/<br />//&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File destFile = new File(targetPath);<br />//&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ImageCutterUtil.cutImage(file, destFile, x, y, width, height);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException 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 />}</div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/430621.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-05-23 14:40 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/05/23/430621.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于Redis实现分布式锁 </title><link>http://www.blogjava.net/wangxinsh55/archive/2016/05/12/430470.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Thu, 12 May 2016 09:52:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2016/05/12/430470.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/430470.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2016/05/12/430470.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/430470.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/430470.html</trackback:ping><description><![CDATA[<div>http://chaopeng.me/blog/2014/01/26/redis-lock.html</div><br /><div>http://blog.csdn.net/ugg/article/details/41894947</div><br /><div>http://www.jeffkit.info/2011/07/1000/</div><br /><div><p>Redis有一系列的命令，特点是以NX结尾，NX是Not eXists的缩写，如SETNX命令就应该理解为：SET if Not eXists。这系列的命令非常有用，这里讲使用SETNX来实现分布式锁。</p> <h3>用SETNX实现分布式锁</h3> <p>利用SETNX非常简单地实现分布式锁。例如：某客户端要获得一个名字foo的锁，客户端使用下面的命令进行获取：</p> <p>SETNX lock.foo &lt;current Unix time + lock timeout + 1&gt;</p> <ul><li>&nbsp;如返回1，则该客户端获得锁，把lock.foo的键值设置为时间值表示该键已被锁定，该客户端最后可以通过DEL lock.foo来释放该锁。</li><li>&nbsp;如返回0，表明该锁已被其他客户端取得，这时我们可以先返回或进行重试等对方完成或等待锁超时。</li></ul> <h3>解决死锁</h3> <p>上面的锁定逻辑有一个问题：如果一个持有锁的客户端失败或崩溃了不能释放锁，该怎么解决？我们可以通过锁的键对应的时间戳来判断这种情况是否发生了，如果当前的时间已经大于lock.foo的值，说明该锁已失效，可以被重新使用。</p> <p>发生这种情况时，可不能简单的通过DEL来删除锁，然后再SETNX一次，当多个客户端检测到锁超时后都会尝试去释放它，这里就可能出现一个竞态条件,让我们模拟一下这个场景：</p> <ol><li>&nbsp;C0操作超时了，但它还持有着锁，C1和C2读取lock.foo检查时间戳，先后发现超时了。</li><li>&nbsp;C1 发送DEL lock.foo</li><li>&nbsp;C1 发送SETNX lock.foo 并且成功了。</li><li>&nbsp;C2 发送DEL lock.foo</li><li>&nbsp;C2 发送SETNX lock.foo 并且成功了。</li></ol> <p>这样一来，C1，C2都拿到了锁！问题大了！</p> <p>幸好这种问题是可以避免D，让我们来看看C3这个客户端是怎样做的：</p> <ol><li>C3发送SETNX lock.foo 想要获得锁，由于C0还持有锁，所以Redis返回给C3一个0</li><li>C3发送GET lock.foo 以检查锁是否超时了，如果没超时，则等待或重试。</li><li>反之，如果已超时，C3通过下面的操作来尝试获得锁：<br /> GETSET lock.foo &lt;current Unix time + lock timeout + 1&gt;</li><li>通过GETSET，C3拿到的时间戳如果仍然是超时的，那就说明，C3如愿以偿拿到锁了。</li><li>如果在C3之前，有个叫C4的客户端比C3快一步执行了上面的操作，那么C3拿到的时间戳是个未超时的值，这时，C3没有如期获得锁，需要再次等待或重试。留意一下，尽管C3没拿到锁，但它改写了C4设置的锁的超时值，不过这一点非常微小的误差带来的影响可以忽略不计。</li></ol> <p><strong>注意：</strong>为了让分布式锁的算法更稳键些，持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时，再去做DEL操作，因为可能客户端因为某个耗时的操作而挂起，操作完的时候锁因为超时已经被别人获得，这时就不必解锁了。</p> <h3>示例伪代码</h3> <p>根据上面的代码，我写了一小段Fake代码来描述使用分布式锁的全过程：</p> <div no=""  python"=""> <ol><li> <div># get lock</div> </li><li> <div>lock = 0</div> </li><li> <div>while lock != 1:</div> </li><li> <div>&nbsp; &nbsp; timestamp =&nbsp;current Unix time + lock timeout + 1</div> </li><li> <div>&nbsp; &nbsp; lock =&nbsp;SETNX lock.foo timestamp</div> </li><li> <div>&nbsp; &nbsp; if lock == 1 or (now() &gt; (GET lock.foo) and&nbsp;now() &gt;&nbsp;(GETSET lock.foo timestamp)):</div> </li><li> <div>&nbsp; &nbsp; &nbsp; &nbsp; break;</div> </li><li> <div>&nbsp; &nbsp; else:</div> </li><li> <div>&nbsp; &nbsp; &nbsp; &nbsp; sleep(10ms)</div> </li><li> <div>&nbsp;</div> </li><li> <div># do your job</div> </li><li> <div>do_job()</div> </li><li> <div>&nbsp;</div> </li><li> <div># release</div> </li><li> <div>if now() &lt; GET lock.foo:</div> </li><li> <div>&nbsp; &nbsp; DEL lock.foo</div> </li></ol> </div> <p>是的，要想这段逻辑可以重用，使用python的你马上就想到了Decorator，而用Java的你是不是也想到了那谁？AOP + annotation？行，怎样舒服怎样用吧，别重复代码就行。</p></div><br /><br /><div><div id="article_content"> <p><span style="font-size:24px;"><strong>背景<br /></strong></span>在 很多互联网产品应用中，有些场景需要加锁处理，比如：秒杀，全局递增ID，楼层生成等等。大部分的解决方案是基于DB实现的，Redis为单进程单线程模 式，采用队列模式将并发访问变成串行访问，且多客户端对Redis的连接并不存在竞争关系。其次Redis提供一些命令SETNX，GETSET，可以方 便实现分布式锁机制。</p><p><strong><span style="font-size:18px;">Redis命令介绍<br /></span></strong>使用Redis实现分布式锁，有两个重要函数需要介绍<br /><br /><span style="font-size:14px;">SETNX命令（SET if Not eXists）</span><br />语法：<br />SETNX key value<br />功能：<br />当且仅当 key 不存在，将 key 的值设为 value ，并返回1；若给定的 key 已经存在，则 SETNX 不做任何动作，并返回0。</p><p><span style="font-size:14px;">GETSET命令</span><br />语法：<br />GETSET key value<br />功能：<br />将给定 key 的值设为 value ，并返回 key 的旧值 (old value)，当 key 存在但不是字符串类型时，返回一个错误，当key不存在时，返回nil。</p><p><span style="font-size:14px;">GET命令</span><br />语法：<br />GET key<br />功能：<br />返回 key 所关联的字符串值，如果 key 不存在那么返回特殊值 nil 。</p><p><span style="font-size:14px;">DEL命令</span><br />语法：<br />DEL key [KEY &#8230;]<br />功能：<br />删除给定的一个或多个 key ,不存在的 key 会被忽略。</p><p>兵贵精，不在多。分布式锁，我们就依靠这四个命令。但在具体实现，还有很多细节，需要仔细斟酌，因为在分布式并发多进程中，任何一点出现差错，都会导致死锁，hold住所有进程。</p><p><strong><span style="font-size:18px;">加锁实现</span></strong></p><p>SETNX 可以直接加锁操作，比如说对某个关键词foo加锁，客户端可以尝试<br />SETNX foo.lock &lt;current unix time&gt;</p><p>如果返回1，表示客户端已经获取锁，可以往下操作，操作完成后，通过<br />DEL foo.lock</p><p>命令来释放锁。<br />如果返回0，说明foo已经被其他客户端上锁，如果锁是非堵塞的，可以选择返回调用。如果是堵塞调用调用，就需要进入以下个重试循环，直至成功获得锁或者重试超时。理想是美好的，现实是残酷的。仅仅使用SETNX加锁带有竞争条件的，在某些特定的情况会造成死锁错误。</p><p><span style="font-size:14px;">处理死锁</span></p><p>在 上面的处理方式中，如果获取锁的客户端端执行时间过长，进程被kill掉，或者因为其他异常崩溃，导致无法释放锁，就会造成死锁。所以，需要对加锁要做时 效性检测。因此，我们在加锁时，把当前时间戳作为value存入此锁中，通过当前时间戳和Redis中的时间戳进行对比，如果超过一定差值，认为锁已经时 效，防止锁无限期的锁下去，但是，在大并发情况，如果同时检测锁失效，并简单粗暴的删除死锁，再通过SETNX上锁，可能会导致竞争条件的产生，即多个客 户端同时获取锁。</p><p>C1获取锁，并崩溃。C2和C3调用SETNX上锁返回0后，获得foo.lock的时间戳，通过比对时间戳，发现锁超时。<br />C2 向foo.lock发送DEL命令。<br />C2 向foo.lock发送SETNX获取锁。<br />C3 向foo.lock发送DEL命令，此时C3发送DEL时，其实DEL掉的是C2的锁。<br />C3 向foo.lock发送SETNX获取锁。</p><p>此时C2和C3都获取了锁，产生竞争条件，如果在更高并发的情况，可能会有更多客户端获取锁。所以，DEL锁的操作，不能直接使用在锁超时的情况下，幸好我们有GETSET方法，假设我们现在有另外一个客户端C4，看看如何使用GETSET方式，避免这种情况产生。</p><p>C1获取锁，并崩溃。C2和C3调用SETNX上锁返回0后，调用GET命令获得foo.lock的时间戳T1，通过比对时间戳，发现锁超时。<br />C4 向foo.lock发送GESET命令，<br />GETSET foo.lock &lt;current unix time&gt;<br />并得到foo.lock中老的时间戳T2</p><p>如果T1=T2，说明C4获得时间戳。<br />如果T1!=T2，说明C4之前有另外一个客户端C5通过调用GETSET方式获取了时间戳，C4未获得锁。只能sleep下，进入下次循环中。</p><p>现在唯一的问题是，C4设置foo.lock的新时间戳，是否会对锁产生影响。其实我们可以看到C4和C5执行的时间差值极小，并且写入foo.lock中的都是有效时间错，所以对锁并没有影响。<br />为 了让这个锁更加强壮，获取锁的客户端，应该在调用关键业务时，再次调用GET方法获取T1，和写入的T0时间戳进行对比，以免锁因其他情况被执行DEL意 外解开而不知。以上步骤和情况，很容易从其他参考资料中看到。客户端处理和失败的情况非常复杂，不仅仅是崩溃这么简单，还可能是客户端因为某些操作被阻塞 了相当长时间，紧接着 DEL  命令被尝试执行(但这时锁却在另外的客户端手上)。也可能因为处理不当，导致死锁。还有可能因为sleep设置不合理，导致Redis在大并发下被压垮。 最为常见的问题还有</p><p><span style="font-weight: bold;"><span style="font-size:14px;">GET返回nil时应该走那种逻辑？</span></span></p><p>第一种走超时逻辑<br />C1客户端获取锁，并且处理完后，DEL掉锁，在DEL锁之前。C2通过SETNX向foo.lock设置时间戳T0 发现有客户端获取锁，进入GET操作。<br />C2 向foo.lock发送GET命令，获取返回值T1(nil)。<br />C2 通过T0&gt;T1+expire对比，进入GETSET流程。<br />C2 调用GETSET向foo.lock发送T0时间戳，返回foo.lock的原值T2<br />C2 如果T2=T1相等，获得锁，如果T2!=T1，未获得锁。</p><p>第二种情况走循环走setnx逻辑<br />C1客户端获取锁，并且处理完后，DEL掉锁，在DEL锁之前。C2通过SETNX向foo.lock设置时间戳T0 发现有客户端获取锁，进入GET操作。<br />C2 向foo.lock发送GET命令，获取返回值T1(nil)。<br />C2 循环，进入下一次SETNX逻辑</p><p>两 种逻辑貌似都是OK，但是从逻辑处理上来说，第一种情况存在问题。当GET返回nil表示，锁是被删除的，而不是超时，应该走SETNX逻辑加锁。走第一 种情况的问题是，正常的加锁逻辑应该走SETNX，而现在当锁被解除后，走的是GETST，如果判断条件不当，就会引起死锁，很悲催，我在做的时候就碰到 了，具体怎么碰到的看下面的问题</p><p><span style="font-weight: bold;"><span style="font-size:14px;">GETSET返回nil时应该怎么处理？</span></span></p><p>C1和C2客户端调用GET接口，C1返回T1，此时C3网络情况更好，快速进入获取锁，并执行DEL删除锁，C2返回T2(nil)，C1和C2都进入超时处理逻辑。<br />C1 向foo.lock发送GETSET命令，获取返回值T11(nil)。<br />C1 比对C1和C11发现两者不同，处理逻辑认为未获取锁。<br />C2 向foo.lock发送GETSET命令，获取返回值T22(C1写入的时间戳)。<br />C2 比对C2和C22发现两者不同，处理逻辑认为未获取锁。</p><p>此 时C1和C2都认为未获取锁，其实C1是已经获取锁了，但是他的处理逻辑没有考虑GETSET返回nil的情况，只是单纯的用GET和GETSET值就行 对比，至于为什么会出现这种情况？一种是多客户端时，每个客户端连接Redis的后，发出的命令并不是连续的，导致从单客户端看到的好像连续的命令，到 Redis  server后，这两条命令之间可能已经插入大量的其他客户端发出的命令，比如DEL,SETNX等。第二种情况，多客户端之间时间不同步，或者不是严格 意义的同步。</p><p><span style="font-weight: bold;"><span style="font-size:14px;">时间戳的问题</span></span></p><p>我们看到foo.lock的value值为时间戳，所以要在多客户端情况下，保证锁有效，一定要同步各服务器的时间，如果各服务器间，时间有差异。时间不一致的客户端，在判断锁超时，就会出现偏差，从而产生竞争条件。<br />锁的超时与否，严格依赖时间戳，时间戳本身也是有精度限制，假如我们的时间精度为秒，从加锁到执行操作再到解锁，一般操作肯定都能在一秒内完成。这样的话，我们上面的CASE，就很容易出现。所以，最好把时间精度提升到毫秒级。这样的话，可以保证毫秒级别的锁是安全的。</p><p><span style="font-size:14px;">分布式锁的问题</span></p><p>1：必要的超时机制：获取锁的客户端一旦崩溃，一定要有过期机制，否则其他客户端都降无法获取锁，造成死锁问题。<br />2：分布式锁，多客户端的时间戳不能保证严格意义的一致性，所以在某些特定因素下，有可能存在锁串的情况。要适度的机制，可以承受小概率的事件产生。<br />3：只对关键处理节点加锁，良好的习惯是，把相关的资源准备好，比如连接数据库后，调用加锁机制获取锁，直接进行操作，然后释放，尽量减少持有锁的时间。<br />4：在持有锁期间要不要CHECK锁，如果需要严格依赖锁的状态，最好在关键步骤中做锁的CHECK检查机制，但是根据我们的测试发现，在大并发时，每一次CHECK锁操作，都要消耗掉几个毫秒，而我们的整个持锁处理逻辑才不到10毫秒，玩客没有选择做锁的检查。<br />5：sleep学问，为了减少对Redis的压力，获取锁尝试时，循环之间一定要做sleep操作。但是sleep时间是多少是门学问。需要根据自己的Redis的QPS，加上持锁处理时间等进行合理计算。<br />6：至于为什么不使用Redis的muti，expire，watch等机制，可以查一参考资料，找下原因。</p><p><span style="font-size:18px;">锁测试数据</span></p><p><strong>未使用sleep</strong><br />第一种，锁重试时未做sleep。单次请求，加锁，执行，解锁时间&nbsp;<br /><img src="http://img.blog.csdn.net/20141212162927906?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdWdn/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /><br /><br />可以看到加锁和解锁时间都很快，当我们使用</p><p>ab -n1000 -c100 'http://sandbox6.wanke.etao.com/test/test_sequence.php?tbpm=t'<br />AB 并发100累计1000次请求，对这个方法进行压测时。 <br /><img src="http://img.blog.csdn.net/20141212162944369" alt="" /><br /><br />我们会发现，获取锁的时间变成，同时持有锁后，执行时间也变成，而delete锁的时间，将近10ms时间，为什么会这样？<br />1：持有锁后，我们的执行逻辑中包含了再次调用Redis操作，在大并发情况下，Redis执行明显变慢。<br />2：锁的删除时间变长，从之前的0.2ms，变成9.8ms，性能下降近50倍。<br />在这种情况下，我们压测的QPS为49，最终发现QPS和压测总量有关，当我们并发100总共100次请求时，QPS得到110多。当我们使用sleep时</p><p><strong>使用Sleep时</strong></p><p>单次执行请求时<br /><img src="http://img.blog.csdn.net/20141212163004664" alt="" /><br /></p><p>我们看到，和不使用sleep机制时，性能相当。当时用相同的压测条件进行压缩时&nbsp;<br /><img src="http://img.blog.csdn.net/20141212163101609" alt="" /><br /></p><p>获取锁的时间明显变长，而锁的释放时间明显变短，仅是不采用sleep机制的一半。当然执行时间变成就是因为，我们在执行过程中，重新创建数据库连接，导致时间变长的。同时我们可以对比下Redis的命令执行压力情况&nbsp;<br /><img src="http://img.blog.csdn.net/20141212163043992" alt="" /><br />上 图中细高部分是为未采用sleep机制的时的压测图，矮胖部分为采用sleep机制的压测图，通上图看到压力减少50%左右，当然，sleep这种方式还 有个缺点QPS下降明显，在我们的压测条件下，仅为35，并且有部分请求出现超时情况。不过综合各种情况后，我们还是决定采用sleep机制，主要是为了 防止在大并发情况下把Redis压垮，很不行，我们之前碰到过，所以肯定会采用sleep机制。</p><p><strong><span style="font-size:18px;">参考资料</span></strong></p><p><a target="_blank" href="http://www.worlduc.com/FileSystem/18/2518/590664/9f63555e6079482f831c8ab1dcb8c19c.pdf">http://www.worlduc.com/FileSystem/18/2518/590664/9f63555e6079482f831c8ab1dcb8c19c.pdf</a><br /><a target="_blank" href="http://redis.io/commands/setnx">http://redis.io/commands/setnx</a><br /><a target="_blank" href="http://www.blogjava.net/caojianhua/archive/2013/01/28/394847.html">http://www.blogjava.net/caojianhua/archive/2013/01/28/394847.html</a></p>    </div></div><br /><div><h2>引子</h2> <p>redis是一个很强大的数据结构存储的nosql数据库，很方便针对业务模型进行效率的优化。最近我的工作是负责对现有Java服务器框架进行整理，并将网络层与逻辑层脱离，以便于逻辑层和网络层的横向扩展。 尽管我在逻辑层上使用了AKKA作为核心框架，尽可能lockfree，但是还是免不了需要跨jvm的锁。所以我需要实现一个分布式锁。</p> <h2>官方的实现</h2> <p>官方在<a href="http://redis.io/commands/setnx">SETNX</a> 这一页给了一个实现。</p> <ul><li>C4 sends SETNX lock.foo in order to acquire the lock</li><li>The crashed client C3 still holds it, so Redis will reply with 0 to C4.</li><li>C4 sends GET lock.foo to check if the lock expired. If it is not, it will sleep for some time and retry from the start.</li><li>Instead, if the lock is expired because the Unix time at lock.foo is  older than the current Unix time, C4 tries to perform: GETSET lock.foo  (current Unix timestamp + lock timeout + 1)</li><li>Because of the GETSET semantic, C4 can check if the old value stored  at key is still an expired timestamp. If it is, the lock was acquired.</li><li>If another client, for instance C5, was faster than C4 and acquired  the lock with the GETSET operation, the C4 GETSET operation will return a  non expired timestamp. C4 will simply restart from the first step. Note  that even if C4 set the key a bit a few seconds in the future this is  not a problem.</li></ul> <p>但是使用官方推荐的getset实现的话，未竞争到锁的一方确实可以判断到自己未能竞争到锁，但却将持有锁一方的时间修改了，这样的直接后果就是，持有锁的一方无法解锁！！！</p> <h2>基于lua的实现</h2> <p>其实官方实现出现的问题，是因为使用redis独立的命令不能将get-check-set这个过程进行原子化，所以我决定引入redis-lua，将get-check-set这个过程使用lua脚本来实现。</p> <p>加锁：</p> <ul><li>script params: lock_key, current_timestamp, lock_timeout</li><li>setnx lock_key (current_timestamp + lock_timeout). if not success,  set lock_key (current_timestamp + lock_timeout) if current_timestamp  &gt; value</li><li>client save current_timestamp(lock_create_timestamp)</li></ul> <p>解锁：</p> <ul><li>script params: lock_key, lock_create_timestamp, lock_timeout</li><li>delete if lock_create_timestamp + lock_timeout == value</li></ul> <p>具体的实现:</p> <div> LUA</div><div><pre id="code0" linenums=""  prettyprinted"=""><ol><li><code>---lock</code></li><li><code></code><br /></li><li><code>local now = tonumber(ARGV[1])</code></li><li><code>local timeout = tonumber(ARGV[2])</code></li><li><code>local to = now + timeout</code></li><li><code>local locked = redis.call('SETNX', KEYS[1], to)</code></li><li><code>if (locked == 1) then</code></li><li><code> return 0</code></li><li><code>end</code></li><li><code>local kt = redis.call('type', KEYS[1]);</code></li><li><code>if (kt['ok'] ~= 'string') then</code></li><li><code> return 2</code></li><li><code>end</code></li><li><code>local keyValue = tonumber(redis.call('get', KEYS[1]))</code></li><li><code>if (now &gt; keyValue) then</code></li><li><code>    redis.call('set', KEYS[1], to)</code></li><li><code> return 0</code></li><li><code>end</code></li><li><code>return 1</code></li><li><code></code><br /></li><li><code>---unlock</code></li><li><code></code><br /></li><li><code>local begin = tonumber(ARGV[1])</code></li><li><code>local timeout = tonumber(ARGV[2])</code></li><li><code>local kt = redis.call('type', KEYS[1]);</code></li><li><code>if (kt['ok'] == 'string') then</code></li><li><code> local keyValue = tonumber(redis.call('get', KEYS[1]))</code></li><li><code> if ((keyValue - begin) == timeout) then</code></li><li><code>        redis.call('del', KEYS[1])</code></li><li><code> return 0</code></li><li><code> end</code></li><li><code>end</code></li><li><code>return 1</code></li></ol></pre></div>  <h2>已知问题</h2> <p>redis的分布式锁会有单点的问题。当然我们的业务量也没有达到挂掉专门做锁的redis单点的水平。</p></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/430470.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2016-05-12 17:52 <a href="http://www.blogjava.net/wangxinsh55/archive/2016/05/12/430470.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>maven将lib的依赖包也打进jar中</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/11/30/428432.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 30 Nov 2015 09:01:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/11/30/428432.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/428432.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/11/30/428432.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/428432.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/428432.html</trackback:ping><description><![CDATA[<div>&lt;project xmlns="http://maven.apache.org/POM/4.0.0"<br /> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br /> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;<br /> &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;<br /> &lt;groupId&gt;com.chinacache.logstat&lt;/groupId&gt;<br /> &lt;artifactId&gt;HadoopLogStat&lt;/artifactId&gt;<br /> &lt;version&gt;1.0&lt;/version&gt;<br /> &lt;packaging&gt;jar&lt;/packaging&gt;<br /> <br /> <br /> &lt;name&gt;HadoopLogStat&lt;/name&gt;<br /> &lt;url&gt;http://maven.apache.org&lt;/url&gt;<br /> <br /> <br /> &lt;properties&gt;<br /> &lt;project.build.sourceEncoding&gt;<br /> UTF-8<br /> &lt;/project.build.sourceEncoding&gt;<br /> &lt;/properties&gt;<br /> <br /> <br /> &lt;build&gt;<br /> &lt;finalName&gt;HadoopLogStat&lt;/finalName&gt;<br /> &lt;plugins&gt;<br /> &lt;plugin&gt;<br /> &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br /> &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;<br /> &lt;version&gt;2.0&lt;/version&gt;<br /> &lt;configuration&gt;<br /> &lt;source&gt;1.5&lt;/source&gt;<br /> &lt;target&gt;1.5&lt;/target&gt;<br /> &lt;encoding&gt;UTF-8&lt;/encoding&gt;<br /> &lt;charset&gt;UTF-8&lt;/charset&gt;<br /> &lt;/configuration&gt;<br /> &lt;/plugin&gt;<br /> &lt;plugin&gt;<br /> &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br /> &lt;artifactId&gt;maven-dependency-plugin&lt;/artifactId&gt;<br /> &lt;executions&gt;<br /> &lt;execution&gt;<br /> &lt;id&gt;copy-dependencies&lt;/id&gt;<br /> &lt;phase&gt;test&lt;/phase&gt;<br /> &lt;goals&gt;<br /> &lt;goal&gt;copy-dependencies&lt;/goal&gt;<br /> &lt;/goals&gt;<br /> &lt;configuration&gt;<br /> &lt;outputDirectory&gt;<br /> target/classes/lib<br /> &lt;/outputDirectory&gt;<br /> &lt;/configuration&gt;<br /> &lt;/execution&gt;<br /> &lt;/executions&gt;<br /> &lt;/plugin&gt;<br /> &lt;plugin&gt;<br /> &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br /> &lt;artifactId&gt;maven-jar-plugin&lt;/artifactId&gt;<br /> &lt;configuration&gt;<br /> &lt;archive&gt;<br /> &lt;manifest&gt;<br /> &lt;addClasspath&gt;true&lt;/addClasspath&gt;<br /> &lt;mainClass&gt;<br /> com.chinacache.logstat.Main<br /> &lt;/mainClass&gt;<br /> &lt;classpathPrefix&gt;lib/&lt;/classpathPrefix&gt;<br /> &lt;/manifest&gt;<br /> &lt;manifestEntries&gt;<br /> &lt;Class-Path&gt;.&lt;/Class-Path&gt;<br /> &lt;/manifestEntries&gt;<br /> &lt;/archive&gt;<br /> &lt;excludes&gt;<br /> &lt;exclude&gt;conf/ipindex/**&lt;/exclude&gt;<br /> &lt;/excludes&gt;<br /> &lt;/configuration&gt;<br /> &lt;/plugin&gt;<br /> &lt;/plugins&gt;<br /> &lt;/build&gt;<br /> &lt;dependencies&gt;<br /> &lt;dependency&gt;<br /> &lt;groupId&gt;junit&lt;/groupId&gt;<br /> &lt;artifactId&gt;junit&lt;/artifactId&gt;<br /> &lt;version&gt;3.8.1&lt;/version&gt;<br /> &lt;scope&gt;test&lt;/scope&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;log4j&lt;/groupId&gt;<br /> &lt;artifactId&gt;log4j&lt;/artifactId&gt;<br /> &lt;version&gt;1.2.15&lt;/version&gt;<br /> &lt;type&gt;jar&lt;/type&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;org.springframework&lt;/groupId&gt;<br /> &lt;artifactId&gt;spring&lt;/artifactId&gt;<br /> &lt;version&gt;2.5.6&lt;/version&gt;<br /> &lt;type&gt;jar&lt;/type&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;commons-beanutils&lt;/groupId&gt;<br /> &lt;artifactId&gt;commons-beanutils&lt;/artifactId&gt;<br /> &lt;version&gt;1.8.3&lt;/version&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;commons-digester&lt;/groupId&gt;<br /> &lt;artifactId&gt;commons-digester&lt;/artifactId&gt;<br /> &lt;version&gt;2.1&lt;/version&gt;<br /> &lt;type&gt;jar&lt;/type&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;commons-io&lt;/groupId&gt;<br /> &lt;artifactId&gt;commons-io&lt;/artifactId&gt;<br /> &lt;version&gt;1.4&lt;/version&gt;<br /> &lt;type&gt;jar&lt;/type&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;commons-lang&lt;/groupId&gt;<br /> &lt;artifactId&gt;commons-lang&lt;/artifactId&gt;<br /> &lt;version&gt;2.4&lt;/version&gt;<br /> &lt;type&gt;jar&lt;/type&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;commons-logging&lt;/groupId&gt;<br /> &lt;artifactId&gt;commons-logging&lt;/artifactId&gt;<br /> &lt;version&gt;1.1.1&lt;/version&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;lucene&lt;/groupId&gt;<br /> &lt;artifactId&gt;lucene&lt;/artifactId&gt;<br /> &lt;version&gt;1.9.1&lt;/version&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;commons-cli&lt;/groupId&gt;<br /> &lt;artifactId&gt;commons-cli&lt;/artifactId&gt;<br /> &lt;version&gt;1.2&lt;/version&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;!-- //真实的环境 --&gt;<br /> &lt;dependency&gt;<br /> &lt;groupId&gt;org.apache.hadoop&lt;/groupId&gt;<br /> &lt;artifactId&gt;hadoop-core&lt;/artifactId&gt;<br /> &lt;version&gt;0.20.2-cdh3u1&lt;/version&gt;<br /> &lt;type&gt;jar&lt;/type&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;org.apache.hadoop&lt;/groupId&gt;<br /> &lt;artifactId&gt;hadoop-index&lt;/artifactId&gt;<br /> &lt;version&gt;0.20.2-cdh3u2&lt;/version&gt;<br /> &lt;/dependency&gt;<br /> <br /> <br /> &lt;dependency&gt;<br /> &lt;groupId&gt;org.apache.hadoop&lt;/groupId&gt;<br /> &lt;artifactId&gt;hadoop-lzo&lt;/artifactId&gt;<br /> &lt;version&gt;0.4.13&lt;/version&gt;<br /> &lt;/dependency&gt;<br /> &lt;/dependencies&gt;<br /> &lt;/project&gt;</div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/428432.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-11-30 17:01 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/11/30/428432.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于HttpClient 4.3.3 的一个上传文件</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/11/17/428235.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 17 Nov 2015 08:44:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/11/17/428235.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/428235.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/11/17/428235.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/428235.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/428235.html</trackback:ping><description><![CDATA[<div>&nbsp;&nbsp;&nbsp; public void test() throws IOException {<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;MockMultipartFile file = new MockMultipartFile("历史.bmp",<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "历史.bmp",<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "image/bmp",<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FileUtils.openInputStream(new File("C:\\Users\\simone\\Pictures\\历史.bmp")));<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String fileName = file.getOriginalFilename();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;HttpPost httpPost = new HttpPost("http://xxxxxxxx/defupload");<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;StringBody token = new StringBody("b27322a42a913b191398035f530c4155", ContentType.TEXT_PLAIN);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ByteArrayBody byteArrayBody = new ByteArrayBody(file.getBytes(), fileName);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;HttpEntity reqEntity = MultipartEntityBuilder.create()<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .addPart("token", token)<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .addPart("file", byteArrayBody)<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .setCharset(CharsetUtils.get("UTF-8"))<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .build();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;httpPost.setEntity(reqEntity);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;CloseableHttpClient httpClient = HttpClients.custom().setProxy(new HttpHost("127.0.0.1", 8888)).build();<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;CloseableHttpResponse response = httpClient.execute(httpPost);<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;EntityUtils.toString(response.getEntity());<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;response.close();<br />&nbsp;&nbsp; &nbsp;}</div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/428235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-11-17 16:44 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/11/17/428235.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>activit jdk8 scripttask</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/07/06/426059.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 06 Jul 2015 07:06:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/07/06/426059.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/426059.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/07/06/426059.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/426059.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/426059.html</trackback:ping><description><![CDATA[scripttask在使用jdk 8的JavaScript脚本时对外java对象的类获取不到，这里有的处理方法为：<br /><div>load("nashorn:mozilla_compat.js");<br />// Import the java.awt package<br />importPackage(java.awt);<br />// Import the java.awt.Frame class<br />importClass(java.awt.Frame);<br />// Create a new Frame object<br />var frame = new java.awt.Frame("hello");<br />// Call the setVisible() method<br />frame.setVisible(true);<br />// Access a JavaBean property<br />print(frame.title);</div><br />在脚本的最前边加入<div>load("nashorn:mozilla_compat.js");</div>这句话，即可。<br /><br />注意2：<br />&lt;bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"&gt;<br /><div>&nbsp;&nbsp; &nbsp;&lt;property name="dataSource" ref="dataSource" /&gt;<br />&nbsp;&nbsp;&nbsp; &lt;property name="transactionManager" ref="transactionManager"/&gt;<br />&nbsp;&nbsp;&nbsp; &lt;property name="databaseSchemaUpdate" value="true"/&gt;<br />&nbsp;&nbsp;&nbsp; &lt;property name="jobExecutorActivate" value="true"/&gt;<br />&nbsp;&nbsp;&nbsp; &lt;!--&lt;property name="history" value="full"/&gt;--&gt;<br />&nbsp;&nbsp;&nbsp; &lt;property name="processDefinitionCacheLimit" value="10"/&gt;<br />&nbsp;&nbsp; &nbsp;<br />&nbsp;&nbsp;&nbsp; &lt;property name="beans"&gt;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;map&gt;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;entry key="shellUtils"&gt;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;bean id="shellUtils" class="com.duxiu.modules.activiti.utils.ShellUtils" /&gt;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/entry&gt;<br />&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/map&gt;<br />&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />&lt;/bean&gt;</div>这里的bean属性可以将ShellUtils类暴露给JavaScript脚本来使用，不同的地方是：<br />jdk7版本ShellUtils类里的方法可以静态方法暴露出去，但是jdk8则不行，只能暴露public方法。<br /><br /><div>http://docs.oracle.com/javase/8/docs/technotes/guides/scripting/prog_guide/javascript.html#A1147207</div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/426059.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-07-06 15:06 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/07/06/426059.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>javaBean与Map&lt;String,Object&gt;互转 </title><link>http://www.blogjava.net/wangxinsh55/archive/2015/06/30/425969.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 30 Jun 2015 10:44:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/06/30/425969.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/425969.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/06/30/425969.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/425969.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/425969.html</trackback:ping><description><![CDATA[<div>使用下边的方法，或者转成fastjson的JsonObject对象<br />http://blog.csdn.net/cuidiwhere/article/details/8130434</div><br /><div><h5><a name="t0"></a>1. 为什么要实现javaBean与Map&lt;String,Object&gt;相互转换？</h5> <p>用过spring的都知道spring的MVC框架中有一个BaseCommandController对象，利用这个对象我们就可以很方便的将从 客户端传递过来的参数封装到一个JavaBean对象中去，而不需要我们 request.getParameter("name");bean.setName(name);了，从而也简化了不少的工作。如果大家用过 BeanUtils.populate的话，就知道，这个方法是可以很方便的将request提交的页面表单自动填写到你创建的对象中</p> <h5><a name="t1"></a>2. 如何实现javaBean与Map&lt;String,Object&gt;相互转换？</h5> <p>方法1： 利用java.beans.Introspector和java.beans.PropertyDescriptor实现&nbsp;javaBean与Map&lt;String,Object&gt;互转</p> <p>方法2： 利用org.apache.commons.beanutils.BeanUtils工具类，BeanUtils.populate实现Map 转换为javaBean&nbsp;</p> <p><br /> </p>  <div bg_java"=""><div><div><strong>[java]</strong> <a href="http://blog.csdn.net/cuidiwhere/article/details/8130434#" title="view plain">view plain</a><a href="http://blog.csdn.net/cuidiwhere/article/details/8130434#" title="copy">copy</a></div></div><ol start="1"><li><span>package&nbsp;javaStudyDemo.bean.reflect.test;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;java.beans.BeanInfo;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.beans.Introspector;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.beans.PropertyDescriptor;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.lang.reflect.Method;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.util.HashMap;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.util.Map;&nbsp;&nbsp;</span></li><li><span>import&nbsp;javaStudyDemo.others.PersonBean;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;org.apache.commons.beanutils.BeanUtils;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>/**&nbsp;</span></li><li><span>&nbsp;*&nbsp;当把Person类作为BeanUtilTest的内部类时，程序出错&lt;br&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;java.lang.NoSuchMethodException:&nbsp;Property&nbsp;'**'&nbsp;has&nbsp;no&nbsp;setter&nbsp;method&lt;br&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;本质：内部类&nbsp;和&nbsp;单独文件中的类的区别&nbsp;&lt;br&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;BeanUtils.populate方法的限制：&lt;br&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;The&nbsp;class&nbsp;must&nbsp;be&nbsp;public,&nbsp;and&nbsp;provide&nbsp;a&nbsp;public&nbsp;constructor&nbsp;that&nbsp;accepts&nbsp;no&nbsp;arguments.&nbsp;&lt;br&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;This&nbsp;allows&nbsp;tools&nbsp;and&nbsp;applications&nbsp;to&nbsp;dynamically&nbsp;create&nbsp;new&nbsp;instances&nbsp;of&nbsp;your&nbsp;bean,&nbsp;&lt;br&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;without&nbsp;necessarily&nbsp;knowing&nbsp;what&nbsp;Java&nbsp;class&nbsp;name&nbsp;will&nbsp;be&nbsp;used&nbsp;ahead&nbsp;of&nbsp;time&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>public&nbsp;class&nbsp;BeanUtilTest&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PersonBean&nbsp;person&nbsp;=&nbsp;<span>new&nbsp;PersonBean();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&lt;String,&nbsp;Object&gt;&nbsp;mp&nbsp;=&nbsp;<span>new&nbsp;HashMap&lt;String,&nbsp;Object&gt;();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mp.put(<span>"name",&nbsp;"Mike");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mp.put(<span>"age",&nbsp;25);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mp.put(<span>"mN",&nbsp;"male");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;将map转换为bean&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;transMap2Bean2(mp,&nbsp;person);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"---&nbsp;transMap2Bean&nbsp;Map&nbsp;Info:&nbsp;");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(Map.Entry&lt;String,&nbsp;Object&gt;&nbsp;entry&nbsp;:&nbsp;mp.entrySet())&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(entry.getKey()&nbsp;+&nbsp;<span>":&nbsp;"&nbsp;+&nbsp;entry.getValue());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"---&nbsp;Bean&nbsp;Info:&nbsp;");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"name:&nbsp;"&nbsp;+&nbsp;person.getName());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"age:&nbsp;"&nbsp;+&nbsp;person.getAge());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"mN:&nbsp;"&nbsp;+&nbsp;person.getmN());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;将javaBean&nbsp;转换为map&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&lt;String,&nbsp;Object&gt;&nbsp;map&nbsp;=&nbsp;transBean2Map(person);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"---&nbsp;transBean2Map&nbsp;Map&nbsp;Info:&nbsp;");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(Map.Entry&lt;String,&nbsp;Object&gt;&nbsp;entry&nbsp;:&nbsp;map.entrySet())&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(entry.getKey()&nbsp;+&nbsp;<span>":&nbsp;"&nbsp;+&nbsp;entry.getValue());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;Map&nbsp;--&gt;&nbsp;Bean&nbsp;2:&nbsp;利用org.apache.commons.beanutils&nbsp;工具类实现&nbsp;Map&nbsp;--&gt;&nbsp;Bean&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;void&nbsp;transMap2Bean2(Map&lt;String,&nbsp;Object&gt;&nbsp;map,&nbsp;Object&nbsp;obj)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(map&nbsp;==&nbsp;null&nbsp;||&nbsp;obj&nbsp;==&nbsp;null)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BeanUtils.populate(obj,&nbsp;map);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"transMap2Bean2&nbsp;Error&nbsp;"&nbsp;+&nbsp;e);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;Map&nbsp;--&gt;&nbsp;Bean&nbsp;1:&nbsp;利用Introspector,PropertyDescriptor实现&nbsp;Map&nbsp;--&gt;&nbsp;Bean&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;void&nbsp;transMap2Bean(Map&lt;String,&nbsp;Object&gt;&nbsp;map,&nbsp;Object&nbsp;obj)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BeanInfo&nbsp;beanInfo&nbsp;=&nbsp;Introspector.getBeanInfo(obj.getClass());&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PropertyDescriptor[]&nbsp;propertyDescriptors&nbsp;=&nbsp;beanInfo.getPropertyDescriptors();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(PropertyDescriptor&nbsp;property&nbsp;:&nbsp;propertyDescriptors)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;key&nbsp;=&nbsp;property.getName();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(map.containsKey(key))&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;value&nbsp;=&nbsp;map.get(key);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;得到property对应的setter方法&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method&nbsp;setter&nbsp;=&nbsp;property.getWriteMethod();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setter.invoke(obj,&nbsp;value);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"transMap2Bean&nbsp;Error&nbsp;"&nbsp;+&nbsp;e);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;Bean&nbsp;--&gt;&nbsp;Map&nbsp;1:&nbsp;利用Introspector和PropertyDescriptor&nbsp;将Bean&nbsp;--&gt;&nbsp;Map&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;Map&lt;String,&nbsp;Object&gt;&nbsp;transBean2Map(Object&nbsp;obj)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if(obj&nbsp;==&nbsp;null){&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;null;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&lt;String,&nbsp;Object&gt;&nbsp;map&nbsp;=&nbsp;<span>new&nbsp;HashMap&lt;String,&nbsp;Object&gt;();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BeanInfo&nbsp;beanInfo&nbsp;=&nbsp;Introspector.getBeanInfo(obj.getClass());&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PropertyDescriptor[]&nbsp;propertyDescriptors&nbsp;=&nbsp;beanInfo.getPropertyDescriptors();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(PropertyDescriptor&nbsp;property&nbsp;:&nbsp;propertyDescriptors)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;key&nbsp;=&nbsp;property.getName();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;过滤class属性&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(!key.equals("class"))&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;得到property对应的getter方法&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method&nbsp;getter&nbsp;=&nbsp;property.getReadMethod();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;value&nbsp;=&nbsp;getter.invoke(obj);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map.put(key,&nbsp;value);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"transBean2Map&nbsp;Error&nbsp;"&nbsp;+&nbsp;e);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;map;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p><br /> </p>  <div bg_java"=""><div><div><strong>[java]</strong> <a href="http://blog.csdn.net/cuidiwhere/article/details/8130434#" title="view plain">view plain</a><a href="http://blog.csdn.net/cuidiwhere/article/details/8130434#" title="copy">copy</a></div></div><ol start="1"><li><span>public&nbsp;class&nbsp;PersonBean&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;String&nbsp;&nbsp;name;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;Integer&nbsp;age;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;String&nbsp;&nbsp;mN;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;the&nbsp;mN&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;String&nbsp;getmN()&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;mN;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;mN&nbsp;the&nbsp;mN&nbsp;to&nbsp;set&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;void&nbsp;setmN(String&nbsp;mN)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.mN&nbsp;=&nbsp;mN;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;the&nbsp;name&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;String&nbsp;getName()&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;name;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;name&nbsp;the&nbsp;name&nbsp;to&nbsp;set&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;void&nbsp;setName(String&nbsp;name)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.name&nbsp;=&nbsp;name;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;the&nbsp;age&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;Integer&nbsp;getAge()&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;age;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;age&nbsp;the&nbsp;age&nbsp;to&nbsp;set&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;void&nbsp;setAge(Integer&nbsp;age)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.age&nbsp;=&nbsp;age;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div><br /> <p><br /> </p> <p>总结： &nbsp;javaBean与Map&lt;String,Object&gt;互转利用到了java的内省（<span style="color:#333333; font-family:Tahoma,Verdana,STHeiTi,simsun,sans-serif; font-size:13.63636302947998px; line-height:17.27272605895996px">&nbsp;Introspector&nbsp;</span>）和反射（reflect）机制。 其思路为：&nbsp;<span style="color:#333333; font-family:Tahoma,Verdana,STHeiTi,simsun,sans-serif; font-size:13.63636302947998px; line-height:17.27272605895996px">通 过类&nbsp;Introspector&nbsp;来获取某个对象的&nbsp;BeanInfo&nbsp;信息，然后通过&nbsp;BeanInfo&nbsp;来获取属性的描述器 PropertyDescriptor，再利用属性描述器获取某个属性对应的&nbsp;getter/setter&nbsp;方法，然后通过反射机制来getter和 setter。</span></p> <p><span style="color:#333333; font-family:Tahoma,Verdana,STHeiTi,simsun,sans-serif; font-size:13.63636302947998px; line-height:17.27272605895996px"><br /> </span></p> <p><strong>什么是内省？&nbsp;</strong></p> <p><span style="color:#333333; font-family:Tahoma,Verdana,STHeiTi,simsun,sans-serif; font-size:13.63636302947998px; line-height:1.4">内 省是&nbsp;Java&nbsp;语言对&nbsp;Bean&nbsp;类属性、事件的一种缺省处理方法。例如类&nbsp;PersonBean中有属性&nbsp;name,&nbsp;那我们可以通 过&nbsp;getName,setName&nbsp;来得到其值或者设置新的值。通过&nbsp;getName/setName&nbsp;来访问&nbsp;name&nbsp;属性，这就是默认的规 则。&nbsp;Java&nbsp;中提供了一套&nbsp;API&nbsp;用来访问某个属性的&nbsp;getter/setter&nbsp;方法，通过这些&nbsp;API&nbsp;可以使你不需要了解这个规则（但你最 好还是要搞清楚），这些&nbsp;API&nbsp;存放于包&nbsp;java.beans&nbsp;中。注意：   PersonBean中属性mN的getter/setter方法必须满足javaBean命名规范，即getmN，不能写作getMN，否则转换失败。 详情参考 &nbsp;</span><a href="http://blog.renren.com/share/236384819/5598710664" style="font-family:Tahoma,Verdana,STHeiTi,simsun,sans-serif; font-size:13.63636302947998px; line-height:1.4">http://blog.renren.com/share/236384819/5598710664</a></p>  <p style="margin-top:0px; margin-bottom:0.8em; padding-top:0px; padding-bottom:0px; line-height:1.4; list-style:none; color:#333333; font-family:Tahoma,Verdana,STHeiTi,simsun,sans-serif; font-size:13.63636302947998px"> &nbsp;</p>  </div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/425969.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-06-30 18:44 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/06/30/425969.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring mvc redis cache</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/06/10/425595.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Wed, 10 Jun 2015 04:00:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/06/10/425595.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/425595.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/06/10/425595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/425595.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/425595.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://blog.joshuawhite.com/java/caching-with-spring-data-redis/ 	Caching with Spring Data Redis	 By Joshua White on January 25, 2013  in JAVA   	 In the example below, I&#8217;ll show you how to use ...&nbsp;&nbsp;<a href='http://www.blogjava.net/wangxinsh55/archive/2015/06/10/425595.html'>阅读全文</a><img src ="http://www.blogjava.net/wangxinsh55/aggbug/425595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-06-10 12:00 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/06/10/425595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用javascript与java进行RSA加密与解密</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/05/19/425175.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 19 May 2015 10:02:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/05/19/425175.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/425175.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/05/19/425175.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/425175.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/425175.html</trackback:ping><description><![CDATA[<div>http://sunxboy.iteye.com/blog/209156</div><br /><div><div id="blog_content">     <p>这几天一直做安全登录，网上查了好多资料，不尽如意。</p> <p>具体实现思路如下：</p> <p>1。服务端生成公钥与私钥，保存。</p> <p>2。客户端在请求到登录页面后，随机生成一字符串。</p> <p>3。后此随机字符串作为密钥加密密码，再用从服务端获取到的公钥加密生成的随机字符串。</p> <p>4。将此两段密文传入服务端，服务端用私钥解出随机字符串，再用此私钥解出加密的密文。</p> <p>这其中有一个关键是解决服务端的公钥，传入客户端，客户端用此公钥加密字符串后，后又能在服务端用私钥解出。</p> <p>此文即为实现此步而作。</p> <p>加密算法为RSA：</p> <p>1。服务端的RSA&nbsp; java实现。</p> <div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://sunxboy.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>/**&nbsp;</span></li><li><span>&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>package&nbsp;com.sunsoft.struts.util;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;java.io.ByteArrayOutputStream;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.io.FileInputStream;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.io.FileOutputStream;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.io.ObjectInputStream;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.io.ObjectOutputStream;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.math.BigInteger;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.KeyFactory;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.KeyPair;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.KeyPairGenerator;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.NoSuchAlgorithmException;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.PrivateKey;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.PublicKey;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.SecureRandom;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.interfaces.RSAPrivateKey;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.interfaces.RSAPublicKey;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.spec.InvalidKeySpecException;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.spec.RSAPrivateKeySpec;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.spec.RSAPublicKeySpec;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;javax.crypto.Cipher;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li><span>/**&nbsp;</span></li><li><span>&nbsp;*&nbsp;RSA&nbsp;工具类。提供加密，解密，生成密钥对等方法。&nbsp;</span></li><li><span>&nbsp;*&nbsp;需要到http://www.bouncycastle.org下载bcprov-jdk14-123.jar。&nbsp;</span></li><li><span>&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>public&nbsp;class&nbsp;RSAUtil&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*&nbsp;生成密钥对&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;KeyPair&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;EncryptException&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;KeyPair&nbsp;generateKeyPair()&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyPairGenerator&nbsp;keyPairGen&nbsp;=&nbsp;KeyPairGenerator.getInstance(<span>"RSA",&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>new&nbsp;org.bouncycastle.jce.provider.BouncyCastleProvider());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>final&nbsp;int&nbsp;KEY_SIZE&nbsp;=&nbsp;1024;//&nbsp;没什么好说的了，这个值关系到块加密的大小，可以更改，但是不要太大，否则效率会低&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyPairGen.initialize(KEY_SIZE,&nbsp;<span>new&nbsp;SecureRandom());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyPair&nbsp;keyPair&nbsp;=&nbsp;keyPairGen.generateKeyPair();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;saveKeyPair(keyPair);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;keyPair;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throw&nbsp;new&nbsp;Exception(e.getMessage());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;KeyPair&nbsp;getKeyPair()throws&nbsp;Exception{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileInputStream&nbsp;fis&nbsp;=&nbsp;<span>new&nbsp;FileInputStream("C:/RSAKey.txt");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ObjectInputStream&nbsp;oos&nbsp;=&nbsp;<span>new&nbsp;ObjectInputStream(fis);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyPair&nbsp;kp=&nbsp;(KeyPair)&nbsp;oos.readObject();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oos.close();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fis.close();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;kp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;void&nbsp;saveKeyPair(KeyPair&nbsp;kp)throws&nbsp;Exception{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FileOutputStream&nbsp;fos&nbsp;=&nbsp;<span>new&nbsp;FileOutputStream("C:/RSAKey.txt");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ObjectOutputStream&nbsp;oos&nbsp;=&nbsp;<span>new&nbsp;ObjectOutputStream(fos);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//生成密钥&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oos.writeObject(kp);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oos.close();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fos.close();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*&nbsp;生成公钥&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;modulus&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;publicExponent&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;RSAPublicKey&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;Exception&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;RSAPublicKey&nbsp;generateRSAPublicKey(byte[]&nbsp;modulus,&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>byte[]&nbsp;publicExponent)&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyFactory&nbsp;keyFac&nbsp;=&nbsp;<span>null;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyFac&nbsp;=&nbsp;KeyFactory.getInstance(<span>"RSA",&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>new&nbsp;org.bouncycastle.jce.provider.BouncyCastleProvider());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(NoSuchAlgorithmException&nbsp;ex)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throw&nbsp;new&nbsp;Exception(ex.getMessage());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RSAPublicKeySpec&nbsp;pubKeySpec&nbsp;=&nbsp;<span>new&nbsp;RSAPublicKeySpec(new&nbsp;BigInteger(&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modulus),&nbsp;<span>new&nbsp;BigInteger(publicExponent));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;(RSAPublicKey)&nbsp;keyFac.generatePublic(pubKeySpec);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(InvalidKeySpecException&nbsp;ex)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throw&nbsp;new&nbsp;Exception(ex.getMessage());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*&nbsp;生成私钥&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;modulus&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;privateExponent&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;RSAPrivateKey&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;Exception&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;RSAPrivateKey&nbsp;generateRSAPrivateKey(byte[]&nbsp;modulus,&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>byte[]&nbsp;privateExponent)&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;KeyFactory&nbsp;keyFac&nbsp;=&nbsp;<span>null;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keyFac&nbsp;=&nbsp;KeyFactory.getInstance(<span>"RSA",&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>new&nbsp;org.bouncycastle.jce.provider.BouncyCastleProvider());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(NoSuchAlgorithmException&nbsp;ex)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throw&nbsp;new&nbsp;Exception(ex.getMessage());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RSAPrivateKeySpec&nbsp;priKeySpec&nbsp;=&nbsp;<span>new&nbsp;RSAPrivateKeySpec(new&nbsp;BigInteger(&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;modulus),&nbsp;<span>new&nbsp;BigInteger(privateExponent));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;(RSAPrivateKey)&nbsp;keyFac.generatePrivate(priKeySpec);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(InvalidKeySpecException&nbsp;ex)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throw&nbsp;new&nbsp;Exception(ex.getMessage());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*&nbsp;加密&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;key&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;加密的密钥&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;data&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;待加密的明文数据&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;加密后的数据&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;Exception&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;byte[]&nbsp;encrypt(PublicKey&nbsp;pk,&nbsp;byte[]&nbsp;data)&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cipher&nbsp;cipher&nbsp;=&nbsp;Cipher.getInstance(<span>"RSA",&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>new&nbsp;org.bouncycastle.jce.provider.BouncyCastleProvider());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cipher.init(Cipher.ENCRYPT_MODE,&nbsp;pk);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;blockSize&nbsp;=&nbsp;cipher.getBlockSize();//&nbsp;获得加密块大小，如：加密前数据为128个byte，而key_size=1024&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;加密块大小为127&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;byte,加密后为128个byte;因此共有2个加密块，第一个127&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;byte第二个为1个byte&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;outputSize&nbsp;=&nbsp;cipher.getOutputSize(data.length);//&nbsp;获得加密块加密后块大小&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;leavedSize&nbsp;=&nbsp;data.length&nbsp;%&nbsp;blockSize;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;blocksSize&nbsp;=&nbsp;leavedSize&nbsp;!=&nbsp;0&nbsp;?&nbsp;data.length&nbsp;/&nbsp;blockSize&nbsp;+&nbsp;1&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;data.length&nbsp;/&nbsp;blockSize;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>byte[]&nbsp;raw&nbsp;=&nbsp;new&nbsp;byte[outputSize&nbsp;*&nbsp;blocksSize];&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;i&nbsp;=&nbsp;0;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>while&nbsp;(data.length&nbsp;-&nbsp;i&nbsp;*&nbsp;blockSize&nbsp;&gt;&nbsp;0)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(data.length&nbsp;-&nbsp;i&nbsp;*&nbsp;blockSize&nbsp;&gt;&nbsp;blockSize)&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cipher.doFinal(data,&nbsp;i&nbsp;*&nbsp;blockSize,&nbsp;blockSize,&nbsp;raw,&nbsp;i&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;outputSize);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>else&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cipher.doFinal(data,&nbsp;i&nbsp;*&nbsp;blockSize,&nbsp;data.length&nbsp;-&nbsp;i&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;blockSize,&nbsp;raw,&nbsp;i&nbsp;*&nbsp;outputSize);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;这里面doUpdate方法不可用，查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;ByteArrayOutputStream中，而最后doFinal的时候才将所有的byte[]进行加密，可是到了此时加密块大小很可能已经超出了&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;OutputSize所以只好用dofinal方法。&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i++;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;raw;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throw&nbsp;new&nbsp;Exception(e.getMessage());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*&nbsp;解密&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;key&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;解密的密钥&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;raw&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;已经加密的数据&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;解密后的明文&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;Exception&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;byte[]&nbsp;decrypt(PrivateKey&nbsp;pk,&nbsp;byte[]&nbsp;raw)&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cipher&nbsp;cipher&nbsp;=&nbsp;Cipher.getInstance(<span>"RSA",&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>new&nbsp;org.bouncycastle.jce.provider.BouncyCastleProvider());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cipher.init(cipher.DECRYPT_MODE,&nbsp;pk);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;blockSize&nbsp;=&nbsp;cipher.getBlockSize();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayOutputStream&nbsp;bout&nbsp;=&nbsp;<span>new&nbsp;ByteArrayOutputStream(64);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;j&nbsp;=&nbsp;0;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>while&nbsp;(raw.length&nbsp;-&nbsp;j&nbsp;*&nbsp;blockSize&nbsp;&gt;&nbsp;0)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bout.write(cipher.doFinal(raw,&nbsp;j&nbsp;*&nbsp;blockSize,&nbsp;blockSize));&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;j++;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;bout.toByteArray();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(Exception&nbsp;e)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throw&nbsp;new&nbsp;Exception(e.getMessage());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;*&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;args&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;Exception&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RSAPublicKey&nbsp;rsap&nbsp;=&nbsp;(RSAPublicKey)&nbsp;RSAUtil.generateKeyPair().getPublic();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;test&nbsp;=&nbsp;<span>"hello&nbsp;world";&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>byte[]&nbsp;en_test&nbsp;=&nbsp;encrypt(getKeyPair().getPublic(),test.getBytes());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>byte[]&nbsp;de_test&nbsp;=&nbsp;decrypt(getKeyPair().getPrivate(),en_test);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>new&nbsp;String(de_test));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p>&nbsp;2.测试页面：</p> <p>IndexAction.java</p> <div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://sunxboy.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>/*&nbsp;</span></li><li><span>&nbsp;*&nbsp;Generated&nbsp;by&nbsp;MyEclipse&nbsp;Struts&nbsp;</span></li><li><span>&nbsp;*&nbsp;Template&nbsp;path:&nbsp;templates/java/JavaClass.vtl&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>package&nbsp;com.sunsoft.struts.action;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;java.security.interfaces.RSAPrivateKey;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.security.interfaces.RSAPublicKey;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;javax.servlet.http.HttpServletRequest;&nbsp;&nbsp;</span></li><li><span>import&nbsp;javax.servlet.http.HttpServletResponse;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;org.apache.struts.action.Action;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.struts.action.ActionForm;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.struts.action.ActionForward;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.struts.action.ActionMapping;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;com.sunsoft.struts.util.RSAUtil;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>/**&nbsp;&nbsp;</span></li><li><span>&nbsp;*&nbsp;MyEclipse&nbsp;Struts&nbsp;</span></li><li><span>&nbsp;*&nbsp;Creation&nbsp;date:&nbsp;06-28-2008&nbsp;</span></li><li><span>&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;*&nbsp;XDoclet&nbsp;definition:&nbsp;</span></li><li><span>&nbsp;*&nbsp;@struts.action&nbsp;validate="true"&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>public&nbsp;class&nbsp;IndexAction&nbsp;extends&nbsp;Action&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Generated&nbsp;Methods&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Method&nbsp;execute&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;mapping&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;form&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;request&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;response&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;ActionForward&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;ActionForward&nbsp;execute(ActionMapping&nbsp;mapping,&nbsp;ActionForm&nbsp;form,&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)<span>throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RSAPublicKey&nbsp;rsap&nbsp;=&nbsp;(RSAPublicKey)&nbsp;RSAUtil.getKeyPair().getPublic();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;module&nbsp;=&nbsp;rsap.getModulus().toString(<span>16);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;empoent&nbsp;=&nbsp;rsap.getPublicExponent().toString(<span>16);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"module");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(module);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"empoent");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(empoent);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;request.setAttribute(<span>"m",&nbsp;module);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;request.setAttribute(<span>"e",&nbsp;empoent);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;mapping.findForward("login");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p>&nbsp;通过此action进入登录页面，并传入公钥的　Modulus 与PublicExponent的hex编码形式。</p> <p>3。登录页面　login.jsp</p> <div id=""><div><div>Html代码 &nbsp;<a title="收藏这段代码"><img src="http://sunxboy.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>&lt;%@&nbsp;page&nbsp;language="java"&nbsp;pageEncoding="GBK"%&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>&lt;%@&nbsp;taglib&nbsp;uri="http://struts.apache.org/tags-bean"&nbsp;prefix="bean"&nbsp;%&gt;&nbsp;&nbsp;</span></li><li><span>&lt;%@&nbsp;taglib&nbsp;uri="http://struts.apache.org/tags-html"&nbsp;prefix="html"&nbsp;%&gt;&nbsp;&nbsp;</span></li><li><span>&lt;%@&nbsp;taglib&nbsp;uri="http://struts.apache.org/tags-logic"&nbsp;prefix="logic"&nbsp;%&gt;&nbsp;&nbsp;</span></li><li><span>&lt;%@&nbsp;taglib&nbsp;uri="http://struts.apache.org/tags-tiles"&nbsp;prefix="tiles"&nbsp;%&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&lt;!DOCTYPE&nbsp;HTML&nbsp;PUBLIC&nbsp;"-//W3C//DTD&nbsp;HTML&nbsp;4.01&nbsp;Transitional//EN"<span>&gt;&nbsp;&nbsp;</span></li><li><span>&lt;html:html&nbsp;lang="true"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>&lt;head&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;html:base&nbsp;/&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;title&gt;login&lt;/title&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;meta&nbsp;http-equiv="pragma"&nbsp;content="no-cache"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;meta&nbsp;http-equiv="cache-control"&nbsp;content="no-cache"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;meta&nbsp;http-equiv="expires"&nbsp;content="0"&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;meta&nbsp;http-equiv="keywords"&nbsp;content="keyword1,keyword2,keyword3"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;meta&nbsp;http-equiv="description"&nbsp;content="This&nbsp;is&nbsp;my&nbsp;page"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;!--&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&lt;link&nbsp;rel="stylesheet"&nbsp;type="text/css"&nbsp;href="styles.css"&gt;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;--&gt;&nbsp;&nbsp;</span></li><li><span>&lt;script&nbsp;type="text/javascript"&nbsp;src="js/RSA.js"&gt;&lt;/script&gt;&nbsp;&nbsp;</span></li><li><span>&lt;script&nbsp;type="text/javascript"&nbsp;src="js/BigInt.js"&gt;&lt;/script&gt;&nbsp;&nbsp;</span></li><li><span>&lt;script&nbsp;type="text/javascript"&nbsp;src="js/Barrett.js"&gt;&lt;/script&gt;&nbsp;&nbsp;</span></li><li><span>&lt;script&nbsp;type="text/javascript"&gt;&nbsp;&nbsp;</span></li><li>function&nbsp;rsalogin()&nbsp;&nbsp;</li><li>{&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;bodyRSA();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;var&nbsp;<span>result&nbsp;=&nbsp;encryptedString(key,&nbsp;document.getElementById("pwd").value);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;//alert(result);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;<span>loginForm.action="login.do?result="+result;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;loginForm.submit();&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li><li>var&nbsp;key&nbsp;;&nbsp;&nbsp;</li><li>function&nbsp;bodyRSA()&nbsp;&nbsp;</li><li>{&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;setMaxDigits(130);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>key&nbsp;=&nbsp;new&nbsp;RSAKeyPair("10001","","8c1cd09a04ed01aafe70dc84c5f32ae23a16fe8fc8898aba6797c5a9c708720de4f08dbf086af429fc51c0636208f56de20a8ab5686affd9bdfb643ae1e90d5617155c4867eef06b0884ba8ecd187907c7069ae3eed4f0155eeca6573411864035ae803ad8fd91a0cc479f27e41b19c13465ab30f3cfbfd14de56f49cbd09481");&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li><span>&lt;/script&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>&lt;/head&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>&lt;body&nbsp;&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;html:form&nbsp;action="login"&nbsp;method="post"&nbsp;focus="username"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;table&nbsp;border="0"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;tr&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;td&gt;Login:&lt;/td&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;td&gt;&lt;html:text&nbsp;property="username"&nbsp;/&gt;&lt;/td&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;/tr&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;tr&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;td&gt;Password:&lt;/td&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;td&gt;&lt;html:password&nbsp;property="password"&nbsp;styleId="pwd"/&gt;&lt;/td&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;/tr&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;tr&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;td&nbsp;colspan="2"&nbsp;align="center"&gt;&lt;input&nbsp;type="button"&nbsp;value="SUBMIT"&nbsp;onclick="rsalogin();"/&gt;&lt;/td&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;/tr&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;/table&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;/html:form&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>&lt;/body&gt;&nbsp;&nbsp;</span></li><li><span>&lt;/html:html&gt;&nbsp;&nbsp;</span></li></ol></div> <p>&nbsp;3.点击登录后，调用LoginAction.java</p> <div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://sunxboy.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>/*&nbsp;</span></li><li><span>&nbsp;*&nbsp;Generated&nbsp;by&nbsp;MyEclipse&nbsp;Struts&nbsp;</span></li><li><span>&nbsp;*&nbsp;Template&nbsp;path:&nbsp;templates/java/JavaClass.vtl&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>package&nbsp;com.sunsoft.struts.action;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;java.math.BigInteger;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;javax.servlet.http.HttpServletRequest;&nbsp;&nbsp;</span></li><li><span>import&nbsp;javax.servlet.http.HttpServletResponse;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;org.apache.struts.action.Action;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.struts.action.ActionForm;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.struts.action.ActionForward;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.struts.action.ActionMapping;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;com.sunsoft.struts.util.RSAUtil;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>/**&nbsp;&nbsp;</span></li><li><span>&nbsp;*&nbsp;MyEclipse&nbsp;Struts&nbsp;</span></li><li><span>&nbsp;*&nbsp;Creation&nbsp;date:&nbsp;06-28-2008&nbsp;</span></li><li><span>&nbsp;*&nbsp;&nbsp;</span></li><li><span>&nbsp;*&nbsp;XDoclet&nbsp;definition:&nbsp;</span></li><li><span>&nbsp;*&nbsp;@struts.action&nbsp;path="/login"&nbsp;name="loginForm"&nbsp;input="/login.jsp"&nbsp;scope="request"&nbsp;validate="true"&nbsp;</span></li><li><span>&nbsp;*&nbsp;@struts.action-forward&nbsp;name="error"&nbsp;path="/error.jsp"&nbsp;</span></li><li><span>&nbsp;*&nbsp;@struts.action-forward&nbsp;name="success"&nbsp;path="/success.jsp"&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>public&nbsp;class&nbsp;LoginAction&nbsp;extends&nbsp;Action&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Generated&nbsp;Methods&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Method&nbsp;execute&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;mapping&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;form&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;request&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;response&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;ActionForward&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;ActionForward&nbsp;execute(ActionMapping&nbsp;mapping,&nbsp;ActionForm&nbsp;form,&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpServletRequest&nbsp;request,&nbsp;HttpServletResponse&nbsp;response)&nbsp;<span>throws&nbsp;Exception{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//LoginForm&nbsp;loginForm&nbsp;=&nbsp;(LoginForm)&nbsp;form;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;result&nbsp;=&nbsp;request.getParameter(<span>"result");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"原文加密后为：");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(result);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>byte[]&nbsp;en_result&nbsp;=&nbsp;new&nbsp;BigInteger(result,&nbsp;16).toByteArray();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"转成byte[]"+new&nbsp;String(en_result));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>byte[]&nbsp;de_result&nbsp;=&nbsp;RSAUtil.decrypt(RSAUtil.getKeyPair().getPrivate(),en_result);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"还原密文：");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>new&nbsp;String(de_result));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;sb&nbsp;=&nbsp;<span>new&nbsp;StringBuffer();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(<span>new&nbsp;String(de_result));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(sb.reverse().toString());&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;mapping.findForward("success");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p>&nbsp;因为发现解出的明文是倒序的，后面就用StringBuffer的reverse()来转换了一下。</p> <p>4。login.jsp所调用的js</p> <p>&nbsp;</p>   </div>       <div>                     <ul><li><a href="http://dl.iteye.com/topics/download/c79f05d8-3f1c-3ee6-9c1e-f19223adaca6">js.rar</a> (6.4 KB)</li><li>描述: login.jsp所调用的javascript,有： RSA.js BigInt.js Barrett.js</li><li>下载次数: 1759</li></ul>                    </div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/425175.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-05-19 18:02 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/05/19/425175.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>javacc 相关博客资料</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/04/27/424706.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 27 Apr 2015 09:28:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/04/27/424706.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/424706.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/04/27/424706.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/424706.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/424706.html</trackback:ping><description><![CDATA[<div>http://www.cnblogs.com/ronaldHU/p/3164899.html</div><br /><div>http://blog.csdn.net/zyb243380456/article/details/7242796</div><br /><div>http://blog.csdn.net/zyb243380456/article/details/7249315</div><br /><div>http://blog.csdn.net/zyb243380456/article/details/7240225</div><br /><br /><div><strong>http://blog.csdn.net/zyb243380456/article/category/1054037/1</strong></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/424706.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-04-27 17:28 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/04/27/424706.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>simHash 简介以及java实现</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/04/17/424493.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Fri, 17 Apr 2015 06:43:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/04/17/424493.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/424493.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/04/17/424493.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/424493.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/424493.html</trackback:ping><description><![CDATA[<div>http://gemantic.iteye.com/blog/1701101</div>文本去重算法还有<div>cos或者MinHash算法</div><br /><br /><br /><div><p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">传统的<span style="font-family: Times New Roman;">hash</span> <span>算法只负责将原始内容尽量均匀随机地映射为一个签名值，原理上相当于伪随机数产生算法。产生的两个签名，如果相等，说明原始内容在一定概 率&nbsp;下是相等的；如果不相等，除了说明原始内容不相等外，不再提供任何信息，因为即使原始内容只相差一个字节，所产生的签名也很可能差别极大。从这个意义 上来&nbsp;说，要设计一个</span> <span style="font-family: Times New Roman;">hash</span> 算法，对相似的内容产生的签名也相近，是更为艰难的任务，因为它的签名值除了提供原始内容是否相等的信息外，还能额外提供不相等的&nbsp;原始内容的差异程度的信息。 </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">而<span style="font-family: Times New Roman;">Google</span> 的 <span style="font-family: Times New Roman;">simhash</span> 算法产生的签名，可以用来比较原始内容的相似度时，便很想了解这种神奇的算法的原理。出人意料，这个算法并不深奥，其思想是非常清澈美妙的。 </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-weight: bold; font-size: 14pt; font-family: 'Times New Roman';">Simhash算法 </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">simhash算法的输入是一个向量，输出是一个 <span style="font-family: Times New Roman;">f</span> 位的签名值。为了陈述方便，假设输入的是一个文档的特征集合，每个特征有一定的权重。比如特征可以是文档中的词，其权重可以是这个词出现的次数。 <span style="font-family: Times New Roman;">simhash</span> 算法如下： </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">1，将一个 <span style="font-family: Times New Roman;">f</span> 维的向量 <span style="font-family: Times New Roman;">V</span> 初始化为 <span style="font-family: Times New Roman;">0</span> ； <span style="font-family: Times New Roman;">f</span> 位的二进制数 <span style="font-family: Times New Roman;">S</span> 初始化为 <span style="font-family: Times New Roman;">0</span> ； </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">2，对每一个特征：用传统的 <span style="font-family: Times New Roman;">hash</span> 算法对该特征产生一个 <span style="font-family: Times New Roman;">f</span> 位的签名 <span style="font-family: Times New Roman;">b</span> 。对 <span style="font-family: Times New Roman;">i=1</span> 到 <span style="font-family: Times New Roman;">f</span> ： </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">如果<span style="font-family: Times New Roman;">b</span> 的第 <span style="font-family: Times New Roman;">i</span> 位为 <span style="font-family: Times New Roman;">1</span> ，则 <span style="font-family: Times New Roman;">V</span> 的第 <span style="font-family: Times New Roman;">i</span> 个元素加上该特征的权重； </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">否则，<span style="font-family: Times New Roman;">V</span> 的第 <span style="font-family: Times New Roman;">i</span> 个元素减去该特征的权重。&nbsp; </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">3，如果 <span style="font-family: Times New Roman;">V</span> 的第 <span style="font-family: Times New Roman;">i</span> 个元素大于 <span style="font-family: Times New Roman;">0</span> ，则 <span style="font-family: Times New Roman;">S</span> 的第 <span style="font-family: Times New Roman;">i</span> 位为 <span style="font-family: Times New Roman;">1</span> ，否则为 <span style="font-family: Times New Roman;">0</span> ； </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">4，输出 <span style="font-family: Times New Roman;">S</span> 作为签名。 </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><img alt="" src="http://gemantic.iteye.com/admin/blogs/1701101/D:%5Ca.jpg" /></p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><img title="点击查看原始大小图片" alt="" src="http://static.oschina.net/uploads/space/2012/0625/213650_tIkA_576409.jpg" height="446" width="700" /></p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><img alt="" /></p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><img alt="" /></p> <p style="margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-weight: bold; font-size: 14pt; font-family: 'Times New Roman';">算法几何意义和原理</span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">这个算法的几何意义非常明了。它首先将每一个特征映射为<span style="font-family: Times New Roman;">f</span> 维空间的一个向量，这个映射规则具体是怎样并不重要，只要对很多不同的特征来说，它们对所对应的&nbsp;向量是均匀随机分布的，并且对相同的特征来说对应的向量是唯一的就行。比如一个特征的 <span style="font-family: Times New Roman;">4</span> 位 <span style="font-family: Times New Roman;">hash</span> 签名的二进制表示为 <span style="font-family: Times New Roman;">1010</span> ，那么这个特征对应的&nbsp; <span style="font-family: Times New Roman;">4</span> 维向量就是 <span style="font-family: Times New Roman;">(1,&nbsp;-1,&nbsp;1,&nbsp;-1)</span> </span> <span style="font-size: 10.5pt; vertical-align: super; font-family: 'Times New Roman';">T</span> <span style="font-size: 10.5pt; font-family: 'Times New Roman';">，即<span style="font-family: Times New Roman;">hash</span> 签名的某一位为 <span style="font-family: Times New Roman;">1</span> ，映射到的向量的对应位就为 <span style="font-family: Times New Roman;">1</span> ，否则为 <span style="font-family: Times New Roman;">-1</span> 。然后，将一个文档中所包含的各个特征对应的向量加权求和，&nbsp;加权的系数等于该特征的权重。 </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">得到的和向量即表征了这个文档，我们可以用向量之间的夹角来衡量对应文档之间的相似度。最后，为了得到一个 <span style="font-family: Times New Roman;">f</span> 位的签名，需要&nbsp;进一步将其压缩，如果和向量的某一维大于 <span style="font-family: Times New Roman;">0</span> ，则最终签名的对应位为 <span style="font-family: Times New Roman;">1</span> ，否则为 <span style="font-family: Times New Roman;">0</span> 。这样的压缩相当于只留下了和向量所在的象限这个信息，而 <span style="font-family: Times New Roman;">64</span> 位的签名可以&nbsp;表示多达 <span style="font-family: Times New Roman;">2</span> </span> <span style="font-size: 10.5pt; vertical-align: super; font-family: 'Times New Roman';">64</span> <span style="font-size: 10.5pt; font-family: 'Times New Roman';">个象限，因此只保存所在象限的信息也足够表征一个文档了。</span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-weight: bold; font-size: 14pt; font-family: '宋体';">比较相似度</span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: '宋体';">海明距离：</span> <span style="font-size: 10.5pt; font-family: 'Times New Roman';">两个码字的对应比特取值不同的比特数称为这两个码字的海明距离。一个有效编码集中<span style="font-family: Times New Roman;">,</span> 任意两个码字的海明距离的最小值称为该编码集的海明距离。举例如下： <span style="font-family: Times New Roman;">10101</span> 和 <span style="font-family: Times New Roman;">00110</span> 从第一位开始依次有第一位、第四、第五位不同，则海明距离为 <span style="font-family: Times New Roman;">3.</span> </span> </p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: '宋体';">异或：</span> <span style="font-size: 10.5pt; font-family: 'Times New Roman';">只有在两个比较的位不同时其结果是<span style="font-family: Times New Roman;">1</span> ，否则结果为 <span style="font-family: Times New Roman;">0&nbsp;</span> </span> </p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">&nbsp;&nbsp;对每篇文档根据<span style="font-family: Times New Roman;">SimHash</span> 算出签名后，再计算两个签名的海明距离（两个二进制异或后 <span style="font-family: Times New Roman;">1</span> 的个数）即可。根据经验值，对 <span style="font-family: Times New Roman;">64</span> 位的 <span style="font-family: Times New Roman;">SimHash</span> ，海明距离在 <span style="font-family: Times New Roman;">3</span> 以内的可以认为相似度比较高。 </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">假设对<span style="font-family: Times New Roman;">64</span> 位的 <span style="font-family: Times New Roman;">SimHash</span> ，我们要找海明距离在 <span style="font-family: Times New Roman;">3</span> 以内的所有签名。我们可以把 <span style="font-family: Times New Roman;">64</span> 位的二进制签名均分成 <span style="font-family: Times New Roman;">4</span> 块，每块 <span style="font-family: Times New Roman;">16</span> 位。根据鸽巢原理（也成抽屉原理，见组合数学），如果两个签名的海明距离在 <span style="font-family: Times New Roman;">3</span> 以内，它们必有一块完全相同。 </span> </p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">我们把上面分成的<span style="font-family: Times New Roman;">4</span> 块中的每一个块分别作为前 <span style="font-family: Times New Roman;">16</span> 位来进行查找。 </span> <span style="font-size: 10.5pt; font-family: '宋体';">建立倒排索引。</span> </p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><img alt="" /></p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><img alt="" /></p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><img title="点击查看原始大小图片" alt="" src="http://static.oschina.net/uploads/space/2012/0625/213706_xhQG_576409.jpg" height="463" width="700" /></p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: 'Times New Roman';">如果库中有<span style="font-family: Times New Roman;">2^34</span> 个（大概 <span style="font-family: Times New Roman;">10</span> 亿）签名，那么匹配上每个块的结果最多有 <span style="font-family: Times New Roman;">2^(34-16)=262144</span> 个候选结果 </span> <span style="font-size: 10.5pt; font-family: '宋体';">(假设数据是均匀分布， <span style="font-family: Times New Roman;">16</span> 位的数据，产生的像限为 <span style="font-family: Times New Roman;">2^16</span> 个，则平均每个像限分布的文档数则 <span style="font-family: Times New Roman;">2^34/2^16&nbsp;=&nbsp;2^(34-16))</span> </span> <span style="font-size: 10.5pt; font-family: 'Times New Roman';">，四个块返回的总结果数为&nbsp;<span style="font-family: Times New Roman;">4*&nbsp;262144</span> （大概 <span style="font-family: Times New Roman;">100</span> 万）。原本需要比较 <span style="font-family: Times New Roman;">10</span> 亿次，经过索引，大概就只需要处理 <span style="font-family: Times New Roman;">100</span> 万次了。由此可见，确实大大减少了计算量。&nbsp; </span> </p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: '宋体';">Java&nbsp;代码实现： </span> </p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://gemantic.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>package&nbsp;com.gemantic.nlp.commons.simhash;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;java.math.BigInteger;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.util.ArrayList;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.util.List;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.util.StringTokenizer;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>public&nbsp;class&nbsp;SimHash&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;String&nbsp;tokens;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;BigInteger&nbsp;intSimHash;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;String&nbsp;strSimHash;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;int&nbsp;hashbits&nbsp;=&nbsp;64;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;SimHash(String&nbsp;tokens)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.tokens&nbsp;=&nbsp;tokens;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.intSimHash&nbsp;=&nbsp;this.simHash();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;SimHash(String&nbsp;tokens,&nbsp;int&nbsp;hashbits)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.tokens&nbsp;=&nbsp;tokens;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.hashbits&nbsp;=&nbsp;hashbits;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.intSimHash&nbsp;=&nbsp;this.simHash();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;BigInteger&nbsp;simHash()&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int[]&nbsp;v&nbsp;=&nbsp;new&nbsp;int[this.hashbits];&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringTokenizer&nbsp;stringTokens&nbsp;=&nbsp;<span>new&nbsp;StringTokenizer(this.tokens);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>while&nbsp;(stringTokens.hasMoreTokens())&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;temp&nbsp;=&nbsp;stringTokens.nextToken();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigInteger&nbsp;t&nbsp;=&nbsp;<span>this.hash(temp);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;this.hashbits;&nbsp;i++)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigInteger&nbsp;bitmask&nbsp;=&nbsp;<span>new&nbsp;BigInteger("1").shiftLeft(i);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(t.and(bitmask).signum()&nbsp;!=&nbsp;0)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v[i]&nbsp;+=&nbsp;<span>1;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>else&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;v[i]&nbsp;-=&nbsp;<span>1;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigInteger&nbsp;fingerprint&nbsp;=&nbsp;<span>new&nbsp;BigInteger("0");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;simHashBuffer&nbsp;=&nbsp;<span>new&nbsp;StringBuffer();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;this.hashbits;&nbsp;i++)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(v[i]&nbsp;&gt;=&nbsp;0)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fingerprint&nbsp;=&nbsp;fingerprint.add(<span>new&nbsp;BigInteger("1").shiftLeft(i));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;simHashBuffer.append(<span>"1");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span>else{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;simHashBuffer.append(<span>"0");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>this.strSimHash&nbsp;=&nbsp;simHashBuffer.toString();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>this.strSimHash&nbsp;+&nbsp;"&nbsp;length&nbsp;"&nbsp;+&nbsp;this.strSimHash.length());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;fingerprint;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>private&nbsp;BigInteger&nbsp;hash(String&nbsp;source)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(source&nbsp;==&nbsp;null&nbsp;||&nbsp;source.length()&nbsp;==&nbsp;0)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;new&nbsp;BigInteger("0");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>else&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>char[]&nbsp;sourceArray&nbsp;=&nbsp;source.toCharArray();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigInteger&nbsp;x&nbsp;=&nbsp;BigInteger.valueOf(((<span>long)&nbsp;sourceArray[0])&nbsp;&lt;&lt;&nbsp;7);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigInteger&nbsp;m&nbsp;=&nbsp;<span>new&nbsp;BigInteger("1000003");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigInteger&nbsp;mask&nbsp;=&nbsp;<span>new&nbsp;BigInteger("2").pow(this.hashbits).subtract(&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>new&nbsp;BigInteger("1"));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(char&nbsp;item&nbsp;:&nbsp;sourceArray)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigInteger&nbsp;temp&nbsp;=&nbsp;BigInteger.valueOf((<span>long)&nbsp;item);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;x.multiply(m).xor(temp).and(mask);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;x.xor(<span>new&nbsp;BigInteger(String.valueOf(source.length())));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(x.equals(new&nbsp;BigInteger("-1")))&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;<span>new&nbsp;BigInteger("-2");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;x;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;取两个二进制的异或，统计为1的个数，就是海明距离&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;other&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;int&nbsp;hammingDistance(SimHash&nbsp;other)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigInteger&nbsp;x&nbsp;=&nbsp;<span>this.intSimHash.xor(other.intSimHash);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;tot&nbsp;=&nbsp;0;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//统计x中二进制位数为1的个数&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//我们想想，一个二进制数减去1，那么，从最后那个1（包括那个1）后面的数字全都反了，对吧，然后，n&amp;(n-1)就相当于把后面的数字清0，&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//我们看n能做多少次这样的操作就OK了。&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>while&nbsp;(x.signum()&nbsp;!=&nbsp;0)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tot&nbsp;+=&nbsp;<span>1;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x&nbsp;=&nbsp;x.and(x.subtract(<span>new&nbsp;BigInteger("1")));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;tot;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;calculate&nbsp;Hamming&nbsp;Distance&nbsp;between&nbsp;two&nbsp;strings&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&nbsp;二进制怕有错，当成字符串，作一个，比较下结果&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@author&nbsp;&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;str1&nbsp;the&nbsp;1st&nbsp;string&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;str2&nbsp;the&nbsp;2nd&nbsp;string&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;Hamming&nbsp;Distance&nbsp;between&nbsp;str1&nbsp;and&nbsp;str2&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;int&nbsp;getDistance(String&nbsp;str1,&nbsp;String&nbsp;str2)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;distance;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(str1.length()&nbsp;!=&nbsp;str2.length())&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;distance&nbsp;=&nbsp;-<span>1;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>else&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;distance&nbsp;=&nbsp;<span>0;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;str1.length();&nbsp;i++)&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(str1.charAt(i)&nbsp;!=&nbsp;str2.charAt(i))&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;distance++;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;distance;&nbsp;&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;如果海明距离取3，则分成四块，并得到每一块的bigInteger值&nbsp;，作为索引值使用&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;simHash&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;distance&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;List&lt;BigInteger&gt;&nbsp;subByDistance(SimHash&nbsp;simHash,&nbsp;int&nbsp;distance){&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;numEach&nbsp;=&nbsp;this.hashbits/(distance+1);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&lt;BigInteger&gt;&nbsp;characters&nbsp;=&nbsp;<span>new&nbsp;ArrayList();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;buffer&nbsp;=&nbsp;<span>new&nbsp;StringBuffer();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;k&nbsp;=&nbsp;0;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for(&nbsp;int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;this.intSimHash.bitLength();&nbsp;i++){&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>boolean&nbsp;sr&nbsp;=&nbsp;simHash.intSimHash.testBit(i);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if(sr){&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer.append(<span>"1");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>else{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer.append(<span>"0");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if(&nbsp;(i+1)%numEach&nbsp;==&nbsp;0&nbsp;){&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BigInteger&nbsp;eachValue&nbsp;=&nbsp;<span>new&nbsp;BigInteger(buffer.toString(),2);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"----"&nbsp;+eachValue&nbsp;);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer.delete(<span>0,&nbsp;buffer.length());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;characters.add(eachValue);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;characters;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;s&nbsp;=&nbsp;<span>"This&nbsp;is&nbsp;a&nbsp;test&nbsp;string&nbsp;for&nbsp;testing";&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SimHash&nbsp;hash1&nbsp;=&nbsp;<span>new&nbsp;SimHash(s,&nbsp;64);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(hash1.intSimHash&nbsp;+&nbsp;<span>"&nbsp;&nbsp;"&nbsp;+&nbsp;hash1.intSimHash.bitLength());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hash1.subByDistance(hash1,&nbsp;<span>3);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"\n");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;<span>"This&nbsp;is&nbsp;a&nbsp;test&nbsp;string&nbsp;for&nbsp;testing,&nbsp;This&nbsp;is&nbsp;a&nbsp;test&nbsp;string&nbsp;for&nbsp;testing&nbsp;abcdef";&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SimHash&nbsp;hash2&nbsp;=&nbsp;<span>new&nbsp;SimHash(s,&nbsp;64);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(hash2.intSimHash+&nbsp;<span>"&nbsp;&nbsp;"&nbsp;+&nbsp;hash2.intSimHash.bitCount());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hash1.subByDistance(hash2,&nbsp;<span>3);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;=&nbsp;<span>"This&nbsp;is&nbsp;a&nbsp;test&nbsp;string&nbsp;for&nbsp;testing&nbsp;als";&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SimHash&nbsp;hash3&nbsp;=&nbsp;<span>new&nbsp;SimHash(s,&nbsp;64);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(hash3.intSimHash+&nbsp;<span>"&nbsp;&nbsp;"&nbsp;+&nbsp;hash3.intSimHash.bitCount());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hash1.subByDistance(hash3,&nbsp;<span>3);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span>"============================");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;dis&nbsp;=&nbsp;hash1.getDistance(hash1.strSimHash,hash2.strSimHash);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(hash1.hammingDistance(hash2)&nbsp;+&nbsp;<span>"&nbsp;"+&nbsp;dis);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;dis2&nbsp;=&nbsp;hash1.getDistance(hash1.strSimHash,hash3.strSimHash);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(hash1.hammingDistance(hash3)&nbsp;+&nbsp;<span>"&nbsp;"&nbsp;+&nbsp;dis2);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> &nbsp; <p style="text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <br /><p style="margin-left: 21pt; text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-left: 21pt; text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-left: 21pt; text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p> <p style="margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 10.5pt; font-family: '宋体';">参考：</span> &nbsp; <a href="http://blog.sina.com.cn/s/blog_72995dcc010145ti.html"><span style="text-decoration: underline; font-size: 10.5pt; font-family: '宋体'; color: #0000ff;">http://blog.sina.com.cn/s/blog_72995dcc010145ti.html </span></a>  </p> <p style="margin-left: 21pt; text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><a href="http://blog.sina.com.cn/s/blog_56d8ea900100y41b.html"><span style="text-decoration: underline; font-size: 10.5pt; font-family: '宋体'; color: #0000ff;">http://blog.sina.com.cn/s/blog_56d8ea900100y41b.html </span></a>  </p> <p style="margin-left: 21pt; text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;"><a href="http://blog.csdn.net/meijia_tts/article/details/7928579"><span style="text-decoration: underline; font-size: 10.5pt; font-family: '宋体'; color: #0000ff;">http://blog.csdn.net/meijia_tts/article/details/7928579 </span></a>  </p> <p style="margin-left: 21pt; text-indent: 21pt; margin-bottom: 0pt; margin-top: 0pt;">&nbsp;</p></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/424493.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-04-17 14:43 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/04/17/424493.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>springmvc StringHttpMessageConverter 中文乱码的几种解决办法</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/04/09/424253.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Thu, 09 Apr 2015 09:05:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/04/09/424253.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/424253.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/04/09/424253.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/424253.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/424253.html</trackback:ping><description><![CDATA[<div>http://wxynxyo.iteye.com/blog/2000327</div><br /><div>使用spingmvc，在JS里面通过ajax发送请求，并返回json格式的数据，从数据库拿出来是正确的中文格式，展示在页面上就是错误的？？，研究了一下，有几种解决办法。 <br /> <br />&nbsp; 我使用的是sping-web-3.2.2,jar <br /> <br />&nbsp; 方法一： <br /> <br />&nbsp; 在@RequestMapping里面加入produces = "text/html;charset=UTF-8" <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://wxynxyo.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>@RequestMapping(value&nbsp;=&nbsp;"/configrole",&nbsp;method&nbsp;=&nbsp;RequestMethod.GET,&nbsp;produces&nbsp;=&nbsp;"text/html;charset=UTF-8")&nbsp;&nbsp;</span></li><li><span>public&nbsp;@ResponseBody&nbsp;String&nbsp;configrole()&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;......&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <br /> <br /> 方法二： <br /> <br /> 因为在StringHttpMessageConverter里面默认设置了字符集是ISO-8859-1 <br /> <br /> 所以拿到源代码，修改成UTF-8并打包到spring-web-3.2.2.jar <br /> <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://wxynxyo.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>public&nbsp;class&nbsp;StringHttpMessageConverter&nbsp;extends&nbsp;AbstractHttpMessageConverter&lt;String&gt;&nbsp;&nbsp;</span></li><li>{&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>public&nbsp;static&nbsp;final&nbsp;Charset&nbsp;DEFAULT_CHARSET&nbsp;=&nbsp;Charset.forName("UTF-8");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;..........&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;</li></ol></div> <br /> <br /> 方法三： <br /> <br /> 修改org.springframework.http.MediaType它的构造方法的参数，并在applicationContext-mvc.xml 加入配置 <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://wxynxyo.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>public&nbsp;MediaType(String&nbsp;type,&nbsp;String&nbsp;subtype,&nbsp;Charset&nbsp;charset)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>super(type,&nbsp;subtype,&nbsp;charset);&nbsp;&nbsp;</span></li><li>}&nbsp;&nbsp;</li></ol></div> <br /> <br /><div id=""><div><div>Xml代码 &nbsp;<a title="收藏这段代码"><img src="http://wxynxyo.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>&lt;bean&nbsp;id="stringHttpMessageConverter"&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>class="org.springframework.http.converter.StringHttpMessageConverter"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;property&nbsp;name="supportedMediaTypes"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;list&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;bean&nbsp;class="org.springframework.http.MediaType"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;constructor-arg&nbsp;value="text"&nbsp;/&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;constructor-arg&nbsp;value="plain"&nbsp;/&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;constructor-arg&nbsp;value="UTF-8"&nbsp;/&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;/bean&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;/list&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>&lt;/property&gt;&nbsp;&nbsp;</span></li><li><span>&lt;/bean&gt;&nbsp;&nbsp;</span></li></ol></div> <br /> <br />方法四： <br /> <br />&nbsp; 直接将org.springframework.http.converter.StringHttpMessageConverter 里面的属性defaultCharset设置成utf-8 <br /><div id=""><div><div>Xml代码 &nbsp;<a title="收藏这段代码"><img src="http://wxynxyo.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>&lt;bean&nbsp;id="stringHttpMessageConverter"&nbsp;class="org.springframework.http.converter.StringHttpMessageConverter"&gt;&nbsp;&nbsp;</span></li><li><span><div><span style="color: red;">&lt;constructor-arg value="UTF-8" /&gt;</span></div></span></li><li><span>&lt;/bean&gt;&nbsp;&nbsp;</span></li></ol></div> <br /> </div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/424253.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-04-09 17:05 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/04/09/424253.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>springmvc velocity 国际化</title><link>http://www.blogjava.net/wangxinsh55/archive/2015/03/26/423858.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Thu, 26 Mar 2015 08:08:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2015/03/26/423858.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/423858.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2015/03/26/423858.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/423858.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/423858.html</trackback:ping><description><![CDATA[<div>原文地址：http://www.cnblogs.com/liukemng/p/3750117.html</div>
<br /><div><span style="color: red;">用Spring做国际化时经常会报： </span><br /><span style="color: red;">org.springframework.context.NoS&nbsp;hMessageException:&nbsp;No&nbsp;message&nbsp;found&nbsp;under&nbsp;code&nbsp;'title'&nbsp;for&nbsp;locale&nbsp;'zh_CN'.&nbsp;这样的错误。请注意以下几点： </span><br /><span style="color: red;">&#9312;新建资源文件时,尽量右击项目新建文件,来增加. </span><br /><span style="color: red;">&#9313;&nbsp;属性文件名的写法： </span><br /><span style="color: red;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;messages_zh_CN.properties&nbsp;&nbsp;(中文)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;messages_en_US.properties&nbsp;&nbsp;（英文） </span><br /><span style="color: red;">&#9314;&nbsp;配置messageSource这个bean（注意：一定是messageSource不是messageResource&nbsp;,这是Spring规定的）例如: </span><br /><span style="color: red;">&lt;beanid="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"&gt;&nbsp;&nbsp;&nbsp;&lt;propertyname="basename"&gt;&nbsp;&nbsp;&nbsp; </span><br /><span style="color: red;">&lt;val&gt;messages&lt;/val&gt; </span><br /><span style="color: red;">&lt;/property&gt; </span><br /><span style="color: red;">&lt;/bean&gt; </span><br />&nbsp;<br /></div><br /><spring:message code="money"><spring:message code="date"><bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"><spring:message code="money"><spring:message code="date"><bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"><bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"><bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"><bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"><bean id="localeResolver" class="xx.xxx.xxx.MyAcceptHeaderLocaleResolver"></bean></bean></bean></bean></bean></spring:message></spring:message></bean></spring:message></spring:message><img src ="http://www.blogjava.net/wangxinsh55/aggbug/423858.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2015-03-26 16:08 <a href="http://www.blogjava.net/wangxinsh55/archive/2015/03/26/423858.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDK8 的 Lambda 表达式 -- 方法引用</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/12/25/421826.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Thu, 25 Dec 2014 08:08:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/12/25/421826.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/421826.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/12/25/421826.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/421826.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/421826.html</trackback:ping><description><![CDATA[<div>http://unmi.cc/jdk8-lambda-method-references/</div><br /><div><p>Lambda 允许我们定义匿名方法(即那个 Lambda 表达式，或叫闭包)，作为一个功能性接口的实例。如果你不想把一个 Lambda  表达式写得过大，那么你可以把表达式的内容分离出来写在一个方法中，然后在放置 Lambda 表达式的位置上填上对那个方法的引用。</p> <p>方法引用也应看作是一个 Lambda 表达式，所以它也需要一个明确的目标类型充当功能性接口的实例。简单说就是被引用的方法要与功能接口的  SAM(Single Abstract Method) 参数、返回类型相匹配。方法引用的引入避免了 Lambda  写复杂了可读性的问题，也使得逻辑更清晰。</p> <p>为了应对方法引用这一概念， JDK8 又重新借用了 C++ 的那个 &#8220;::&#8221; 域操作符，全称为作用域解析操作符。</p> <p>上面的表述也许不好明白，我看官方的那份 State of the Lambda 也觉得不怎么容易理解，特别是它举了那个例子很难让人望文生意。我用个自己写的例子来说明一下吧。</p> <p>目前的 Eclipse-JDK8 版还不能支持方法引用的特性，幸好就是在昨天正式版的 NetBeans IDE 7.4 对 JDK8 有了较好的支持，所以在 NetBeans 7.4 中写测试代码。</p> <div><div id="highlighter_945863" code_border=""  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">01</div><div number2="" index1=""  alt1"="">02</div><div number3="" index2=""  alt2"="">03</div><div number4="" index3=""  alt1"="">04</div><div number5="" index4=""  alt2"="">05</div><div number6="" index5=""  alt1"="">06</div><div number7="" index6=""  alt2"="">07</div><div number8="" index7=""  alt1"="">08</div><div number9="" index8=""  alt2"="">09</div><div number10="" index9=""  alt1"="">10</div><div number11="" index10=""  alt2"="">11</div><div number12="" index11=""  alt1"="">12</div><div number13="" index12=""  alt2"="">13</div><div number14="" index13=""  alt1"="">14</div><div number15="" index14=""  alt2"="">15</div><div number16="" index15=""  alt1"="">16</div><div number17="" index16=""  alt2"="">17</div><div number18="" index17=""  alt1"="">18</div><div number19="" index18=""  alt2"="">19</div><div number20="" index19=""  alt1"="">20</div><div number21="" index20=""  alt2"="">21</div><div number22="" index21=""  alt1"="">22</div><div number23="" index22=""  alt2"="">23</div><div number24="" index23=""  alt1"="">24</div><div number25="" index24=""  alt2"="">25</div><div number26="" index25=""  alt1"="">26</div><div number27="" index26=""  alt2"="">27</div><div number28="" index27=""  alt1"="">28</div><div number29="" index28=""  alt2"="">29</div><div number30="" index29=""  alt1"="">30</div><div number31="" index30=""  alt2"="">31</div><div number32="" index31=""  alt1"="">32</div><div number33="" index32=""  alt2"="">33</div><div number34="" index33=""  alt1"="">34</div><div number35="" index34=""  alt2"="">35</div><div number36="" index35=""  alt1"="">36</div></td><td><div><div number1="" index0=""  alt2"=""><code keyword"="">package</code> <code plain"="">testjdk8;</code></div><div number2="" index1=""  alt1"="">&nbsp;</div><div number3="" index2=""  alt2"=""><code preprocessor"="">/**</code></div><div number4="" index3=""  alt1"=""><code spaces"="">&nbsp;</code><code preprocessor"="">*</code></div><div number5="" index4=""  alt2"=""><code spaces"="">&nbsp;</code><code preprocessor"="">* @author Unmi</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;</code><code preprocessor"="">*/</code></div><div number7="" index6=""  alt2"=""><code keyword"="">public</code> <code keyword"="">class</code> <code plain"="">TestJdk8 {</code></div><div number8="" index7=""  alt1"="">&nbsp;</div><div number9="" index8=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">public</code> <code keyword"="">static</code> <code keyword"="">void</code> <code plain"="">main(String[] args) {</code></div><div number10="" index9=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">//使用 Lambda 表达式，输出： 16: send email</code></div><div number11="" index10=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">start((id, task) -&gt; id + </code><code string"="">": "</code> <code plain"="">+ task);</code></div><div number12="" index11=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">//或者</code></div><div number13="" index12=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">Machine m1 = (id, task) -&gt; id + </code><code string"="">": "</code> <code plain"="">+ task;</code></div><div number14="" index13=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">m1.doSomething(</code><code value"="">16</code><code plain"="">, </code><code string"="">"send email"</code><code plain"="">);</code></div><div number15="" index14=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code>&nbsp;</div><div number16="" index15=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">//使用方法引用，输出： Hello 16: send email</code></div><div number17="" index16=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">start(TestJdk8::hello);</code></div><div number18="" index17=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">//或者</code></div><div number19="" index18=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">Machine m2 = TestJdk8::hello;</code></div><div number20="" index19=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">m2.doSomething(</code><code value"="">16</code><code plain"="">, </code><code string"="">"send email"</code><code plain"="">);</code></div><div number21="" index20=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div><div number22="" index21=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code>&nbsp;</div><div number23="" index22=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">private</code> <code keyword"="">static</code> <code keyword"="">void</code> <code plain"="">start(Machine machine){</code></div><div number24="" index23=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">String result = machine.doSomething(</code><code value"="">16</code><code plain"="">, </code><code string"="">"send email"</code><code plain"="">);</code></div><div number25="" index24=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">System.out.println(result);</code></div><div number26="" index25=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div><div number27="" index26=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code>&nbsp;</div><div number28="" index27=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">public</code> <code keyword"="">static</code> <code plain"="">String hello(</code><code keyword"="">int</code> <code plain"="">id, String task){</code></div><div number29="" index28=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">return</code> <code string"="">"Hello "</code> <code plain"="">+ id +</code><code string"="">": "</code> <code plain"="">+ task;</code></div><div number30="" index29=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div><div number31="" index30=""  alt2"=""><code plain"="">}</code></div><div number32="" index31=""  alt1"="">&nbsp;</div><div number33="" index32=""  alt2"=""><code color1"="">@FunctionalInterface</code></div><div number34="" index33=""  alt1"=""><code keyword"="">interface</code> <code plain"="">Machine {</code></div><div number35="" index34=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">public</code> <code plain"="">String doSomething(</code><code keyword"="">int</code> <code plain"="">id, String task);</code></div><div number36="" index35=""  alt1"=""><code plain"="">}</code></div></div></td></tr></tbody></table></div></div> <p>说明：</p> <p>1. Machine 是一个功能性接口，它只有一个抽象方法<br /> 2. start(Machine machine) 方法为 Lambda 表达式提供了一个上下文，表明它期盼接收一个 Machine 的功能性接口类型<br /> 3. start((id, task) -&gt; id + ": " + task), 是传递了一个 Lambda 表达式给 start() 方法<br /> 4. start(TestJdk8::hello) 是把指向 TestJdk8::hello 方法的引用传递给了 start() 方法，这里可以理解 hello() 方法是 Lambda 表达式的另一种表现形式。</p> <p>对应一下两个 start() 方法调用的参数，Lambda 表达式的参数列表 (id, task) 与 hello 方法的参数 (int id, String task) 是一致的，返回值类型也是一致的。</p> <p>想像一下如果一个 Lambda 表达式的代码量很大，全部挤在一起作为 start() 方法的参数部分，混乱也不太方便于单步调试。所以可以把  Lambda 的实现挪出来放在一个单独的方法中，在使用处只放置一个对该方法的引用即可。借助于方法引用，JDK8&nbsp; 把方法与 Lambda  表达式巧妙的结合了起来，直接的说 Lambda 表达就是一个方法，它用自己的方法列表和返回值。</p> <p><strong>那么符合什么条件的方法可以作为 Lambda 表达式来用呢</strong>？答：方法签名与功能性接口的 SAM 一致即可。比如，可以进行下面的赋值：</p> <div><div id="highlighter_400481" code_border=""  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">Consumer&lt;Integer&gt; b1 = System::exit </code><code comments"="">//void exit(int status) 与 Consumer 的 SAM void accept(T t) 相匹配</code></div><div number2="" index1=""  alt1"=""><code plain"="">Runnable r = MyProgram::main;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </code><code comments"="">//void main(String... args) 与 run() 方法能配上对</code></div></div></td></tr></tbody></table></div></div>      <p><strong>有些什么样子的方法引用：</strong></p> <ol><li>静态方法 (ClassName::methName)</li><li>对象的实例方法 (instanceRef::methName)</li><li>对象的super 方法 (super::methName)</li><li>类型的实例方法 (ClassName::methName, 引用时和静态方法是一样的，但这里的 methName 是个实例方法)</li><li>类的构造方法 (ClassName::new)</li><li>数组的构造方法 (TypeName[]::new)</li></ol> <p>第 1 条，静态方法以 ClassName 为作用域好理解，第 4 条中实例方法也可以用 ClassName::methName  的方式去引用，那么这里又有个约定了：如果实例方法用类型来引用的时候，那么调用时第一个参数将作为该引用方法的接收者，其余参数依次作为引用方法的参 数。举个例子：</p> <div><div id="highlighter_245358" code_border=""  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">01</div><div number2="" index1=""  alt1"="">02</div><div number3="" index2=""  alt2"="">03</div><div number4="" index3=""  alt1"="">04</div><div number5="" index4=""  alt2"="">05</div><div number6="" index5=""  alt1"="">06</div><div number7="" index6=""  alt2"="">07</div><div number8="" index7=""  alt1"="">08</div><div number9="" index8=""  alt2"="">09</div><div number10="" index9=""  alt1"="">10</div><div number11="" index10=""  alt2"="">11</div><div number12="" index11=""  alt1"="">12</div><div number13="" index12=""  alt2"="">13</div><div number14="" index13=""  alt1"="">14</div><div number15="" index14=""  alt2"="">15</div><div number16="" index15=""  alt1"="">16</div><div number17="" index16=""  alt2"="">17</div><div number18="" index17=""  alt1"="">18</div><div number19="" index18=""  alt2"="">19</div><div number20="" index19=""  alt1"="">20</div><div number21="" index20=""  alt2"="">21</div><div number22="" index21=""  alt1"="">22</div><div number23="" index22=""  alt2"="">23</div><div number24="" index23=""  alt1"="">24</div><div number25="" index24=""  alt2"="">25</div><div number26="" index25=""  alt1"="">26</div><div number27="" index26=""  alt2"="">27</div><div number28="" index27=""  alt1"="">28</div><div number29="" index28=""  alt2"="">29</div></td><td><div><div number1="" index0=""  alt2"=""><code keyword"="">package</code> <code plain"="">testjdk8;</code></div><div number2="" index1=""  alt1"="">&nbsp;</div><div number3="" index2=""  alt2"=""><code keyword"="">import</code> <code plain"="">java.util.function.Function;</code></div><div number4="" index3=""  alt1"="">&nbsp;</div><div number5="" index4=""  alt2"=""><code preprocessor"="">/**</code></div><div number6="" index5=""  alt1"=""><code spaces"="">&nbsp;</code><code preprocessor"="">*</code></div><div number7="" index6=""  alt2"=""><code spaces"="">&nbsp;</code><code preprocessor"="">* @author Unmi</code></div><div number8="" index7=""  alt1"=""><code spaces"="">&nbsp;</code><code preprocessor"="">*/</code></div><div number9="" index8=""  alt2"=""><code keyword"="">public</code> <code keyword"="">class</code> <code plain"="">TestJdk8 {</code></div><div number10="" index9=""  alt1"="">&nbsp;</div><div number11="" index10=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">public</code> <code keyword"="">static</code> <code keyword"="">void</code> <code plain"="">main(String[] args) {</code></div><div number12="" index11=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">Function&lt;String, String&gt; upperfier = String::toUpperCase;</code></div><div number13="" index12=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">System.out.println(upperfier.apply(</code><code string"="">"Hello"</code><code plain"="">)); </code><code comments"="">//HELLO</code></div><div number14="" index13=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code>&nbsp;</div><div number15="" index14=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">Machine m = TestJdk8::hello; </code><code comments"="">//hello 是实例方法</code></div><div number16="" index15=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">TestJdk8 test = </code><code keyword"="">new</code> <code plain"="">TestJdk8();</code></div><div number17="" index16=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code comments"="">//test 作为 hello 方法的接收者，"Unmi" 作为 task 参数</code></div><div number18="" index17=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">System.out.println(m.doSomething(test, </code><code string"="">"Unmi"</code><code plain"="">)); </code><code comments"="">//Hello Unmi</code></div><div number19="" index18=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div><div number20="" index19=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code>&nbsp;</div><div number21="" index20=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">public</code> <code plain"="">String hello(String task){</code></div><div number22="" index21=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">return</code> <code string"="">"Hello "</code> <code plain"="">+ task;</code></div><div number23="" index22=""  alt2"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code plain"="">}</code></div><div number24="" index23=""  alt1"=""><code plain"="">}</code></div><div number25="" index24=""  alt2"="">&nbsp;</div><div number26="" index25=""  alt1"=""><code color1"="">@FunctionalInterface</code></div><div number27="" index26=""  alt2"=""><code keyword"="">interface</code> <code plain"="">Machine {</code></div><div number28="" index27=""  alt1"=""><code spaces"="">&nbsp;&nbsp;&nbsp;&nbsp;</code><code keyword"="">public</code> <code plain"="">String doSomething(TestJdk8 test, String task);</code></div><div number29="" index28=""  alt2"=""><code plain"="">}</code></div></div></td></tr></tbody></table></div></div> <p>上面的代码应该能有助于理解实例方法用类型来引用，如果引用的是泛型方法，类型写在 :: 之前。</p> <p>同样当然对于第 2 条，引用实例方法时，SAM 的第一个参数也作为接收者，其作参数依次填充过去。</p> <p>第 5 条，类的构造方法要用类型去引用，new 相当一个返回当前类型实例的实例方法，所以</p> <div><div id="highlighter_677265" code_border=""  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">SocketImplFactory factory = MySocketImpl::</code><code keyword"="">new</code><code plain"="">;</code></div><div number2="" index1=""  alt1"=""><code plain"="">SocketImpl socketImpl = factory.createSocketImpl();</code></div></div></td></tr></tbody></table></div></div> <p>数组是种类型，可以认为数组的构造方法是只接受一个整形参数，所以能这样引用数组的构造方法：</p> <div><div id="highlighter_585602" code_border=""  java"=""><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td><div number1="" index0=""  alt2"="">1</div><div number2="" index1=""  alt1"="">2</div></td><td><div><div number1="" index0=""  alt2"=""><code plain"="">IntFunction&lt;</code><code keyword"="">int</code><code plain"="">[]&gt; arrayMaker = </code><code keyword"="">int</code><code plain"="">[]::</code><code keyword"="">new</code><code plain"="">;</code></div><div number2="" index1=""  alt1"=""><code keyword"="">int</code><code plain"="">[] array = arrayMaker.apply(</code><code value"="">10</code><code plain"="">);&nbsp; </code><code comments"="">// creates an int[10]</code></div></div></td></tr></tbody></table></div></div> 小结：Lambda 表达式就是一个功能性接口的实例，因而调用方式参照功能性接口。Lambda  表达式可抽取到一个方法中，然后用方法引用指向这个方法，被引用的方法签名与功能性接口的 SAM 的一致性，注意引用实例方法时，SAM  的第一个参数将作为引用方法的接收者。我们把数组理解为有一个接收整数的构造方法。</div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/421826.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-12-25 16:08 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/12/25/421826.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jdk8预览</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/12/25/421825.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Thu, 25 Dec 2014 08:07:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/12/25/421825.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/421825.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/12/25/421825.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/421825.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/421825.html</trackback:ping><description><![CDATA[<div><div>http://blog.csdn.net/goldenfish1919/article/details/11780751</div></div><br /><div>原文：http://www.techempower.com/blog/2013/03/26/everything-about-java-8/<br /> 1.接口增强<br /> （1）接口可以定义static方法<br /> java.util.Comparator：<br /> public static &lt;T extends Comparable&lt;? super T&gt;&gt; Comparator&lt;T&gt; naturalOrder() {<br /> &nbsp; &nbsp; return (Comparator&lt;T&gt;)Comparators.NaturalOrderComparator.INSTANCE;<br /> }<br /> （2）接口可以有default方法<br /> java.lang.Iterable:<br /> public default void forEach(Consumer&lt;? super T&gt; action) {<br /> &nbsp; &nbsp; Objects.requireNonNull(action);<br /> &nbsp; &nbsp; for (T t : this) {<br /> &nbsp; &nbsp; &nbsp; &nbsp; action.accept(t);<br /> &nbsp; &nbsp; }<br /> }<br /> default方法不能够override：toString()、equals()、hashCode()方法。<br /> An interface cannot provide a default implementation for any of the methods of the Object class。<br /> 接口不能够提供Object类里面的方法的default实现。<br /> <br /> <br /> ps：接口看上去越来越像抽象类了。<br /> <br /> <br /> 2.Functional接口<br /> 一个接口只定义了一个abstract方法，这个接口就是&#8220;functional接口&#8221;，比如：java.lang.Runnable。<br /> &#8220;functional接口&#8221;中可以定义default方法<br /> 新引入@FunctionalInterface来标记<br /> <br /> <br /> 3.Lambdas表达式<br /> functional接口可以用Lambdas来实例化。<br /> (int x, int y) -&gt; { return x + y; } ：两个入参，一个返回值<br /> (x, y) -&gt; x + y：两个入参，一个返回值，自动推断类型<br /> x -&gt; x * x：一个入参，一个返回值，自动推断类型<br /> () -&gt; x：没有入参，一个返回值<br /> x -&gt; { System.out.println(x); }：一个入参，没有返回值，自动推断类型<br /> String::valueOf static方法引用<br /> Object::toString &nbsp;非static方法引用<br /> x::toString &nbsp; Capturing method reference<br /> ArrayList::new &nbsp;构造函数引用<br /> 以下是等价的：<br /> 方法引用 &nbsp; &nbsp; &nbsp; &nbsp; 等价的Lambdas表达式<br /> String::valueOf x -&gt; String.valueOf(x)<br /> Object::toString x -&gt; x.toString()<br /> x::toString () -&gt; x.toString()<br /> ArrayList::new () -&gt; new ArrayList&lt;&gt;()<br /> <br /> <br /> ps：看到String::valueOf这种引用方式，不仅让人想起了C++。<br /> <br /> <br /> 如果Lambdas表达式和&#8220;functional接口&#8221;外形相似，二者就可以兼容：<br /> Comparator&lt;String&gt; c = (a, b) -&gt; Integer.compare(a.length(),b.length());<br /> Comparator类的compare()方法接收两个String的入参，返回一个int，跟右边的Lambdas表达式兼容。<br /> 所谓的外形相似就是说：入参、返回、checked异常。<br /> <br /> <br /> Runnable r = () -&gt; { System.out.println("Running!"); }也是ok的。<br /> <br /> <br /> Capturing 与 non-capturing lambdas<br /> 如果一个Lambdas表达式访问了{}范围以外的非static的变量或者对象，那就是个Capturing Lambdas表达式：<br /> int x = 5;<br /> return y -&gt; x + y;<br /> Lambdas表达式captures了变量x，x必须得是&#8220;final等效&#8221;的：要么是final的，要么没有被修改过。<br /> 是否是Capturing Lambdas与性能有关，non-capturing的性能更高，non-capturing只需要被evaluated一次，只有一个instance，<br /> 但是，每次遇到Capturing lambdas都会evaluated，类似于匿名内部类的实例化。<br /> <br /> <br /> 3.新添加包：java.util.function<br /> 这个包下面添加了很多functional接口：<br /> Function&lt;T, R&gt; - take a T as input, return an R as ouput<br /> Predicate&lt;T&gt; - take a T as input, return a boolean as output<br /> Consumer&lt;T&gt; - take a T as input, perform some action and don't return anything<br /> Supplier&lt;T&gt; - with nothing as input, return a T<br /> BinaryOperator&lt;T&gt; - take two T's as input, return one T as output, useful for "reduce" operations<br /> 新添加了对应基本数据类型的功能函数类，比如：<br /> IntConsumer接收int，无返回，主要是为了性能的原因，避免自动拆装箱。<br /> <br /> <br /> 4.新添加包：java.util.stream<br /> java.util.stream这个包主要是为了support functional-style operations on streams of value。<br /> 常见的获取stream的方式是从Collection获取：<br /> Stream&lt;T&gt; stream = collection.stream();<br /> 一个stream就类似于是一个Iterator，只能遍历一次，当然stream也可能是无穷的。<br /> stream可能是串行的也可能是并行的。<br /> stream能做什么呢？<br /> int sumOfWeights = blocks.stream().filter(b -&gt; b.getColor() == RED)<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .mapToInt(b -&gt; b.getWeight())<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .sum();<br /> 以上使用了简单类型的stream，sum()方法只有在简单类型的stream上才有。<br /> stream提供了api用来转换value，或者是对结果做一些操作，对stream的操作可以是&#8220;中间操作&#8221;也可能是&#8220;终止操作&#8221;。<br /> 中间操作：会保持stream处于打开的状态，并允许进一步的操作，上例中的filter()和mapToInt()就是中间操作，返回的还是当前的stream，允许更多的链式操作。<br /> 终止操作：必须是stream上的最后一个操作，一旦被调用，stream就被消费掉，而且不能再使用了。<br /> <br /> <br /> 一般来说，对stream的处理包含三个步骤：<br /> （1）从源处获取stream<br /> （2）做一个或多个中间操作<br /> （3）做一个终止操作<br /> Stream可以是有状态（Stateful）的。<br /> stream是可以短路操作（Short-circuiting）的，比如在处理无穷的stream的时候就需要提前停止。<br /> stream的api方法介绍：<br /> 中间操作：<br /> filter：排除掉所有不满足预定条件的元素<br /> map ：使用Function对元素做一对一的转换<br /> flatMap ：把一个元素映射成0个或者多个元素<br /> distinct ：根据equals方法，排除掉所有的重复元素，这是个stateful的操作。<br /> sorted ：让元素有序，stateful<br /> limit ：让后续的操作只能看到最多limit个元素，stateful并且short-circuiting<br /> substream ：让后续的操作只能看到stream的一部分。<br /> List&lt;String&gt; names = Arrays.asList("Alice", "Bob", "Charlie", "Dave");<br /> List&lt;String&gt; filteredNames = names.stream().filter(e -&gt; e.length() &gt;= 4).collect(Collectors.toList());<br /> for (String name : filteredNames) {<br /> &nbsp; &nbsp; System.out.println(name); &nbsp;//Alice Charlie Dave<br /> }<br /> <br /> <br /> 终止操作：<br /> forEach ：对stream的每一个元素做一些处理<br /> toArray ：把元素导出到数组里面<br /> reduce ：使用BinaryOperator，把多个stream组合成一个<br /> collect ：把元素导出到某个容器里面，比如：collection或者map<br /> min，max ，count ，<br /> anyMatch ：是否至少一个匹配的元素，short-circuiting。<br /> allMatch ：是否所有的元素都匹配，short-circuiting。<br /> noneMatch ：是否所有的元素都不匹配，short-circuiting。<br /> findFirst ：找到第一个匹配的元素，hort-circuiting。<br /> findAny ：找到任何一个匹配的元素，hort-circuiting。<br /> <br /> <br /> 中间操作是延迟（lazy）的。只有终止操作才会触发对stream的处理。在终止操作开始的时候，无论有多少中间操作，&nbsp;<br /> the elements are then consumed in (usually, but not quite always) a single pass.所有的元素都是进行一次性处理，<br /> 有些Stateful操作（sorted(),distinct()）可能会进行第二次处理。<br /> <br /> <br /> 有专门针对基本类型的stream：IntStream，LongStream，DoubleStream<br /> List&lt;String&gt; strings = Arrays.asList("hello", "java", "");<br /> Object[] list = strings.stream() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Stream&lt;String&gt;<br /> &nbsp; &nbsp; &nbsp; &nbsp; .mapToInt(String::length) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // IntStream<br /> &nbsp; &nbsp; &nbsp; &nbsp; .mapToLong(x -&gt; Long.valueOf(x)) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// LongStream<br /> &nbsp; &nbsp; &nbsp; &nbsp; .mapToDouble(x -&gt; x * 2.0) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// DoubleStream<br /> &nbsp; &nbsp; &nbsp; &nbsp; .boxed() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Stream&lt;Double&gt;<br /> &nbsp; &nbsp; &nbsp; &nbsp; .toArray();<br /> System.out.println(java.util.Arrays.toString(list));//[10.0, 8.0, 0.0]<br /> <br /> <br /> <br /> <br /> 5.泛型类型推断增强<br /> java7里面：<br /> foo(Utility.&lt;Type&gt;bar());<br /> Utility.&lt;Type&gt;foo().bar();<br /> 但是java8里面：<br /> foo(Utility.bar());<br /> Utility.foo().bar();<br /> <br /> <br /> 6.新引入java.time包<br /> LocalDateTime：日期+时间<br /> LocalDate：日期<br /> LocalTime：时间<br /> Instant：类似于java.util.Date<br /> DateTimeFormatter：与字符串的转化<br /> 与老的api转化：<br /> Date.toInstant()<br /> Date.from(Instant)<br /> Calendar.toInstant()<br /> <br /> <br /> 7.新添加了Collections API<br /> Iterable.forEach(Consumer)<br /> Iterator.forEachRemaining(Consumer)<br /> Collection.removeIf(Predicate)<br /> Collection.spliterator()<br /> Collection.stream()<br /> Collection.parallelStream()<br /> List.sort(Comparator)<br /> List.replaceAll(UnaryOperator)<br /> Map.forEach(BiConsumer)<br /> Map.replaceAll(BiFunction)<br /> Map.putIfAbsent(K, V)<br /> Map.remove(Object, Object)<br /> Map.replace(K, V, V)<br /> Map.replace(K, V)<br /> Map.computeIfAbsent(K, Function)<br /> Map.computeIfPresent(K, BiFunction)<br /> Map.compute(K, BiFunction)<br /> Map.merge(K, V, BiFunction)<br /> Map.getOrDefault(Object, V)<br /> <br /> <br /> List&lt;String&gt; strings = Arrays.asList("a", "b", "c");<br /> // Index strings by length:<br /> Map&lt;Integer, List&lt;String&gt;&gt; map = new HashMap&lt;&gt;();<br /> for (String s : strings) {<br /> &nbsp; &nbsp; map.computeIfAbsent(s.length(),key -&gt; new ArrayList&lt;String&gt;()).add(s);<br /> }<br /> System.out.println(map);//{1=[a, b, c]}<br /> <br /> <br /> 把stram里面的元素放到colection或者map里面：<br /> List&lt;String&gt; strings = Arrays.asList("a", "b", "c","hello","world");<br /> // Although in this case the stream API may be a better choice:<br /> Map&lt;Integer, List&lt;String&gt;&gt; map = strings.stream().collect(Collectors.groupingBy(String::length));<br /> System.out.println(map);//{1=[a, b, c], 5=[hello, world]}<br /> <br /> <br /> 8.新添加了Concurrency API<br /> ConcurrentHashMap被完全重写<br /> 9.新添加了Concurrency API<br /> 10.反射和注解增强<br /> 注解可以加在泛型参数上： List&lt;@Nullable String&gt;<br /> 11.Nashorn JavaScript Engine<br /> 12.其他的一些api：<br /> Base64<br /> StringJoiner<br /> Objects.isNull(Object)&nbsp;<br /> Objects.nonNull(Object)&nbsp;<br /> ThreadLocal&lt;List&lt;String&gt;&gt; strings = ThreadLocal.withInital(ArrayList::new);<br /> people.sort(<br /> &nbsp; &nbsp; Comparator.comparing(Person::getLastName)<br /> &nbsp; &nbsp; &nbsp; &nbsp; .thenComparing(Person::getFirstName)<br /> &nbsp; &nbsp; &nbsp; &nbsp; .thenComparing(<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Person::getEmailAddress,<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Comparator.nullsLast()<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .thenComparing(String.CASE_INSENSITIVE_ORDER)));<br /> <br /> <br /> 总之一句话，加入了lambda表达式的java越来越像动态语言了，源码也越来越看不懂了，估计得好好的适应一段时间了。  </div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/421825.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-12-25 16:07 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/12/25/421825.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>怎么在hadoop作map/reduce时输出N种不同类型的value</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/11/11/419920.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 11 Nov 2014 06:10:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/11/11/419920.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/419920.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/11/11/419920.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/419920.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/419920.html</trackback:ping><description><![CDATA[<div><div id="blog_content">     <p>BTW:再次感叹下没有机器, 3.4G的语料,单机处理了10来个小时, 真是郁闷~~　要是有N台机器多好啊.</p> <p>&nbsp;</p> <p>在很多时候,特别是处理大数据的时候,我们希望一道MapReduce过程就可以解决几个问题。这样可以避免再次读取数据。比如：在做文本聚类/分 类的时候，mapper读取语料，进行分词后，要同时算出每个词条(term)的term frequency以及它的document  frequency.　前者对于每个词条来说其实是个向量,　它代表此词条在N篇文档各中的词频；而后者就是一个非负整数。  这时候就可以借助一种特殊的Writable类：GenericWritable.</p> <p>&nbsp;</p> <p>用法是：继承这个类，然后把你要输出value的Writable类型加进它的CLASSES静态变量里,在后面的TermMapper和 TermReducer中我的value使用了三种ArrayWritable,IntWritable和我自已定义的TFWritable,所以要把三 者全加入TermWritable的CLASSES中。</p> <div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://coderplay.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>package&nbsp;redpoll.examples;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;org.apache.hadoop.io.GenericWritable;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.io.Writable;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>/**&nbsp;</span></li><li><span>&nbsp;*&nbsp;Generic&nbsp;Writable&nbsp;class&nbsp;for&nbsp;terms.&nbsp;</span></li><li><span>&nbsp;*&nbsp;@author&nbsp;Jeremy&nbsp;Chow(coderplay@gmail.com)&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>public&nbsp;class&nbsp;TermWritable&nbsp;extends&nbsp;GenericWritable&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>private&nbsp;static&nbsp;Class&lt;?&nbsp;extends&nbsp;Writable&gt;[]&nbsp;CLASSES&nbsp;=&nbsp;null;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>static&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;CLASSES&nbsp;=&nbsp;(Class&lt;?&nbsp;<span>extends&nbsp;Writable&gt;[])&nbsp;new&nbsp;Class[]&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.apache.hadoop.io.ArrayWritable.<span>class,&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.apache.hadoop.io.IntWritable.<span>class,&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redpoll.examples.TFWritable.<span>class&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;</li><li>&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>public&nbsp;TermWritable()&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>public&nbsp;TermWritable(Writable&nbsp;instance)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;set(instance);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>@Override&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>protected&nbsp;Class&lt;?&nbsp;extends&nbsp;Writable&gt;[]&nbsp;getTypes()&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;CLASSES;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p>&nbsp;Mapper在collect数据时，用刚才定义的TermWritable来包装(wrap)要使用的Writable类。</p> <div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://coderplay.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>package&nbsp;redpoll.examples;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;java.io.IOException;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.io.StringReader;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;org.apache.commons.logging.Log;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.commons.logging.LogFactory;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.io.IntWritable;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.io.LongWritable;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.io.Text;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.mapred.JobConf;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.mapred.MapReduceBase;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.mapred.Mapper;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.mapred.OutputCollector;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.mapred.Reporter;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.lucene.analysis.Analyzer;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.lucene.analysis.Token;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.lucene.analysis.TokenStream;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.lucene.analysis.standard.StandardAnalyzer;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>/**&nbsp;</span></li><li><span>&nbsp;*&nbsp;A&nbsp;class&nbsp;provides&nbsp;for&nbsp;doing&nbsp;words&nbsp;segmenation&nbsp;and&nbsp;counting&nbsp;term&nbsp;TFs&nbsp;and&nbsp;DFs.&lt;p&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;in:&nbsp;key&nbsp;is&nbsp;document&nbsp;id,&nbsp;value&nbsp;is&nbsp;a&nbsp;document&nbsp;instance.&nbsp;&lt;br&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;output:&nbsp;</span></li><li><span>&nbsp;*&nbsp;&lt;li&gt;key&nbsp;is&nbsp;term,&nbsp;value&nbsp;is&nbsp;a&nbsp;&lt;documentId,&nbsp;tf&gt;&nbsp;pair&lt;/li&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;&lt;li&gt;key&nbsp;is&nbsp;term,&nbsp;value&nbsp;is&nbsp;document&nbsp;frequency&nbsp;corresponsing&nbsp;to&nbsp;the&nbsp;key&lt;/li&gt;&nbsp;</span></li><li><span>&nbsp;*&nbsp;@author&nbsp;Jeremy&nbsp;Chow(coderplay@gmail.com)&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>public&nbsp;class&nbsp;TermMapper&nbsp;extends&nbsp;MapReduceBase&nbsp;implements&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;Mapper&lt;LongWritable,&nbsp;Document,&nbsp;Text,&nbsp;TermWritable&gt;&nbsp;{&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>private&nbsp;static&nbsp;final&nbsp;Log&nbsp;log&nbsp;=&nbsp;LogFactory.getLog(TermMapper.class&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.getName());&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>/*&nbsp;analyzer&nbsp;for&nbsp;words&nbsp;segmentation&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>private&nbsp;Analyzer&nbsp;analyzer&nbsp;=&nbsp;null;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>/*&nbsp;frequency&nbsp;weight&nbsp;for&nbsp;document&nbsp;title&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>private&nbsp;IntWritable&nbsp;titleWeight&nbsp;=&nbsp;new&nbsp;IntWritable(2);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>/*&nbsp;frequency&nbsp;weight&nbsp;for&nbsp;document&nbsp;content&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>private&nbsp;IntWritable&nbsp;contentWeight&nbsp;=&nbsp;new&nbsp;IntWritable(1);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>public&nbsp;void&nbsp;map(LongWritable&nbsp;key,&nbsp;Document&nbsp;value,&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutputCollector&lt;Text,&nbsp;TermWritable&gt;&nbsp;output,&nbsp;Reporter&nbsp;reporter)&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throws&nbsp;IOException&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;doMap(key,&nbsp;value.getTitle(),&nbsp;titleWeight,&nbsp;output,&nbsp;reporter);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;doMap(key,&nbsp;value.getContent(),&nbsp;contentWeight,&nbsp;output,&nbsp;reporter);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>private&nbsp;void&nbsp;doMap(LongWritable&nbsp;key,&nbsp;String&nbsp;value,&nbsp;IntWritable&nbsp;weight,&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutputCollector&lt;Text,&nbsp;TermWritable&gt;&nbsp;output,&nbsp;Reporter&nbsp;reporter)&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throws&nbsp;IOException&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;do&nbsp;words&nbsp;segmentation&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;TokenStream&nbsp;ts&nbsp;=&nbsp;analyzer.tokenStream(<span>"dummy",&nbsp;new&nbsp;StringReader(value));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;Token&nbsp;token&nbsp;=&nbsp;<span>new&nbsp;Token();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>while&nbsp;((token&nbsp;=&nbsp;ts.next(token))&nbsp;!=&nbsp;null)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;termString&nbsp;=&nbsp;<span>new&nbsp;String(token.termBuffer(),&nbsp;0,&nbsp;token.termLength());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Text&nbsp;term&nbsp;=&nbsp;<span>new&nbsp;Text(termString);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;&lt;term,&nbsp;&lt;documentId,tf&gt;&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TFWritable&nbsp;tf&nbsp;=&nbsp;<span>new&nbsp;TFWritable(key,&nbsp;weight);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.collect(term,&nbsp;<span>new&nbsp;TermWritable(tf));&nbsp;//&nbsp;wrap&nbsp;then&nbsp;collect&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;&lt;term,&nbsp;weight&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;output.collect(term,&nbsp;<span>new&nbsp;TermWritable(weight));&nbsp;//&nbsp;wrap&nbsp;then&nbsp;collect&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>@Override&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>public&nbsp;void&nbsp;configure(JobConf&nbsp;job)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;analyzerName&nbsp;=&nbsp;job.get(<span>"redpoll.text.analyzer");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(analyzerName&nbsp;!=&nbsp;null)&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;analyzer&nbsp;=&nbsp;(Analyzer)&nbsp;Class.forName(analyzerName).newInstance();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>catch&nbsp;(Exception&nbsp;excp)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;excp.printStackTrace();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(analyzer&nbsp;==&nbsp;null)&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;analyzer&nbsp;=&nbsp;<span>new&nbsp;StandardAnalyzer();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> &nbsp; <p>Reduce如果想获取数据，则可以解包(unwrap)它：</p> <div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://coderplay.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>package&nbsp;redpoll.examples;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;java.io.IOException;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.util.ArrayList;&nbsp;&nbsp;</span></li><li><span>import&nbsp;java.util.Iterator;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>import&nbsp;org.apache.commons.logging.Log;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.commons.logging.LogFactory;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.io.ArrayWritable;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.io.IntWritable;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.io.Text;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.io.Writable;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.mapred.MapReduceBase;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.mapred.OutputCollector;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.mapred.Reducer;&nbsp;&nbsp;</span></li><li><span>import&nbsp;org.apache.hadoop.mapred.Reporter;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li><span>/**&nbsp;</span></li><li><span>&nbsp;*&nbsp;Form&nbsp;a&nbsp;tf&nbsp;vector&nbsp;and&nbsp;caculate&nbsp;the&nbsp;df&nbsp;for&nbsp;terms.&nbsp;</span></li><li><span>&nbsp;*&nbsp;@author&nbsp;Jeremy&nbsp;Chow(coderplay@gmail.com)&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>public&nbsp;class&nbsp;TermReducer&nbsp;extends&nbsp;MapReduceBase&nbsp;implements&nbsp;Reducer&lt;Text,&nbsp;TermWritable,&nbsp;Text,&nbsp;Writable&gt;&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>private&nbsp;static&nbsp;final&nbsp;Log&nbsp;log&nbsp;=&nbsp;LogFactory.getLog(TermReducer.class.getName());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;<span>public&nbsp;void&nbsp;reduce(Text&nbsp;key,&nbsp;Iterator&lt;TermWritable&gt;&nbsp;values,&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutputCollector&lt;Text,&nbsp;Writable&gt;&nbsp;output,&nbsp;Reporter&nbsp;reporter)&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throws&nbsp;IOException&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;ArrayList&lt;TFWritable&gt;&nbsp;tfs&nbsp;=&nbsp;<span>new&nbsp;ArrayList&lt;TFWritable&gt;();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>int&nbsp;sum&nbsp;=&nbsp;0;&nbsp;&nbsp;</span></li><li><span>//&nbsp;&nbsp;&nbsp;&nbsp;log.info("term:"&nbsp;+&nbsp;key.toString());&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>while&nbsp;(values.hasNext())&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Writable&nbsp;value&nbsp;=&nbsp;values.next().get();&nbsp;<span>//&nbsp;unwrap&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(value&nbsp;&nbsp;instanceof&nbsp;TFWritable)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tfs.add((TFWritable)&nbsp;value&nbsp;);&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span>else&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum&nbsp;+=&nbsp;((IntWritable)&nbsp;value).get();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;TFWritable&nbsp;writables[]&nbsp;=&nbsp;<span>new&nbsp;TFWritable[tfs.size()];&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;ArrayWritable&nbsp;aw&nbsp;=&nbsp;<span>new&nbsp;ArrayWritable(TFWritable.class,&nbsp;tfs.toArray(writables));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;wrap&nbsp;again&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;output.collect(key,&nbsp;<span>new&nbsp;TermWritable(aw));&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;output.collect(key,&nbsp;<span>new&nbsp;TermWritable(new&nbsp;IntWritable(sum)));&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <p>&nbsp;这儿collect的时候可以不再用TermWritable,只不过我在重新定义了OutputFormat，让它输出到两个不同的文件，而且输出的类型也是不一样的。</p> <p>&nbsp;</p>   </div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/419920.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-11-11 14:10 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/11/11/419920.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Tomcat https</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/07/21/416041.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 21 Jul 2014 05:47:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/07/21/416041.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/416041.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/07/21/416041.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/416041.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/416041.html</trackback:ping><description><![CDATA[<div>http://www.blogjava.net/stevenjohn/archive/2012/08/22/385989.html</div><br /><div>http://www.blogjava.net/stevenjohn/archive/2012/09/26/388600.html</div><br /><div>http://www.oschina.net/code/snippet_12_13918</div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/416041.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-07-21 13:47 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/07/21/416041.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JAVA对字符串的压缩与解压缩</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/06/10/414586.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Tue, 10 Jun 2014 07:58:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/06/10/414586.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/414586.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/06/10/414586.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/414586.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/414586.html</trackback:ping><description><![CDATA[<div><div>http://www.cnblogs.com/gengaixue/archive/2013/09/04/3300658.html</div><br /><br />import java.io.ByteArrayInputStream;<br />import java.io.ByteArrayOutputStream;<br />import java.io.IOException;<br />import java.util.zip.GZIPInputStream;<br />import java.util.zip.GZIPOutputStream;<br />import java.util.zip.ZipEntry;<br />import java.util.zip.ZipInputStream;<br />import java.util.zip.ZipOutputStream;<br /><br />public class ZipUtils {<br /><br />/**<br /><br />* 使用gzip进行压缩<br />*/<br />public static String gzip(String primStr) {<br />if (primStr == null || primStr.length() == 0) {<br />return primStr;<br />}<br /><br />ByteArrayOutputStream out = new ByteArrayOutputStream();<br /><br />GZIPOutputStream gzip=null;<br />try {<br />gzip = new GZIPOutputStream(out);<br />gzip.write(primStr.getBytes());<br />} catch (IOException e) {<br />e.printStackTrace();<br />}finally{<br />if(gzip!=null){<br />try {<br />gzip.close();<br />} catch (IOException e) {<br />e.printStackTrace();<br />}<br />}<br />}<br /><br /><br />return new sun.misc.BASE64Encoder().encode(out.toByteArray());<br />}<br /><br />/**<br />*<br />* &lt;p&gt;Description:使用gzip进行解压缩&lt;/p&gt;<br />* @param compressedStr<br />* @return<br />*/<br />public static String gunzip(String compressedStr){<br />if(compressedStr==null){<br />return null;<br />}<br /><br />ByteArrayOutputStream out= new ByteArrayOutputStream();<br />ByteArrayInputStream in=null;<br />GZIPInputStream ginzip=null;<br />byte[] compressed=null;<br />String decompressed = null;<br />try {<br />compressed = new sun.misc.BASE64Decoder().decodeBuffer(compressedStr);<br />in=new ByteArrayInputStream(compressed);<br />ginzip=new GZIPInputStream(in);<br /><br />byte[] buffer = new byte[1024];<br />int offset = -1;<br />while ((offset = ginzip.read(buffer)) != -1) {<br />out.write(buffer, 0, offset);<br />}<br />decompressed=out.toString();<br />} catch (IOException e) {<br />e.printStackTrace();<br />} finally {<br />if (ginzip != null) {<br />try {<br />ginzip.close();<br />} catch (IOException e) {<br />}<br />}<br />if (in != null) {<br />try {<br />in.close();<br />} catch (IOException e) {<br />}<br />}<br />if (out != null) {<br />try {<br />out.close();<br />} catch (IOException e) {<br />}<br />}<br />}<br /><br />return decompressed;<br />}<br /><br />/**<br />* 使用zip进行压缩<br />* @param str 压缩前的文本<br />* @return 返回压缩后的文本<br />*/<br />public static final String zip(String str) {<br />if (str == null)<br />return null;<br />byte[] compressed;<br />ByteArrayOutputStream out = null;<br />ZipOutputStream zout = null;<br />String compressedStr = null;<br />try {<br />out = new ByteArrayOutputStream();<br />zout = new ZipOutputStream(out);<br />zout.putNextEntry(new ZipEntry("0"));<br />zout.write(str.getBytes());<br />zout.closeEntry();<br />compressed = out.toByteArray();<br />compressedStr = new sun.misc.BASE64Encoder().encodeBuffer(compressed);<br />} catch (IOException e) {<br />compressed = null;<br />} finally {<br />if (zout != null) {<br />try {<br />zout.close();<br />} catch (IOException e) {<br />}<br />}<br />if (out != null) {<br />try {<br />out.close();<br />} catch (IOException e) {<br />}<br />}<br />}<br />return compressedStr;<br />}<br /><br />/**<br />* 使用zip进行解压缩<br />* @param compressed 压缩后的文本<br />* @return 解压后的字符串<br />*/<br />public static final String unzip(String compressedStr) {<br />if (compressedStr == null) {<br />return null;<br />}<br /><br />ByteArrayOutputStream out = null;<br />ByteArrayInputStream in = null;<br />ZipInputStream zin = null;<br />String decompressed = null;<br />try {<br />byte[] compressed = new sun.misc.BASE64Decoder().decodeBuffer(compressedStr);<br />out = new ByteArrayOutputStream();<br />in = new ByteArrayInputStream(compressed);<br />zin = new ZipInputStream(in);<br />zin.getNextEntry();<br />byte[] buffer = new byte[1024];<br />int offset = -1;<br />while ((offset = zin.read(buffer)) != -1) {<br />out.write(buffer, 0, offset);<br />}<br />decompressed = out.toString();<br />} catch (IOException e) {<br />decompressed = null;<br />} finally {<br />if (zin != null) {<br />try {<br />zin.close();<br />} catch (IOException e) {<br />}<br />}<br />if (in != null) {<br />try {<br />in.close();<br />} catch (IOException e) {<br />}<br />}<br />if (out != null) {<br />try {<br />out.close();<br />} catch (IOException e) {<br />}<br />}<br />}<br />return decompressed;<br />}<br />}</div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/414586.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-06-10 15:58 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/06/10/414586.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MyBatis 缓存机制深度解剖 / 自定义二级缓存</title><link>http://www.blogjava.net/wangxinsh55/archive/2014/05/30/414267.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Fri, 30 May 2014 05:53:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2014/05/30/414267.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/414267.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2014/05/30/414267.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/414267.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/414267.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://denger.iteye.com/blog/1126423缓存概述&nbsp;正如大多数持久层框架一样，MyBatis 同样提供了一级缓存和二级缓存的支持；一级缓存基于&nbsp;PerpetualCache&nbsp;的 HashMap 本地缓存，其存储作用域为 Session，当 Session flush 或 close 之后，该Session中的所有 Cache 就将清空。...&nbsp;&nbsp;<a href='http://www.blogjava.net/wangxinsh55/archive/2014/05/30/414267.html'>阅读全文</a><img src ="http://www.blogjava.net/wangxinsh55/aggbug/414267.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2014-05-30 13:53 <a href="http://www.blogjava.net/wangxinsh55/archive/2014/05/30/414267.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jconsole连接远程进程</title><link>http://www.blogjava.net/wangxinsh55/archive/2012/12/14/392992.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Fri, 14 Dec 2012 06:48:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2012/12/14/392992.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/392992.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2012/12/14/392992.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/392992.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/392992.html</trackback:ping><description><![CDATA[<div></div><div><div><div>http://www.iteye.com/topic/778425<br /> <br /> 连接远程进程时，需要输入ip和port。<br /> 其中ip查看方式：<br /> -Djava.rmi.server.hostname=<span style="color: red;">10.27.5.139</span><br /> port查看方式：<br /> -Dcom.sun.management.jmxremote.port=<span style="color: red;">8888</span><br /> <br /> 另远程jvm的设置方式，加入：<br /> -Djava.rmi.server.hostname=10.27.5.139<br /> -Dcom.sun.management.jmxremote<br /> -Dcom.sun.management.jmxremote.port=8888<br /> -Dcom.sun.management.jmxremote.authenticate=false<br /> -Dcom.sun.management.jmxremote.ssl=false<br /> 其中设置ip和port即可。<br /> <br /> 今天装了台activemq5 Jms服务器，打算用本地jconsole 通过jmx连接到amq，总是失败；<br /> 检查了一下bin下的activemq脚本，里面配置如下：<br /> if [ -z "$SUNJMX" ] ; then<br /> SUNJMX="-Dcom.sun.management.jmxremote.port=9999 -<br /> Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"<br /> fi<br /> 应该没有问题<br /> 随后检查了conf下activemq.xml<br /> broker 已经设置了 useJmx="true"<br /> 依然无法访问；<br /> 最后修改了一下/etc/hosts，将ip加了进去就可以了<br /> 或者修改SUNJMX参数增加：<br /> -Djava.rmi.server.hostname=ip 项，也可以远程连接</div></div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/392992.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2012-12-14 14:48 <a href="http://www.blogjava.net/wangxinsh55/archive/2012/12/14/392992.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>三、解析QueryParser.jj</title><link>http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391193.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 12 Nov 2012 03:59:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391193.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/391193.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391193.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/391193.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/391193.html</trackback:ping><description><![CDATA[<div>http://forfuture1978.iteye.com/blog/661680</div><br /><div><h2><strong>3.1、声明QueryParser类</strong></h2> <p>在QueryParser.jj文件中，PARSER_BEGIN(QueryParser)和PARSER_END(QueryParser)之间，定义了QueryParser类。</p> <p>其中最重要的一个函数是public Query parse(String query)函数，也即我们解析Lucene查询语法的时候调用的函数。</p> <p>这是一个纯Java代码定义的函数，会直接拷贝到QueryParser.java文件中。</p> <p>parse函数中，最重要的一行代码是调用Query res = TopLevelQuery(field)，而TopLevelQuery函数是QueryParser.jj中定义的语法分析器被JavaCC编译后会生成的函数。</p> <h2><strong>3.2、声明词法分析器</strong></h2> <p>在解析词法分析器之前，首先介绍一下JavaCC的词法状态的概念(lexical state)。</p> <p>有可能存在如下的情况，在不同的情况下，要求的词法词法规则不同，比如我们要解析一个java文件(即满足java语法的表达式)，在默认的状态 DEFAULT下，是要求解析的对象(即表达式)满足java语言的词法规则，然而当出现"/**"的时候，其后面的表达式则不需要满足java语言的语 法规则，而是应该满足java注释的语法规则(要识别@param变量等)，于是我们做如下定义：</p> <table width="744"><tbody><tr> <td width="742"> <p><strong>//默认处于DEFAULT状态，当遇到/**的时候，转换为IN_JAVADOC_COMMENT状态</strong></p> <p>&lt;DEFAULT&gt; TOKEN : {&lt;STARTDOC : &#8220;/**&#8221; &gt; : IN_JAVADOC_COMMENT }</p> <p><strong>//在IN_JAVADOC_COMMENT状态下，需要识别@param变量</strong></p> <p>&lt;IN_JAVADOC_COMMENT&gt; TOKEN : {&lt;PARAM : "@param" &gt;}</p> <p><strong>//在IN_JAVADOC_COMMENT状态下，遇到*/的时候，装换为DEFAULT状态</strong></p> <p>&lt;IN_JAVADOC_COMMENT&gt; TOKEN : {&lt;ENDDOC: "*/"&gt;: DEFAULT }</p> </td> </tr></tbody></table> <p>&lt;*&gt; 表示应用于任何状态。</p> <h3><strong>(1) 应用于所有状态的变量</strong></h3> <table width="783"><tbody><tr> <td width="781"> <p>&lt;*&gt; TOKEN : {</p> <p>&nbsp; &lt;#_NUM_CHAR:&nbsp;&nbsp; ["0"-"9"] &gt; <strong>//数字</strong></p> <p>| &lt;#_ESCAPED_CHAR: "\\" ~[] &gt; <strong>//"\"后的任何一个字符都是被转义的</strong></p> <p>| &lt;#_TERM_START_CHAR: ( ~[ " ", "\t", "\n", "\r", "\u3000", "+",  "-", "!", "(", ")", ":", "^", "[", "]", "\"", "{", "}", "~", "*", "?",  "\\" ] | &lt;_ESCAPED_CHAR&gt; ) &gt; <strong>//表达式中任何一个term，都不能以[]括起来的列表中的lucene查询语法关键字开头，当然被转义的除外。</strong></p> <p>| &lt;#_TERM_CHAR: ( &lt;_TERM_START_CHAR&gt; | &lt;_ESCAPED_CHAR&gt; | "-" | "+" ) &gt; <strong>//表达式中的term非起始字符，可以包含任何非语法关键字字符，转义过的字符，也可以包含+, -(但包含+,-的符合词法，不合语法)。</strong></p> <p>| &lt;#_WHITESPACE: ( " " | "\t" | "\n" | "\r" | "\u3000") &gt; <strong>//被认为是空格的字符</strong></p> <p>| &lt;#_QUOTED_CHAR: ( ~[ "\"", "\\" ] | &lt;_ESCAPED_CHAR&gt; ) &gt; <strong>//被引号括起来的字符不应再包括"和\，当然转义过的除外。</strong></p> <p>}</p> </td> </tr></tbody></table> <p>&nbsp;</p> <h3><strong>(2) 默认状态的Token</strong></h3> <table width="798"> <tbody><tr> <td width="796"> <p>&lt;DEFAULT&gt; TOKEN : {</p> <p>&nbsp; &lt;AND:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ("AND" | "&amp;&amp;") &gt;</p> <p>| &lt;OR:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ("OR" | "||") &gt;</p> <p>| &lt;NOT:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ("NOT" | "!") &gt;</p> <p>| &lt;PLUS:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "+" &gt;</p> <p>| &lt;MINUS:&nbsp;&nbsp;&nbsp;&nbsp; "-" &gt;</p> <p>| &lt;LPAREN:&nbsp;&nbsp;&nbsp; "(" &gt;</p> <p>| &lt;RPAREN:&nbsp;&nbsp;&nbsp; ")" &gt;</p> <p>| &lt;COLON:&nbsp;&nbsp;&nbsp;&nbsp; ":" &gt;</p> <p>| &lt;STAR:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "*" &gt;</p> <p>| &lt;CARAT:&nbsp;&nbsp;&nbsp;&nbsp; "^" &gt; : Boost <strong>//当遇到^的时候，后面跟随的是boost表达式，进入Boost状态</strong></p> <p>| &lt;QUOTED:&nbsp;&nbsp;&nbsp;&nbsp; "\"" (&lt;_QUOTED_CHAR&gt;)* "\""&gt;</p> <p>| &lt;TERM:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;_TERM_START_CHAR&gt; (&lt;_TERM_CHAR&gt;)*&nbsp; &gt;</p> <p>| &lt;FUZZY_SLOP:&nbsp;&nbsp;&nbsp;&nbsp; "~" ( (&lt;_NUM_CHAR&gt;)+ ( "." (&lt;_NUM_CHAR&gt;)+ )? )? &gt; <strong>//Fuzzy查询，~后面跟小数。</strong></p> <p>| &lt;PREFIXTERM:&nbsp; ("*") | ( &lt;_TERM_START_CHAR&gt; (&lt;_TERM_CHAR&gt;)* "*" ) &gt; <strong>//使用*进行Prefix查询，可以尽包含*，或者末尾包含*，然而只包含*符合词法，不合语法。</strong></p> <p>| &lt;WILDTERM:&nbsp; (&lt;_TERM_START_CHAR&gt; | [ "*", "?" ]) (&lt;_TERM_CHAR&gt; | ( [ "*", "?" ] ))* &gt; <strong>//使用*和?进行wildcard查询</strong></p> <p>| &lt;RANGEIN_START: "[" &gt; : RangeIn <strong>//遇到[]的时候，是包含边界的Range查询</strong></p> <p>| &lt;RANGEEX_START: "{" &gt; : RangeEx <strong>//遇到{}的时候，是不包含边界的Range查询</strong></p> <p>}</p> </td> </tr> <tr> <td width="796"> <p>&lt;Boost&gt; TOKEN : {</p> <p>&lt;NUMBER:&nbsp;&nbsp;&nbsp; (&lt;_NUM_CHAR&gt;)+ ( "." (&lt;_NUM_CHAR&gt;)+ )? &gt; : DEFAULT <strong>//boost是一个小数</strong></p> <p>}</p> </td> </tr> <tr> <td width="796"> <p><strong>//包含边界的Range查询是[A TO B]的形式。</strong></p> <p>&lt;RangeIn&gt; TOKEN : {</p> <p>&lt;RANGEIN_TO: "TO"&gt;</p> <p>| &lt;RANGEIN_END: "]"&gt; : DEFAULT</p> <p>| &lt;RANGEIN_QUOTED: "\"" (~["\""] | "\\\"")+ "\""&gt;</p> <p>| &lt;RANGEIN_GOOP: (~[ " ", "]" ])+ &gt;</p> <p>}</p> </td> </tr> <tr> <td width="796"> <p><strong>//不包含边界的Range查询是{A TO B}的形式</strong></p> <p>&lt;RangeEx&gt; TOKEN : {</p> <p>&lt;RANGEEX_TO: "TO"&gt;</p> <p>| &lt;RANGEEX_END: "}"&gt; : DEFAULT</p> <p>| &lt;RANGEEX_QUOTED: "\"" (~["\""] | "\\\"")+ "\""&gt;</p> <p>| &lt;RANGEEX_GOOP: (~[ " ", "}" ])+ &gt;</p> <p>}</p> </td> </tr> </tbody></table> <p>&nbsp;</p> <h2><strong>3.3、声明语法分析器</strong></h2> <p>Lucene的语法规则如下：</p> <table width="755"><tbody><tr> <td width="753"> <p>Query&nbsp; ::= ( Clause )*</p> <p>Clause ::= ["+", "-"] [&lt;TERM&gt; ":"] ( &lt;TERM&gt; | "(" Query ")" )</p> </td> </tr></tbody></table> <h3><strong>(1) 从Query到Clause</strong></h3> <p>一个Query查询语句，是由多个clause组成的，每个clause有修饰符Modifier，或为+, 或为-，clause之间的有连接符，或为AND，或为OR，或为NOT。</p> <p>在Lucene的语法解析中NOT被算作Modifier，和-起相同作用。</p> <p>此过程表达式如下：</p> <table width="703"> <tbody><tr> <td width="701"> <p>Query TopLevelQuery(String field) : </p> <p>{</p> <p>&nbsp;&nbsp;&nbsp; Query q;</p> <p>}</p> <p>{</p> <p>&nbsp;&nbsp;&nbsp; q=Query(field) &lt;EOF&gt;</p> <p>&nbsp;&nbsp;&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return q;</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>}</p> </td> </tr> <tr> <td width="701"> <p>Query Query(String field) :</p> <p>{</p> <p>&nbsp; List&lt;BooleanClause&gt; clauses = new ArrayList&lt;BooleanClause&gt;();</p> <p>&nbsp; Query q, firstQuery=null;</p> <p>&nbsp; int conj, mods;</p> <p>}</p> <p>{</p> <p>&nbsp; <strong>//查询语句开头是一个Modifier，可以为空</strong></p> <p><strong>&nbsp; //Modifier后面便是子语句clause，可以生成子查询语句q</strong></p> <p>&nbsp; mods=Modifiers() q=Clause(field)</p> <p>&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp; <strong>//如果第一个语句的Modifier是空，则将子查询q付给firstQuery，从后面我们可以看到，当只有一个查询 语句的时候，如果其Modifier为空，则不返回BooleanQuery，而是返回子查询对象firstQuery。从这里我们可以看出，如果查询语 句为"A"，则生成TermQuery，其term为"A"，如果查询语句为"+A"，则生成BooleanQuery，其子查询只有一个，就是 TermQuery，其term为"A"。</strong></p> <p>&nbsp;&nbsp;&nbsp; addClause(clauses, CONJ_NONE, mods, q);</p> <p>&nbsp;&nbsp;&nbsp; if (mods == MOD_NONE)</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; firstQuery=q;</p> <p>&nbsp; }</p> <p>&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp; <strong>//除了第一个语句外，其他的前面可以有连接符，或为AND，或为OR。</strong></p> <p><strong>&nbsp;&nbsp;&nbsp; //如果在第一个语句之前出现连接符，则报错，如"OR a"，会报Encountered " &lt;OR&gt; "OR "" at line 1, column 0.</strong></p> <p><strong>&nbsp;&nbsp;&nbsp; //除了连接符，也会有Modifier，后面是子语句clause，生成子查询q，并加入BooleanQuery中。</strong></p> <p>&nbsp;&nbsp;&nbsp; conj=Conjunction() mods=Modifiers() q=Clause(field)</p> <p>&nbsp;&nbsp;&nbsp; { addClause(clauses, conj, mods, q); }</p> <p>&nbsp; )*</p> <p>&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp; <strong>//如果只有一个查询语句，且其modifier为空，则返回firstQuery，否则由所有的子语句clause，生成BooleanQuery。</strong></p> <p>&nbsp;&nbsp;&nbsp; if (clauses.size() == 1 &amp;&amp; firstQuery != null)</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return firstQuery;</p> <p>&nbsp;&nbsp;&nbsp; else {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getBooleanQuery(clauses);</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp; }</p> <p>}</p> </td> </tr> <tr> <td width="701"> <p>int Modifiers() : {</p> <p>&nbsp; <strong>//默认modifier为空，如果遇到+，就是required，如果遇到-或者NOT，就是prohibited。</strong></p> <p>&nbsp; int ret = MOD_NONE;</p> <p>}</p> <p>{</p> <p>&nbsp; [</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; &lt;PLUS&gt; { ret = MOD_REQ; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; | &lt;MINUS&gt; { ret = MOD_NOT; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; | &lt;NOT&gt; { ret = MOD_NOT; }</p> <p>&nbsp; ]</p> <p>&nbsp; { return ret; }</p> <p>}</p> </td> </tr> <tr> <td width="701"> <p><strong>//连接符</strong></p> <p>int Conjunction() : {</p> <p>&nbsp; int ret = CONJ_NONE;</p> <p>}</p> <p>{</p> <p>&nbsp; [</p> <p>&nbsp;&nbsp;&nbsp; &lt;AND&gt; { ret = CONJ_AND; }</p> <p>&nbsp;&nbsp;&nbsp; | &lt;OR&gt;&nbsp; { ret = CONJ_OR; }</p> <p>&nbsp; ]</p> <p>&nbsp; { return ret; }</p> <p>}</p> </td> </tr> </tbody></table> <p>&nbsp;</p> <h3><strong>(2) 一个子语句clause</strong></h3> <p>由上面的分析我们可以知道，JavaCC使用的是编译原理里面的自上而下分析法，基本采用的是LL(1)的方法：</p> <ul><li>第一个L ：从左到右扫描输入串 </li><li>第二个L ：生成的是最左推导 </li><li>(1)：向前看一个输入符号（lookahead) </li></ul> <p>JavaCC还提供LOOKAHEAD(n)，也即当仅读入下一个符号时，不足以判断接下来的如何解析，会出现Choice Conflict，则需要多读入几个符号，来进一步判断。</p> <table width="871"> <tbody><tr> <td width="869"> <p>&nbsp;</p> <p>Query Clause(String field) : {</p> <p>&nbsp; Query q;</p> <p>&nbsp; Token fieldToken=null, boost=null;</p> <p>}</p> <p>{</p> <p>&nbsp; <strong>//此处之所以向前看两个符号，就是当看到&lt;TERM&gt;的时候，不知道它是一个field，还是一个term，当&lt;TERM&gt;&lt;COLON&gt;在一起的时候，说明&lt;TERM&gt;代表一个field, 否则代表一个term</strong></p> <p>&nbsp; [</p> <p>&nbsp;&nbsp;&nbsp; LOOKAHEAD(2)</p> <p>&nbsp;&nbsp;&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp; fieldToken=&lt;TERM&gt; &lt;COLON&gt; {field=discardEscapeChar(fieldToken.image);}</p> <p>&nbsp;&nbsp;&nbsp; | &lt;STAR&gt; &lt;COLON&gt; {field="*";}</p> <p>&nbsp;&nbsp;&nbsp; )</p> <p>&nbsp; ] </p> <p>&nbsp; (</p> <p>&nbsp; <strong>//或者是一个term，则由此term生成一个查询对象</strong></p> <p><strong>&nbsp;&nbsp; //或者是一个由括号括起来的子查询</strong></p> <p><strong>&nbsp;&nbsp; //()?表示可能存在一个boost，格式为^加一个数字</strong></p> <p>&nbsp;&nbsp; q=Term(field)</p> <p>&nbsp;&nbsp; | &lt;LPAREN&gt; q=Query(field) &lt;RPAREN&gt; (&lt;CARAT&gt; boost=&lt;NUMBER&gt;)? </p> <p>&nbsp; )</p> <p>&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp; <strong>//如果存在boost，则设定查询对象的boost</strong></p> <p>&nbsp;&nbsp;&nbsp; if (boost != null) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float f = (float)1.0;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f = Float.valueOf(boost.image).floatValue();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q.setBoost(f);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ignored) { }</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; return q;</p> <p>&nbsp; }</p> <p>}</p> </td> </tr> <tr> <td width="869"> <p>&nbsp;</p> <p>Query Term(String field) : {</p> <p>&nbsp; Token term, boost=null, fuzzySlop=null, goop1, goop2;</p> <p>&nbsp; boolean prefix = false;</p> <p>&nbsp; boolean wildcard = false;</p> <p>&nbsp; boolean fuzzy = false;</p> <p>&nbsp; Query q;</p> <p>}</p> <p>{</p> <p>&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>//如果term仅结尾包含*则是prefix查询。</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果以*开头，或者中间包含*，或者结尾包含*(如果仅结尾包含，则prefix优先)则为wildcard查询。</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; term=&lt;TERM&gt;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | term=&lt;STAR&gt; { wildcard=true; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | term=&lt;PREFIXTERM&gt; { prefix=true; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | term=&lt;WILDTERM&gt; { wildcard=true; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | term=&lt;NUMBER&gt;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; )</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; <strong>//如果term后面是~，则是fuzzy查询</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp; [ fuzzySlop=&lt;FUZZY_SLOP&gt; { fuzzy=true; } ]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; [ &lt;CARAT&gt; boost=&lt;NUMBER&gt; [ fuzzySlop=&lt;FUZZY_SLOP&gt; { fuzzy=true; } ] ]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>//如果是wildcard查询，则调用getWildcardQuery，</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp; *:*得到MatchAllDocsQuery，将返回所有的文档</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp; 目前不支持最前面带通配符的查询(虽然词法分析和语法分析都能通过)，否则报ParseException</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;&nbsp;&nbsp; 最后生成WildcardQuery</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果是prefix查询，则调用getPrefixQuery，生成PrefixQuery</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果是fuzzy查询，则调用getFuzzyQuery,生成FuzzyQuery</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果是普通查询，则调用getFieldQuery</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String termImage=discardEscapeChar(term.image);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (wildcard) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = getWildcardQuery(field, termImage);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (prefix) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = getPrefixQuery(field, discardEscapeChar(term.image.substring(0, term.image.length()-1)));</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (fuzzy) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float fms = fuzzyMinSim;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fms = Float.valueOf(fuzzySlop.image.substring(1)).floatValue();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (Exception ignored) { }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(fms &lt; 0.0f || fms &gt; 1.0f){</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ParseException("Minimum similarity for a FuzzyQuery has to be between 0.0f and 1.0f !");</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = getFuzzyQuery(field, termImage,fms);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = getFieldQuery(field, termImage);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; <strong>//包含边界的range查询，取得[goop1 TO goop2]，调用getRangeQuery，生成TermRangeQuery</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp; | ( &lt;RANGEIN_START&gt; ( goop1=&lt;RANGEIN_GOOP&gt;|goop1=&lt;RANGEIN_QUOTED&gt; )</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ &lt;RANGEIN_TO&gt; ] ( goop2=&lt;RANGEIN_GOOP&gt;|goop2=&lt;RANGEIN_QUOTED&gt; )</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;RANGEIN_END&gt; )</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ &lt;CARAT&gt; boost=&lt;NUMBER&gt; ]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (goop1.kind == RANGEIN_QUOTED) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goop1.image = goop1.image.substring(1, goop1.image.length()-1);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (goop2.kind == RANGEIN_QUOTED) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goop2.image = goop2.image.substring(1, goop2.image.length()-1);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = getRangeQuery(field, discardEscapeChar(goop1.image), discardEscapeChar(goop2.image), true);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; <strong>//不包含边界的range查询，取得{goop1 TO goop2}，调用getRangeQuery，生成TermRangeQuery</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp; | ( &lt;RANGEEX_START&gt; ( goop1=&lt;RANGEEX_GOOP&gt;|goop1=&lt;RANGEEX_QUOTED&gt; )</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ &lt;RANGEEX_TO&gt; ] ( goop2=&lt;RANGEEX_GOOP&gt;|goop2=&lt;RANGEEX_QUOTED&gt; )</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;RANGEEX_END&gt; )</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ &lt;CARAT&gt; boost=&lt;NUMBER&gt; ]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (goop1.kind == RANGEEX_QUOTED) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goop1.image = goop1.image.substring(1, goop1.image.length()-1);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (goop2.kind == RANGEEX_QUOTED) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goop2.image = goop2.image.substring(1, goop2.image.length()-1);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = getRangeQuery(field, discardEscapeChar(goop1.image), discardEscapeChar(goop2.image), false);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp; <strong>//被""括起来的term，得到phrase查询，调用getFieldQuery</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp; | term=&lt;QUOTED&gt;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ fuzzySlop=&lt;FUZZY_SLOP&gt; ]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ &lt;CARAT&gt; boost=&lt;NUMBER&gt; ]</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int s = phraseSlop; </p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (fuzzySlop != null) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = Float.valueOf(fuzzySlop.image.substring(1)).intValue();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (Exception ignored) { }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q = getFieldQuery(field, discardEscapeChar(term.image.substring(1, term.image.length()-1)), s);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp; )</p> <p>&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp; if (boost != null) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float f = (float) 1.0;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f = Float.valueOf(boost.image).floatValue();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (Exception ignored) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } </p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // avoid boosting null queries, such as those caused by stop words</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (q != null) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q.setBoost(f);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; return q;</p> <p>&nbsp; }</p> <p>}</p> </td> </tr> </tbody></table> <p>&nbsp;</p> <p>此处需要详细解析的是getFieldQuery：</p>   <p>protected Query getFieldQuery(String field, String queryText)&nbsp; throws ParseException {</p> <p>&nbsp; <strong>//需要用analyzer对文本进行分词</strong></p> <p>&nbsp; TokenStream source;</p> <p>&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp; source = analyzer.reusableTokenStream(field, new StringReader(queryText));</p> <p>&nbsp;&nbsp;&nbsp; source.reset();</p> <p>&nbsp; } catch (IOException e) {</p> <p>&nbsp;&nbsp;&nbsp; source = analyzer.tokenStream(field, new StringReader(queryText));</p> <p>&nbsp; }</p> <p>&nbsp; CachingTokenFilter buffer = new CachingTokenFilter(source);</p> <p>&nbsp; TermAttribute termAtt = null;</p> <p>&nbsp; PositionIncrementAttribute posIncrAtt = null;</p> <p>&nbsp; int numTokens = 0;</p> <p>&nbsp; boolean success = false;</p> <p>&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp; buffer.reset();</p> <p>&nbsp;&nbsp;&nbsp; success = true;</p> <p>&nbsp; } catch (IOException e) {</p> <p>&nbsp; }</p> <p>&nbsp; <strong>//得到TermAttribute和PositionIncrementAttribute，此两项将决定到底产生什么样的Query对象</strong></p> <p>&nbsp; if (success) {</p> <p>&nbsp;&nbsp;&nbsp; if (buffer.hasAttribute(TermAttribute.class)) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; termAtt = buffer.getAttribute(TermAttribute.class);</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; if (buffer.hasAttribute(PositionIncrementAttribute.class)) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; posIncrAtt = buffer.getAttribute(PositionIncrementAttribute.class);</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp; }</p> <p>&nbsp; int positionCount = 0;</p> <p>&nbsp; boolean severalTokensAtSamePosition = false;</p> <p>&nbsp; boolean hasMoreTokens = false;</p> <p>&nbsp; if (termAtt != null) {</p> <p>&nbsp;&nbsp;&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>//遍历分词后的所有Token，统计Tokens的个数numTokens，以及positionIncrement的总数，即positionCount。</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //当有一次positionIncrement为0的时候，severalTokensAtSamePosition设为true，表示有多个Token处在同一个位置。</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hasMoreTokens = buffer.incrementToken();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (hasMoreTokens) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; numTokens++;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int positionIncrement = (posIncrAtt != null) ? posIncrAtt.getPositionIncrement() : 1;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (positionIncrement != 0) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; positionCount += positionIncrement;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; severalTokensAtSamePosition = true;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hasMoreTokens = buffer.incrementToken();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; } catch (IOException e) {</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp; }</p> <p>&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp; <strong>//重设buffer，以便生成phrase查询的时候，term和position可以重新遍历。</strong></p> <p>&nbsp;&nbsp;&nbsp; buffer.reset();</p> <p>&nbsp;&nbsp;&nbsp; source.close();</p> <p>&nbsp; }</p> <p>&nbsp; catch (IOException e) {</p> <p>&nbsp; }</p> <p>&nbsp; if (numTokens == 0)</p> <p>&nbsp;&nbsp;&nbsp; return null;</p> <p>&nbsp; else if (numTokens == 1) {</p> <p>&nbsp;&nbsp;&nbsp; <strong>//如果分词后只有一个Token，则生成TermQuery</strong></p> <p>&nbsp;&nbsp;&nbsp; String term = null;</p> <p>&nbsp;&nbsp;&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean hasNext = buffer.incrementToken();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; term = termAtt.term();</p> <p>&nbsp;&nbsp;&nbsp; } catch (IOException e) {</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; return newTermQuery(new Term(field, term));</p> <p>&nbsp; } else {</p> <p>&nbsp;&nbsp; <strong>//如果分词后不只有一个Token</strong></p> <p>&nbsp;&nbsp;&nbsp; if (severalTokensAtSamePosition) {</p> <p>&nbsp;&nbsp; <strong>//如果有多个Token处于同一个位置</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (positionCount == 1) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>//并且处于同一位置的Token还全部处于第一个位置，则生成BooleanQuery，处于同一位置的Token之间是OR的关系</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BooleanQuery q = newBooleanQuery(true);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; numTokens; i++) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String term = null;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean hasNext = buffer.incrementToken();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; term = termAtt.term();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException e) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Query currentQuery = newTermQuery(new Term(field, term));</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; q.add(currentQuery, BooleanClause.Occur.SHOULD);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return q;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>//如果有多个Token处于同一位置，但不是第一个位置，则生成MultiPhraseQuery。</strong></p> <p><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  //所谓MultiPhraseQuery即其可以包含多个phrase，其又一个ArrayList&lt;Term[]&gt;  termArrays，每一项都是一个Term的数组，属于同一个数组的Term表示在同一个位置。它有函数void add(Term[]  terms)一次添加一个数组的Term。比如我们要搜索"microsoft app*"，其表示多个phrase，"microsoft  apple"，"microsoft application"都算。此时用QueryParser.parse("\"microsoft  app*\"")从而生成PhraseQuery是搜不出microsoft apple和microsoft  application的，也不能搜出microsoft  app，因为*一旦被引号所引，就不算通配符了。所以必须生成MultiPhraseQuery，首先用add(new Term[]{new  Term("field", "microsoft")})将microsoft作为一个Term数组添加进去，然后用add(new  Term[]{new Term("field", "app"), new Term("field", "apple"), new  Term("field", "application")})作为一个Term数组添加进去(算作同一个位置的)，则三者都能搜的出来。</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MultiPhraseQuery mpq = newMultiPhraseQuery(); </p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mpq.setSlop(phraseSlop);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; List&lt;Term&gt; multiTerms = new ArrayList&lt;Term&gt;();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int position = -1;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; numTokens; i++) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String term = null;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int positionIncrement = 1;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean hasNext = buffer.incrementToken();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert hasNext == true;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; term = termAtt.term();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (posIncrAtt != null) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; positionIncrement = posIncrAtt.getPositionIncrement();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException e) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (positionIncrement &gt; 0 &amp;&amp; multiTerms.size() &gt; 0) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>//如果positionIncrement大于零，说明此Term和前一个Term已经不是同一个位置 了，所以原来收集在multiTerms中的Term都算作同一个位置，添加到MultiPhraseQuery中作为一项。并清除 multiTerms，以便重新收集相同位置的Term。</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (enablePositionIncrements) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mpq.add(multiTerms.toArray(new Term[0]),position);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mpq.add(multiTerms.toArray(new Term[0]));</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; multiTerms.clear();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>//将此Term收集到multiTerms中。</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; position += positionIncrement;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; multiTerms.add(new Term(field, term));</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>//当遍历完所有的Token，同处于最后一个位置的Term已经收集到multiTerms中了，把他们加到MultiPhraseQuery中作为一项。</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (enablePositionIncrements) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mpq.add(multiTerms.toArray(new Term[0]),position);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mpq.add(multiTerms.toArray(new Term[0]));</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return mpq;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; else {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <strong>//如果不存在多个Token处于同一个位置的情况，则直接生成PhraseQuery</strong></p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PhraseQuery pq = newPhraseQuery();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pq.setSlop(phraseSlop);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int position = -1;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; numTokens; i++) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String term = null;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int positionIncrement = 1;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; boolean hasNext = buffer.incrementToken();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assert hasNext == true;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; term = termAtt.term();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (posIncrAtt != null) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; positionIncrement = posIncrAtt.getPositionIncrement();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } catch (IOException e) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (enablePositionIncrements) {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; position += positionIncrement;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pq.add(new Term(field, term),position);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pq.add(new Term(field, term));</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return pq;</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp; }</p> <p>} </p></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/391193.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2012-11-12 11:59 <a href="http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391193.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lucene学习总结之八：Lucene的查询语法，JavaCC及QueryParser</title><link>http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391191.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 12 Nov 2012 03:58:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391191.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/391191.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/391191.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/391191.html</trackback:ping><description><![CDATA[<div><p><a href="http://forfuture1978.iteye.com/blog/661678"><span style="font-size: x-small;"><strong><span style="color: #0000ff;"><div>http://forfuture1978.iteye.com/blog/661883</div><br /></span></strong></span></a></p><p><a href="http://forfuture1978.iteye.com/blog/661678"><span style="font-size: x-small;"><strong><span style="color: #0000ff;"><br /></span></strong></span></a></p><p><a href="http://forfuture1978.iteye.com/blog/661678"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之八：Lucene的查询语法，JavaCC及QueryParser(1)</span></strong></span></a></p> <p><a href="http://forfuture1978.iteye.com/blog/661678"><strong>http://forfuture1978.iteye.com/blog/661678</strong></a></p> <p> </p> <p><a href="http://forfuture1978.iteye.com/blog/661680"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之八：Lucene的查询语法，JavaCC及QueryParser(2)</span></strong></span></a></p> <p><a href="http://forfuture1978.iteye.com/blog/661680"><strong>http://forfuture1978.iteye.com/blog/661680</strong></a></p>  <p><span style="font-size: x-small;"><strong><span style="color: #0000ff;"><br /></span></strong></span></p> <p><span style="font-size: x-small;"><strong><span style="color: #0000ff;">此系列相关文章</span></strong></span></p> <p><span style="font-size: x-small;"><strong><span style="color: #0000ff;">----------------------------------------------------------</span></strong></span></p> <p> </p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: normal;"><a target="_blank" href="http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623594.html"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之一：全文检索的基本原理</span></strong></span></a></span></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/546771"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/546771</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: normal;"><a target="_blank" href="http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623596.html"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之二：Lucene的总体架构</span></strong></span></a></span></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/546808"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/546808</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: normal;"><a target="_blank" href="http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623597.html"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之三：Lucene的索引文件格式(1)</span></strong></span></a></span></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/546824"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/546824</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: normal;"><a target="_blank" href="http://www.cnblogs.com/forfuture1978/archive/2009/12/14/1623599.html"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之三：Lucene的索引文件格式(2)</span></strong></span></a></span></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/546832"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/546832</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: normal;"><a target="_blank" href="http://www.cnblogs.com/forfuture1978/archive/2010/02/02/1661436.html"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之三：Lucene的索引文件格式(3)</span></strong></span></a></span></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/546841"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/546841</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: normal;"><a target="_blank" href="http://www.cnblogs.com/forfuture1978/archive/2010/02/02/1661439.html"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之四：Lucene索引过程分析(1)</span></strong></span></a></span></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/587113"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/587113</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: normal;"><a target="_blank" href="http://www.cnblogs.com/forfuture1978/archive/2010/02/02/1661440.html"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之四：Lucene索引过程分析(2)</span></strong></span></a></span></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/587116"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/587116</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: normal;"><a target="_blank" href="http://www.cnblogs.com/forfuture1978/archive/2010/02/02/1661441.html"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之四：Lucene索引过程分析(3)</span></strong></span></a></span></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/587120"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/587120</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: normal;"><a target="_blank" href="http://www.cnblogs.com/forfuture1978/archive/2010/02/02/1661442.html"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之四：Lucene索引过程分析(4)</span></strong></span></a></span><span style="font-size: x-small;"><strong>&nbsp;</strong></span><span style="font-size: x-small;"><strong>&nbsp;</strong></span></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/587122"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/587122</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/609197"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之五：Lucene段合并(merge)过程分析</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/609197"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/609197</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/609502"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之六：Lucene打分公式的数学推导</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/609502"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/609502</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; font-size: 13px; line-height: 19px; text-indent: 0px; padding: 0px;"><span style="line-height: 18px; font-size: 12px;"> </span></p><p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632815"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之七：Lucene搜索过程解析(1)</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632815"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/632815</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632816"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之七：Lucene搜索过程解析(2)</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632816"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/632816</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632822"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之七：Lucene搜索过程解析(3)</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632822"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/632822</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632829"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之七：Lucene搜索过程解析(4)</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632829"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/632829</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632840"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之七：Lucene搜索过程解析(5)</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632840"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/632840</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632859"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之七：Lucene搜索过程解析(6)</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632859"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/632859</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632869"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之七：Lucene搜索过程解析(7)</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632869"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/632869</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632872"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">Lucene学习总结之七：Lucene搜索过程解析(8)</span></strong></span></a></p> <p style="margin-top: 5px; margin-right: auto; margin-bottom: 5px; margin-left: auto; line-height: 19px; text-indent: 0px; padding: 0px;"><a href="http://forfuture1978.iteye.com/blog/632872"><span style="font-size: x-small;"><strong><span style="color: #0000ff;">http://forfuture1978.iteye.com/blog/632872</span></strong></span></a></p></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/391191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2012-11-12 11:58 <a href="http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lucene学习总结之八：Lucene的查询语法，JavaCC及QueryParser(1)</title><link>http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391192.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 12 Nov 2012 03:58:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391192.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/391192.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391192.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/391192.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/391192.html</trackback:ping><description><![CDATA[<div>http://forfuture1978.iteye.com/blog/661678</div><br /><div><h1><strong>一、Lucene的查询语法</strong></h1> <p>Lucene所支持的查询语法可见<a href="http://lucene.apache.org/java/3_0_1/queryparsersyntax.html">http://lucene.apache.org/java/3_0_1/queryparsersyntax.html</a></p> <h3><strong>(1) 语法关键字</strong></h3> <p>+ - &amp;&amp; || ! ( ) { } [ ] ^ " ~ * ? : \</p> <p>如果所要查询的查询词中本身包含关键字，则需要用\进行转义</p> <h3><strong>(2) 查询词(Term)</strong></h3> <p>Lucene支持两种查询词，一种是单一查询词，如"hello"，一种是词组(phrase)，如"hello world"。</p> <h3><strong>(3) 查询域(Field)</strong></h3> <p>在查询语句中，可以指定从哪个域中寻找查询词，如果不指定，则从默认域中查找。</p> <p>查询域和查询词之间用:分隔，如title:"Do it right"。</p> <p>:仅对紧跟其后的查询词起作用，如果title:Do it right，则仅表示在title中查询Do，而it right要在默认域中查询。</p> <h3><strong>(4) 通配符查询(Wildcard)</strong></h3> <p>支持两种通配符：?表示一个字符，*表示多个字符。</p> <p>通配符可以出现在查询词的中间或者末尾，如te?t，test*，te*t，但决不能出现在开始，如*test，?test。</p> <h3><strong>(5) 模糊查询(Fuzzy)</strong></h3> <p>模糊查询的算法是基于Levenshtein  Distance，也即当两个词的差别小于某个比例的时候，就算匹配，如roam~0.8，即表示差别小于0.2，相似度大于0.8才算匹配。</p> <h3><strong>(6) 临近查询(Proximity)</strong></h3> <p>在词组后面跟随~10，表示词组中的多个词之间的距离之和不超过10，则满足查询。</p> <p>所谓词之间的距离，即查询词组中词为满足和目标词组相同的最小移动次数。</p> <p>如索引中有词组"apple boy cat"。</p> <p>如果查询词为"apple boy cat"~0，则匹配。</p> <p>如果查询词为"boy apple cat"~2，距离设为2方能匹配，设为1则不能匹配。</p> <table width="215"> <tbody><tr> <td width="34"> <p>(0)</p> </td> <td width="56"> <p>boy</p> </td> <td width="61"> <p>apple</p> </td> <td width="62"> <p>cat</p> </td> </tr> <tr> <td width="34"> <p>(1)</p> </td> <td width="56"><br /></td> <td width="61"> <p>boy</p> <p>apple</p> </td> <td width="62"> <p>cat</p> </td> </tr> <tr> <td width="34"> <p>(2)</p> </td> <td width="56"> <p>apple</p> </td> <td width="61"> <p>boy</p> </td> <td width="62"> <p>cat</p> </td> </tr> </tbody></table> <p>如果查询词为"cat boy apple"~4，距离设为4方能匹配。</p> <table width="400"> <tbody><tr> <td width="100"> <p>(0)</p> </td> <td width="100"> <p>cat</p> </td> <td width="100"> <p>boy</p> </td> <td width="100"> <p>apple</p> </td> </tr> <tr> <td width="100"> <p>(1)</p> </td> <td width="100"><br /></td> <td width="100"> <p>cat</p> <p>boy</p> </td> <td width="100"> <p>apple</p> </td> </tr> <tr> <td width="100"> <p>(2)</p> </td> <td width="100"><br /></td> <td width="100"> <p>boy</p> </td> <td width="100"> <p>cat</p> <p>apple</p> </td> </tr> <tr> <td width="100"> <p>(3)</p> </td> <td width="100"><br /></td> <td width="100"> <p>boy</p> <p>apple</p> </td> <td width="100"> <p>cat</p> </td> </tr> <tr> <td width="100"> <p>(4)</p> </td> <td width="100"> <p>apple</p> </td> <td width="100"> <p>boy</p> </td> <td width="100"> <p>cat</p> </td> </tr> </tbody></table> <p>&nbsp;</p> <h3><strong>(7) 区间查询(Range)</strong></h3> <p>区间查询包含两种，一种是包含边界，用[A TO B]指定，一种是不包含边界，用{A TO B}指定。</p> <p>如date:[20020101 TO 20030101]，当然区间查询不仅仅用于时间，如title:{Aida TO Carmen}</p> <h3><strong>(8) 增加一个查询词的权重(Boost)</strong></h3> <p>可以在查询词后面加^N来设定此查询词的权重，默认是1，如果N大于1，则说明此查询词更重要，如果N小于1，则说明此查询词更不重要。</p> <p>如jakarta^4 apache，"jakarta apache"^4 "Apache Lucene"</p> <h3><strong>(9) 布尔操作符</strong></h3> <p>布尔操作符包括连接符，如AND，OR，和修饰符，如NOT，+，-。</p> <p>默认状态下，空格被认为是OR的关系，QueryParser.setDefaultOperator(Operator.AND)设置为空格为AND。</p> <p>+表示一个查询语句是必须满足的(required)，NOT和-表示一个查询语句是不能满足的(prohibited)。</p> <h3><strong>(10) 组合</strong></h3> <p>可以用括号，将查询语句进行组合，从而设定优先级。</p> <p>如(jakarta OR apache) AND website</p> <p>&nbsp;</p> <p>Lucene的查询语法是由QueryParser来进行解析，从而生成查询对象的。</p> <p>通过编译原理我们知道，解析一个语法表达式，需要经过词法分析和语法分析的过程，也即需要词法分析器和语法分析器。</p> <p>QueryParser是通过JavaCC来生成词法分析器和语法分析器的。</p> <p>&nbsp;</p> <h1><strong>二、JavaCC介绍</strong></h1> <p>本节例子基本出于JavaCC tutorial的文章，<a href="http://www.engr.mun.ca/%7Etheo/JavaCC-Tutorial/">http://www.engr.mun.ca/~theo/JavaCC-Tutorial/</a></p> <p>JavaCC是一个词法分析器和语法分析器的生成器。</p> <p>所谓词法分析器就是将一系列字符分成一个个的Token，并标记Token的分类。</p> <p>例如，对于下面的C语言程序：</p> <table width="400"><tbody><tr> <td width="400"> <p>int main() { </p> <p>&nbsp;&nbsp;&nbsp; return 0 ; </p> <p>}</p> </td> </tr></tbody></table> &nbsp;&nbsp;&nbsp; <p>将被分成以下的Token:</p> <table width="400"><tbody><tr> <td width="400"> <p>&#8220;int&#8221;, &#8220; &#8221;, &#8220;main&#8221;, &#8220;(&#8221;, &#8220;)&#8221;, </p> <p>&#8220;&#8221;,&#8220;{&#8221;, &#8220;\n&#8221;, &#8220;\t&#8221;, &#8220;return&#8221; </p> <p>&#8220;&#8221;,&#8220;0&#8221;,&#8220;&#8221;,&#8220;;&#8221;,&#8220;\n&#8221;, </p> <p>&#8220;}&#8221;, &#8220;\n&#8221;, &#8220;&#8221;</p> </td> </tr></tbody></table> <p>标记了Token的类型后如下：</p> <table width="400"><tbody><tr> <td width="400"> <p>KWINT, SPACE, ID, OPAR, CPAR, </p> <p>SPACE, OBRACE, SPACE, SPACE, KWRETURN, </p> <p>SPACE, OCTALCONST, SPACE, SEMICOLON, SPACE, </p> <p>CBRACE, SPACE, EOF</p> </td> </tr></tbody></table> <p>EOF表示文件的结束。</p> <p>词法分析器工作过程如图所示：</p> <p>&nbsp;</p> <p><img src="http://dl.iteye.com/upload/attachment/245906/94ff926c-0b0f-3580-a9d2-8bcc16c43fcb.jpg" alt="" height="386" width="476" /></p> <p>&nbsp;</p> <p>此一系列Token将被传给语法分析器(当然并不是所有的Token都会传给语法分析器，本例中SPACE就例外)，从而形成一棵语法分析树来表示程序的结构。</p> <p>&nbsp;</p> <p><img src="http://dl.iteye.com/upload/attachment/245908/a2d58ba2-3fe3-3400-bf06-b5a64759583c.jpg" alt="" height="536" width="446" /></p> <p>&nbsp;</p> <p>JavaCC本身既不是一个词法分析器，也不是一个语法分析器，而是根据指定的规则生成两者的生成器。</p> <h2><strong>2.1、第一个实例&#8212;&#8212;正整数相加</strong></h2> <p>下面我们来看第一个例子，即能够解析正整数相加的表达式，例如99+42+0+15。</p> <h3><strong>(1) 生成一个adder.jj文件</strong></h3> <p>此文件中写入的即生成词法分析器和语法分析器的规则。 </p> <h3><strong>(2) 设定选项，并声明类</strong></h3> <table width="727"><tbody><tr> <td width="725"> <p>&nbsp;</p> <p>/* adder.jj Adding up numbers */ </p> <p>options { </p> <p>&nbsp; STATIC = false ; </p> <p>} </p> <p>PARSER_BEGIN(Adder) </p> <p>class Adder { </p> <p>&nbsp; static void main( String[] args ) throws ParseException, TokenMgrError {  </p> <p>&nbsp;&nbsp;&nbsp; Adder parser = new Adder( System.in ) ; </p> <p>&nbsp;&nbsp;&nbsp; parser.Start() ; </p> <p>&nbsp; } </p> <p>} </p> <p>PARSER_END(Adder)</p> </td> </tr></tbody></table> <p>STATIC选项默认是true，设为false，使得生成的函数不是static的。 </p> <p>PARSER_BEGIN和PARSER_END之间的java代码部分，此部分不需要通过JavaCC根据规则生成java代码，而是直接拷贝到生成的java代码中的。  </p> <h3><strong>(3) 声明一个词法分析器</strong></h3> <table width="400"><tbody><tr> <td width="400"> <p>SKIP : { " " } </p> <p>SKIP : { "\n" | "\r" | "\r\n" } </p> <p>TOKEN : { &lt; PLUS : "+" &gt; } </p> <p>TOKEN : { &lt; NUMBER : (["0"-"9"])+ &gt; }</p> </td> </tr></tbody></table> <p>第一二行表示空格和回车换行是不会传给语法分析器的。 </p> <p>第三行声明了一个Token，名称为PLUS，符号为&#8220;+&#8221;。 </p> <p>第四行声明了一个Token，名称为NUMBER，符号位一个或多个0-9的数的组合。 </p> <p>如果词法分析器分析的表达式如下： </p> <ul><li>&#8220;123 + 456\n&#8221;，则分析为NUMBER, PLUS, NUMBER, EOF  </li><li>&#8220;123 - 456\n&#8221;，则报TokenMgrError，因为&#8220;-&#8221;不是一个有效的Token.  </li><li>&#8220;123 ++ 456\n&#8221;，则分析为NUMBER, PLUS, PLUS, NUMBER, EOF，词法分析正确，后面的语法分析将会错误。  </li></ul> <h3><strong>(4) 声明一个语法分析器</strong></h3> <table width="400"><tbody><tr> <td width="400"> <p>void Start() : </p> <p>{} </p> <p>{ </p> <p>&nbsp; &lt;NUMBER&gt; </p> <p>&nbsp; ( </p> <p>&nbsp;&nbsp;&nbsp; &lt;PLUS&gt; </p> <p>&nbsp;&nbsp;&nbsp; &lt;NUMBER&gt; </p> <p>&nbsp; )* </p> <p>&nbsp; &lt;EOF&gt; </p> <p>}</p> </td> </tr></tbody></table> <p>语法分析器使用BNF表达式。 </p> <p>上述声明将生成start函数，称为Adder类的一个成员函数 </p> <p>语法分析器要求输入的语句必须以NUMBER开始，以EOF结尾，中间是零到多个PLUS和NUMBER的组合。 </p> <h3><strong>(5) 用javacc编译adder.jj来生成语法分析器和词法分析器</strong></h3> <p>最后生成的adder.jj如下：</p> <table width="515"><tbody><tr> <td width="513"> <p>options <br />{ <br />&nbsp; static = false; <br />} </p> <p>PARSER_BEGIN(Adder) <br />package org.apache.javacc; </p> <p>public class Adder <br />{ <br />&nbsp; public static void main(String args []) throws  ParseException <br />&nbsp; { <br />&nbsp;&nbsp;&nbsp; Adder parser = new Adder(System.in); <br />&nbsp;&nbsp;&nbsp;  parser.start(); <br />&nbsp; } <br />} <br />PARSER_END(Adder) </p> <p>SKIP : <br />{ <br />&nbsp; " " <br />| "\r" <br />| "\t" <br />| "\n" <br />} </p> <p>TOKEN : /* OPERATORS */ <br />{ <br />&nbsp; &lt; PLUS : "+" &gt; <br />} </p> <p>TOKEN : <br />{ <br />&nbsp; &lt; NUMBER : ([ "0"-"9" ])+ &gt; <br />} </p> <p>void start() : <br />{} <br />{ <br />&nbsp; &lt;NUMBER&gt; <br />&nbsp; ( <br />&nbsp;&nbsp;&nbsp; &lt;PLUS&gt;  <br />&nbsp;&nbsp;&nbsp; &lt;NUMBER&gt; <br />&nbsp; )* <br />}</p> </td> </tr></tbody></table> <p>用JavaCC编译adder.jj生成如下文件：</p> <ul><li>Adder.java：语法分析器。其中的main函数是完全从adder.jj中拷贝的，而start函数是被javacc由adder.jj描述的规则生成的。  </li><li>AdderConstants.java：一些常量，如PLUS, NUMBER, EOF等。  </li><li>AdderTokenManager.java：词法分析器。  </li><li>ParseException.java：用于在语法分析错误的时候抛出。  </li><li>SimpleCharStream.java：用于将一系列字符串传入词法分析器。  </li><li>Token.java：代表词法分析后的一个个Token。Token对象有一个整型域kind，来表示此Token的类型(PLUS, NUMBER,  EOF)，有一个String类型的域image，来表示此Token的值。  </li><li>TokenMgrError.java：用于在词法分析错误的时候抛出。 </li></ul> <p>下面我们对adder.jj生成的start函数进行分析：</p> <table width="669"><tbody><tr> <td width="667"> <p>final public void start() throws ParseException {</p> <p>&nbsp; <strong>//从词法分析器取得下一个Token，而且要求必须是NUMBER类型，否则抛出异常。</strong></p> <p>&nbsp; <strong>//此步要求表达式第一个出现的字符必须是NUMBER。</strong></p> <p>&nbsp; jj_consume_token(NUMBER);</p> <p>&nbsp; label_1:</p> <p>&nbsp; while (true) {</p> <p>&nbsp;&nbsp;&nbsp; <strong>//jj_ntk()是取得下一个Token的类型，如果是PLUS，则继续进行，如果是EOF则退出循环。</strong></p> <p>&nbsp;&nbsp;&nbsp; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {</p> <p>&nbsp;&nbsp;&nbsp; case PLUS:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; default:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_la1[0] = jj_gen;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break label_1;</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp; <strong>//要求下一个PLUS字符，再下一个是一个NUMBER，如此下去。</strong></p> <p>&nbsp;&nbsp;&nbsp; jj_consume_token(PLUS);</p> <p>&nbsp;&nbsp;&nbsp; jj_consume_token(NUMBER);</p> <p>&nbsp; }</p> <p>}</p> </td> </tr></tbody></table> <h3><strong>(6) 运行Adder.java</strong></h3> <p>如果输入&#8220;123+456&#8221;则不报任何错误。</p> <p>如果输入&#8220;123++456&#8221;则报如下异常：</p> <table width="784"><tbody><tr> <td width="782"> <p>Exception in thread "main" org.apache.javacc.ParseException: Encountered "  "+" "+ "" at line 1, column 5. <br />Was expecting: <br />&nbsp;&nbsp;&nbsp; &lt;NUMBER&gt; ...  <br />&nbsp;&nbsp;&nbsp; at org.apache.javacc.Adder.generateParseException(Adder.java:185)  <br />&nbsp;&nbsp;&nbsp; at org.apache.javacc.Adder.jj_consume_token(Adder.java:123) <br />&nbsp;&nbsp;&nbsp; at  org.apache.javacc.Adder.start(Adder.java:24) <br />&nbsp;&nbsp;&nbsp; at  org.apache.javacc.Adder.main(Adder.java:8)</p> </td> </tr></tbody></table> <p>如果输入&#8220;123-456&#8221;则报如下异常：</p> <table width="925"><tbody><tr> <td width="923"> <p>Exception in thread "main" org.apache.javacc.TokenMgrError: Lexical error at  line 1, column 4.&nbsp; Encountered: "-" (45), after : "" <br />&nbsp;&nbsp;&nbsp; at  org.apache.javacc.AdderTokenManager.getNextToken(AdderTokenManager.java:262)  <br />&nbsp;&nbsp;&nbsp; at org.apache.javacc.Adder.jj_ntk(Adder.java:148) <br />&nbsp;&nbsp;&nbsp; at  org.apache.javacc.Adder.start(Adder.java:15) <br />&nbsp;&nbsp;&nbsp; at  org.apache.javacc.Adder.main(Adder.java:8)</p> </td> </tr></tbody></table> <h2><strong>2.2、扩展语法分析器</strong></h2> <p>在上面的例子中的start函数中，我们仅仅通过语法分析器来判断输入的语句是否正确。</p> <p>我们可以扩展BNF表达式，加入Java代码，使得经过语法分析后，得到我们想要的结果或者对象。</p> <p>我们将start函数改写为：</p> <table width="523"><tbody><tr> <td width="521"> <p>int start() throws NumberFormatException :</p> <p>{</p> <p>&nbsp; <strong>//start函数中有三个变量</strong></p> <p>&nbsp; Token t ;</p> <p>&nbsp; int i ;</p> <p>&nbsp; int value ;</p> <p>}</p> <p>{</p> <p>&nbsp; <strong>//首先要求表达式的第一个一定是一个NUMBER，并把其值付给t</strong></p> <p>&nbsp; t= &lt;NUMBER&gt;</p> <p>&nbsp; <strong>//将t的值取出来，解析为整型，放入变量i中</strong></p> <p>&nbsp; { i = Integer.parseInt( t.image ) ; }</p> <p>&nbsp; <strong>//最后的结果value设为i</strong></p> <p>&nbsp; { value = i ; }</p> <p>&nbsp; <strong>//紧接着应该是零个或者多个PLUS和NUMBER的组合</strong></p> <p>&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp; &lt;PLUS&gt;</p> <p>&nbsp;&nbsp;&nbsp; <strong>//每出现一个NUMBER，都将其付给t，并将t的值解析为整型，付给i</strong></p> <p>&nbsp;&nbsp;&nbsp; t= &lt;NUMBER&gt;</p> <p>&nbsp;&nbsp;&nbsp; { i = Integer.parseInt( t.image ) ; }</p> <p>&nbsp;&nbsp;&nbsp; <strong>//将i加到value上</strong></p> <p>&nbsp;&nbsp;&nbsp; { value += i ; }</p> <p>&nbsp; )*</p> <p>&nbsp; <strong>//最后的value就是表达式的和</strong></p> <p>&nbsp; { return value ; }</p> <p>}</p> </td> </tr></tbody></table> <p>生成的start函数如下：</p> <table width="530"><tbody><tr> <td width="528"> <p>final public int start() throws ParseException, NumberFormatException {</p> <p>&nbsp; Token t;</p> <p>&nbsp; int i;</p> <p>&nbsp; int value;</p> <p>&nbsp; t = jj_consume_token(NUMBER);</p> <p>&nbsp; i = Integer.parseInt(t.image);</p> <p>&nbsp; value = i;</p> <p>&nbsp; label_1: while (true) {</p> <p>&nbsp;&nbsp;&nbsp; switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {</p> <p>&nbsp;&nbsp;&nbsp; case PLUS:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; default:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_la1[0] = jj_gen;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break label_1;</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; jj_consume_token(PLUS);</p> <p>&nbsp;&nbsp;&nbsp; t = jj_consume_token(NUMBER);</p> <p>&nbsp;&nbsp;&nbsp; i = Integer.parseInt(t.image);</p> <p>&nbsp;&nbsp;&nbsp; value += i;</p> <p>&nbsp; }</p> <p>&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp; if (true)</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return value;</p> <p>&nbsp; }</p> <p>&nbsp; throw new Error("Missing return statement in function");</p> <p>}</p> </td> </tr></tbody></table> <p>从上面的例子，我们发现，把一个NUMBER取出，并解析为整型这一步是可以共用的，所以可以抽象为一个函数：</p> <table width="532"><tbody><tr> <td width="530"> <p>int start() throws NumberFormatException :</p> <p>{</p> <p>&nbsp; int i;</p> <p>&nbsp; int value ;</p> <p>}</p> <p>{</p> <p>&nbsp; value = getNextNumberValue()</p> <p>&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp; &lt;PLUS&gt;</p> <p>&nbsp;&nbsp;&nbsp; i = getNextNumberValue()</p> <p>&nbsp;&nbsp;&nbsp; { value += i ; }</p> <p>&nbsp; )*</p> <p>&nbsp; { return value ; }</p> <p>}</p> <p>int getNextNumberValue() throws NumberFormatException :</p> <p>{</p> <p>&nbsp; Token t ;</p> <p>}</p> <p>{</p> <p>&nbsp; t=&lt;NUMBER&gt;</p> <p>&nbsp; { return Integer.parseInt( t.image ) ; }</p> <p>}</p> </td> </tr></tbody></table> <p>生成的函数如下：</p> <table width="532"><tbody><tr> <td width="530"> <p>&nbsp;</p> <p>final public int start() throws ParseException, NumberFormatException {</p> <p>&nbsp; int i;</p> <p>&nbsp; int value;</p> <p>&nbsp; value = getNextNumberValue();</p> <p>&nbsp; label_1: while (true) {</p> <p>&nbsp;&nbsp;&nbsp; switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {</p> <p>&nbsp;&nbsp;&nbsp; case PLUS:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; default:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_la1[0] = jj_gen;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break label_1;</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; jj_consume_token(PLUS);</p> <p>&nbsp;&nbsp;&nbsp; i = getNextNumberValue();</p> <p>&nbsp;&nbsp;&nbsp; value += i;</p> <p>&nbsp; }</p> <p>&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp; if (true)</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return value;</p> <p>&nbsp; }</p> <p>&nbsp; throw new Error("Missing return statement in function");</p> <p>} </p> <p>final public int getNextNumberValue() throws ParseException,  NumberFormatException {</p> <p>&nbsp; Token t;</p> <p>&nbsp; t = jj_consume_token(NUMBER);</p> <p>&nbsp; {</p> <p>&nbsp;&nbsp;&nbsp; if (true)</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Integer.parseInt(t.image);</p> <p>&nbsp; }</p> <p>&nbsp; throw new Error("Missing return statement in function");</p> <p>}</p> </td> </tr></tbody></table> <p>&nbsp;</p> <h2><strong>2.3、第二个实例：计算器</strong></h2> <h3><strong>(1) 生成一个calculator.jj文件</strong></h3> <p>用于写入生成计算器词法分析器和语法分析器的规则。 </p> <h3><strong>(2) 设定选项，并声明类</strong></h3> <table width="763"><tbody><tr> <td width="761"> <p>options {</p> <p>STATIC = false ;</p> <p>}</p> <p>PARSER_BEGIN(Calculator)</p> <p>&nbsp; import java.io.PrintStream ;</p> <p>&nbsp; class Calculator {</p> <p>&nbsp;&nbsp;&nbsp; static void main( String[] args ) throws ParseException, TokenMgrError,  NumberFormatException {</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calculator parser = new Calculator( System.in ) ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parser.Start( System.out ) ;</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; double previousValue = 0.0 ;</p> <p>&nbsp; }</p> <p>PARSER_END(Calculator)</p> </td> </tr></tbody></table> <p>previousValue用来记录上一次计算的结果。</p> <h3><strong>(3) 声明一个词法分析器</strong></h3> <table width="761"><tbody><tr> <td width="759"> <p>SKIP : { " " }</p> <p>TOKEN : { &lt; EOL:"\n" | "\r" | "\r\n" &gt; }</p> <p>TOKEN : { &lt; PLUS : "+" &gt; }</p> </td> </tr></tbody></table> <p>我们想要支持小数，则有四种情况：没有小数，小数点在中间，小数点在前面，小数点在后面。则语法规则如下：</p> <table width="759"><tbody><tr> <td width="757"> <p>TOKEN { &lt; NUMBER : (["0"-"9"])+ | (["0"-"9"])+ "." (["0"-"9"])+ |  (["0"-"9"])+ "." | "." (["0"-"9"])+ &gt; }</p> </td> </tr></tbody></table> <p>由于同一个表达式["0"-"9"]使用了多次，因而我们可以定义变量，如下：</p> <table width="760"><tbody><tr> <td width="758"> <p>TOKEN : { &lt; NUMBER : &lt;DIGITS&gt; | &lt;DIGITS&gt; "." &lt;DIGITS&gt; |  &lt;DIGITS&gt; "." | "." &lt;DIGITS&gt;&gt; }</p> <p>TOKEN : { &lt; #DIGITS : (["0"-"9"])+ &gt; }</p> </td> </tr></tbody></table> <h3><strong>(4) 声明一个语法分析器</strong></h3> <p>我们想做的计算器包含多行，每行都是一个四则运算表达式，语法规则如下：</p> <table width="547"> <tbody><tr> <td width="545"> <p>Start -&gt; (Expression EOL)* EOF</p> </td> </tr> <tr> <td width="545"> <p>void Start(PrintStream printStream) throws NumberFormatException :</p> <p>{}</p> <p>{</p> <p>&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp; previousValue = Expression()</p> <p>&nbsp;&nbsp;&nbsp; &lt;EOL&gt;</p> <p>&nbsp;&nbsp;&nbsp; { printStream.println( previousValue ) ; }</p> <p>&nbsp; )*</p> <p>&nbsp; &lt;EOF&gt;</p> <p>}</p> </td> </tr> </tbody></table> <p>每一行的四则运算表达式如果只包含加法，则语法规则如下：</p> <table width="547"> <tbody><tr> <td width="545"> <p>Expression -&gt; Primary (PLUS Primary)*</p> </td> </tr> <tr> <td width="545"> <p>double Expression() throws NumberFormatException :</p> <p>{</p> <p>&nbsp; double i ;</p> <p>&nbsp; double value ;</p> <p>}</p> <p>{</p> <p>&nbsp; value = Primary()</p> <p>&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp; &lt;PLUS&gt;</p> <p>&nbsp;&nbsp;&nbsp; i= Primary()</p> <p>&nbsp;&nbsp;&nbsp; { value += i ; }</p> <p>&nbsp; )*</p> <p>&nbsp; { return value ; }</p> <p>}</p> </td> </tr> </tbody></table> <p>其中Primary()得到一个数的值：</p> <table width="547"><tbody><tr> <td width="545"> <p>double Primary() throws NumberFormatException :</p> <p>{</p> <p>&nbsp; Token t ;</p> <p>}</p> <p>{</p> <p>&nbsp; t= &lt;NUMBER&gt;</p> <p>&nbsp; { return Double.parseDouble( t.image ) ; }</p> <p>}</p> </td> </tr></tbody></table> <h3><strong>(5) 扩展词法分析器和语法分析器</strong></h3> <p>如果我们想支持减法，则需要在词法分析器中添加：</p> <table width="400"><tbody><tr> <td width="400"> <p>TOKEN : { &lt; MINUS : "-" &gt; }</p> </td> </tr></tbody></table> <p>语法分析器应该变为：</p> <table width="484"> <tbody><tr> <td width="482"> <p>Expression -&gt; Primary (PLUS Primary | MINUS Primary)*</p> </td> </tr> <tr> <td width="482"> <p>double Expression() throws NumberFormatException :</p> <p>{</p> <p>&nbsp; double i ;</p> <p>&nbsp; double value ;</p> <p>}</p> <p>{</p> <p>&nbsp; value = Primary()</p> <p>&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp; &lt;PLUS&gt;</p> <p>&nbsp;&nbsp;&nbsp; i = Primary()</p> <p>&nbsp;&nbsp;&nbsp; { value += i ; }</p> <p>&nbsp;&nbsp;&nbsp; |</p> <p>&nbsp;&nbsp;&nbsp; &lt;MINUS&gt;</p> <p>&nbsp;&nbsp;&nbsp; i = Primary()</p> <p>&nbsp;&nbsp;&nbsp; { value -= i ; }</p> <p>&nbsp; )*</p> <p>&nbsp; { return value ; }</p> <p>}</p> </td> </tr> </tbody></table> <p>如果我们想添加乘法和除法，则在词法分析器中应该加入：</p> <table width="484"><tbody><tr> <td width="482"> <p>TOKEN : { &lt; TIMES : "*" &gt; }</p> <p>TOKEN : { &lt; DIVIDE : "/" &gt; }</p> </td> </tr></tbody></table> <p>对于加减乘除混合运算，则应该考虑优先级，乘除的优先级高于加减，应该先做乘除，再做加减：</p> <table width="482"> <tbody><tr> <td width="480"> <p>Expression -&gt; Term (PLUSTerm | MINUSTerm)*</p> <p>Term -&gt; Primary (TIMES Primary | DIVIDE Primary)*</p> </td> </tr> <tr> <td width="480"> <p>double Expression() throws NumberFormatException :</p> <p>{</p> <p>&nbsp; double i ;</p> <p>&nbsp; double value ;</p> <p>}</p> <p>{</p> <p>&nbsp; value = Term()</p> <p>&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp; &lt;PLUS&gt;</p> <p>&nbsp;&nbsp;&nbsp; i= Term()</p> <p>&nbsp;&nbsp;&nbsp; { value += i ; }</p> <p>&nbsp;&nbsp;&nbsp; |</p> <p>&nbsp;&nbsp;&nbsp; &lt;MINUS&gt;</p> <p>&nbsp;&nbsp;&nbsp; i= Term()</p> <p>&nbsp;&nbsp;&nbsp; { value -= i ; }</p> <p>&nbsp; )*</p> <p>&nbsp; { return value ; }</p> <p>}</p> </td> </tr> <tr> <td width="480"> <p>double Term() throws NumberFormatException :</p> <p>{</p> <p>&nbsp; double i ;</p> <p>&nbsp; double value ;</p> <p>}</p> <p>{</p> <p>&nbsp; value = Primary()</p> <p>&nbsp; (</p> <p>&nbsp;&nbsp;&nbsp; &lt;TIMES&gt;</p> <p>&nbsp;&nbsp;&nbsp; i = Primary()</p> <p>&nbsp;&nbsp;&nbsp; { value *= i ; }</p> <p>&nbsp;&nbsp;&nbsp; |</p> <p>&nbsp;&nbsp;&nbsp; &lt;DIVIDE&gt;</p> <p>&nbsp;&nbsp;&nbsp; i = Primary()</p> <p>&nbsp;&nbsp;&nbsp; { value /= i ; }</p> <p>&nbsp; )*</p> <p>&nbsp; { return value ; }</p> <p>}</p> </td> </tr> </tbody></table> <p>下面我们要开始支持括号，负号，以及取得上一行四则运算表达式的值。</p> <p>对于词法分析器，我们添加如下Token：</p> <table width="400"><tbody><tr> <td width="400"> <p>TOKEN : { &lt; OPEN PAR : "(" &gt; }</p> <p>TOKEN : { &lt; CLOSE PAR : ")" &gt; }</p> <p>TOKEN : { &lt; PREVIOUS : "$" &gt; }</p> </td> </tr></tbody></table> <p>对于语法分析器，对于最基本的表达式，有四种情况：</p> <p>其可以是一个NUMBER，也可以是上一行四则运算表达式的值PREVIOUS，也可以是被括号括起来的一个子语法表达式，也可以是取负的一个基本语法表达式。</p> <table width="639"> <tbody><tr> <td width="637"> <p>Primary &#8211;&gt; NUMBER | PREVIOUS | OPEN_PAR Expression CLOSE_PAR | MINUS  Primary</p> </td> </tr> <tr> <td width="637"> <p>double Primary() throws NumberFormatException :</p> <p>{</p> <p>&nbsp; Token t ;</p> <p>&nbsp; double d ;</p> <p>}</p> <p>{</p> <p>&nbsp; t=&lt;NUMBER&gt;</p> <p>&nbsp; { return Double.parseDouble( t.image ) ; }</p> <p>&nbsp; |</p> <p>&nbsp; &lt;PREVIOUS&gt;</p> <p>&nbsp; { return previousValue ; }</p> <p>&nbsp; |</p> <p>&nbsp; &lt;OPEN PAR&gt; d=Expression() &lt;CLOSE PAR&gt;</p> <p>&nbsp; { return d ; }</p> <p>&nbsp; |</p> <p>&nbsp; &lt;MINUS&gt; d=Primary()</p> <p>&nbsp; { return -d ; }</p> <p>}</p> </td> </tr> </tbody></table> <h3><strong>(6) 用javacc编译calculator.jj来生成语法分析器和词法分析器</strong></h3> <p>最后生成的calculator.jj如下：</p> <table width="744"><tbody><tr> <td width="742"> <p>options <br />{ <br />&nbsp; static = false; <br />} </p> <p>PARSER_BEGIN(Calculator) <br />package org.apache.javacc.calculater; <br />&nbsp;  import java.io.PrintStream ; <br />&nbsp; class Calculator { <br />&nbsp;&nbsp;&nbsp; static void main(  String[] args ) throws ParseException, TokenMgrError, NumberFormatException {  <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calculator parser = new Calculator( System.in ) ; <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  parser.start( System.out ) ; <br />&nbsp;&nbsp;&nbsp; } <br />&nbsp;&nbsp;&nbsp; double previousValue = 0.0 ;  <br />&nbsp; } <br />PARSER_END(Calculator) </p> <p>SKIP : { " " } <br />TOKEN : { &lt; EOL: "\n" | "\r" | "\r\n" &gt; } <br />TOKEN  : { &lt; PLUS : "+" &gt; } <br />TOKEN : { &lt; MINUS : "-" &gt; } <br />TOKEN : {  &lt; TIMES : "*" &gt; } <br />TOKEN : { &lt; DIVIDE : "/" &gt; } <br />TOKEN : {  &lt; NUMBER : &lt;DIGITS&gt; | &lt;DIGITS&gt; "." &lt;DIGITS&gt; |  &lt;DIGITS&gt; "." | "." &lt;DIGITS&gt;&gt; } <br />TOKEN : { &lt; #DIGITS :  (["0"-"9"])+ &gt; } <br />TOKEN : { &lt; OPEN_PAR : "(" &gt; } <br />TOKEN : { &lt;  CLOSE_PAR : ")" &gt; } <br />TOKEN : { &lt; PREVIOUS : "$" &gt; } </p> <p>void start(PrintStream printStream) throws NumberFormatException : <br />{}  <br />{ <br />&nbsp; ( <br />&nbsp;&nbsp;&nbsp; previousValue = Expression() <br />&nbsp;&nbsp;&nbsp; {  printStream.println( previousValue ) ; } <br />&nbsp; )* <br />} </p> <p>double Expression() throws NumberFormatException : <br />{ <br />&nbsp; double i ;  <br />&nbsp; double value ; <br />} <br />{ <br />&nbsp; value = Term() <br />&nbsp; ( <br />&nbsp;&nbsp;&nbsp;  &lt;PLUS&gt; <br />&nbsp;&nbsp;&nbsp; i= Term() <br />&nbsp;&nbsp;&nbsp; { value += i ; } <br />&nbsp;&nbsp;&nbsp; | <br />&nbsp;&nbsp;&nbsp;  &lt;MINUS&gt; <br />&nbsp;&nbsp;&nbsp; i= Term() <br />&nbsp;&nbsp;&nbsp; { value -= i ; } <br />&nbsp; )* <br />&nbsp; { return  value ; } <br />} </p> <p>double Term() throws NumberFormatException : <br />{ <br />&nbsp; double i ; <br />&nbsp;  double value ; <br />} <br />{ <br />&nbsp; value = Primary() <br />&nbsp; ( <br />&nbsp;&nbsp;&nbsp; &lt;TIMES&gt;  <br />&nbsp;&nbsp;&nbsp; i = Primary() <br />&nbsp;&nbsp;&nbsp; { value *= i ; } <br />&nbsp;&nbsp;&nbsp; | <br />&nbsp;&nbsp;&nbsp; &lt;DIVIDE&gt;  <br />&nbsp;&nbsp;&nbsp; i = Primary() <br />&nbsp;&nbsp;&nbsp; { value /= i ; } <br />&nbsp; )* <br />&nbsp; { return value ; }  <br />} </p> <p>double Primary() throws NumberFormatException : <br />{ <br />&nbsp; Token t ; <br />&nbsp;  double d ; <br />} <br />{ <br />&nbsp; t=&lt;NUMBER&gt; <br />&nbsp; { return Double.parseDouble(  t.image ) ; } <br />&nbsp; | <br />&nbsp; &lt;PREVIOUS&gt; <br />&nbsp; { return previousValue ; }  <br />&nbsp; | <br />&nbsp; &lt;OPEN_PAR&gt; d=Expression() &lt;CLOSE_PAR&gt; <br />&nbsp; { return d  ; } <br />&nbsp; | <br />&nbsp; &lt;MINUS&gt; d=Primary() <br />&nbsp; { return -d ; }  <br />}</p> </td> </tr></tbody></table> <p>生成的start函数如下：</p>   <p>final public void start(PrintStream printStream) throws ParseException,  NumberFormatException {</p> <p>&nbsp; label_1:</p> <p>&nbsp; while (true) {</p> <p>&nbsp;&nbsp;&nbsp; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {</p> <p>&nbsp;&nbsp;&nbsp; case MINUS:</p> <p>&nbsp;&nbsp;&nbsp; case NUMBER:</p> <p>&nbsp;&nbsp;&nbsp; case OPEN_PAR:</p> <p>&nbsp;&nbsp;&nbsp; case PREVIOUS:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; default:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_la1[0] = jj_gen;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break label_1;</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; previousValue = Expression();</p> <p>&nbsp;&nbsp;&nbsp; printStream.println( previousValue ) ;</p> <p>&nbsp; }</p> <p>} </p> <p>final public double Expression() throws ParseException, NumberFormatException  {</p> <p>&nbsp; double i ;</p> <p>&nbsp; double value ;</p> <p>&nbsp; value = Term();</p> <p>&nbsp; label_2:</p> <p>&nbsp; while (true) {</p> <p>&nbsp;&nbsp;&nbsp; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {</p> <p>&nbsp;&nbsp;&nbsp; case PLUS:</p> <p>&nbsp;&nbsp;&nbsp; case MINUS:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; default:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_la1[1] = jj_gen;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break label_2;</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {</p> <p>&nbsp;&nbsp;&nbsp; case PLUS:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_consume_token(PLUS);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = Term();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value += i ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; case MINUS:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_consume_token(MINUS);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = Term();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value -= i ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; default:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_la1[2] = jj_gen;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_consume_token(-1);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ParseException();</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp; }</p> <p>&nbsp; {if (true) return value ;}</p> <p>&nbsp; throw new Error("Missing return statement in function");</p> <p>} </p> <p>final public double Term() throws ParseException, NumberFormatException {</p> <p>&nbsp; double i ;</p> <p>&nbsp; double value ;</p> <p>&nbsp; value = Primary();</p> <p>&nbsp; label_3:</p> <p>&nbsp; while (true) {</p> <p>&nbsp;&nbsp;&nbsp; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {</p> <p>&nbsp;&nbsp;&nbsp; case TIMES:</p> <p>&nbsp;&nbsp;&nbsp; case DIVIDE:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; default:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_la1[3] = jj_gen;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break label_3;</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp;&nbsp;&nbsp; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {</p> <p>&nbsp;&nbsp;&nbsp; case TIMES:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_consume_token(TIMES);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = Primary();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value *= i ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; case DIVIDE:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_consume_token(DIVIDE);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i = Primary();</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value /= i ;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp;&nbsp;&nbsp; default:</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_la1[4] = jj_gen;</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jj_consume_token(-1);</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw new ParseException();</p> <p>&nbsp;&nbsp;&nbsp; }</p> <p>&nbsp; }</p> <p>&nbsp; {if (true) return value ;}</p> <p>&nbsp; throw new Error("Missing return statement in function");</p> <p>} </p> <p>final public double Primary() throws ParseException, NumberFormatException  {</p> <p>&nbsp; Token t ;</p> <p>&nbsp; double d ;</p> <p>&nbsp; switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {</p> <p>&nbsp; case NUMBER:</p> <p>&nbsp;&nbsp;&nbsp; t = jj_consume_token(NUMBER);</p> <p>&nbsp;&nbsp;&nbsp; {if (true) return Double.parseDouble( t.image ) ;}</p> <p>&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp; case PREVIOUS:</p> <p>&nbsp;&nbsp;&nbsp; jj_consume_token(PREVIOUS);</p> <p>&nbsp;&nbsp;&nbsp; {if (true) return previousValue ;}</p> <p>&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp; case OPEN_PAR:</p> <p>&nbsp;&nbsp;&nbsp; jj_consume_token(OPEN_PAR);</p> <p>&nbsp;&nbsp;&nbsp; d = Expression();</p> <p>&nbsp;&nbsp;&nbsp; jj_consume_token(CLOSE_PAR);</p> <p>&nbsp;&nbsp;&nbsp; {if (true) return d ;}</p> <p>&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp; case MINUS:</p> <p>&nbsp;&nbsp;&nbsp; jj_consume_token(MINUS);</p> <p>&nbsp;&nbsp;&nbsp; d = Primary();</p> <p>&nbsp;&nbsp;&nbsp; {if (true) return -d ;}</p> <p>&nbsp;&nbsp;&nbsp; break;</p> <p>&nbsp; default:</p> <p>&nbsp;&nbsp;&nbsp; jj_la1[5] = jj_gen;</p> <p>&nbsp;&nbsp;&nbsp; jj_consume_token(-1);</p> <p>&nbsp;&nbsp;&nbsp; throw new ParseException();</p> <p>&nbsp; }</p> <p>&nbsp; throw new Error("Missing return statement in function");</p> <p>}</p></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/391192.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2012-11-12 11:58 <a href="http://www.blogjava.net/wangxinsh55/archive/2012/11/12/391192.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>