tag:blogger.com,1999:blog-26980628995921782962024-03-12T21:47:38.767-07:00倫倫3號Beta-Log技術扎記Beta倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.comBlogger74125tag:blogger.com,1999:blog-2698062899592178296.post-8205803364038557942013-10-03T23:18:00.000-07:002013-10-16T06:28:43.422-07:00[Xcode]產生iOS可用的jansson函式庫<h4>
序言</h4>
<a href="http://www.digip.org/jansson/" target="_blank"> jansson</a>函式庫是一個使用C語言開發的JSON編解譯的工具,<br />
<br />
理論上應該是可以在不同環境下編譯後就能產生對應的函式庫檔來使用。<br />
<br />
不過似乎從<a href="https://github.com/akheron/jansson/issues/94" target="_blank">別人的發問與官方的回應</a>下並沒有針對iOS給出一個確切的答案回答能不能使用。<br />
<br />
經過嘗試之後,發現有另一個函式庫:<a href="https://github.com/NetEase/libpomelo" target="_blank">libpomelo</a>裡面有使用到這個函式庫,而這個函式庫目前也支援Andorid與iOS。<br />
<br />
並且在我編譯過libpomelo就會產生jansson的函式庫,所以以下的步驟就是編譯過程與從中取得jansson函式庫檔。<br />
<br />
<div>
<div>
<h4>
環境</h4>
<ul>
<li>mac mini+New iPad with iOS 6.1<br />
<br />
</li>
<li>Xcode 4.6</li>
<li><a href="https://github.com/NetEase/libpomelo" target="_blank">libpomelo</a> 0.3<br />
<br />
</li>
</ul>
<h4>
命令</h4>
開啟Terminal,依序輸入以下命令<br />
<br />
<pre><code>svn checkout https://github.com/NetEase/libpomelo.git/trunk libpomelo
cd libpomelo
svn checkout http://gyp.googlecode.com/svn/trunk/ gyp-read-only
cd gyp-read-only
./setup.py build
cd ..
sudo ./gyp-read-only/gyp --depth=. pomelo.gyp -Dlibrary=static_library -DTO=ios
./build_ios
./build_iossim
</code></pre>
<br />
<br />
<h4>
命令解釋</h4>
<ol>
<li>下載目前最新版的libpomelo</li>
<li>進入下載後的目錄</li>
<li>因為libpomelo的編譯是透過gyp這個工具,所以下載這個工具</li>
<li>進入gyp目錄</li>
<li>編譯gyp</li>
<li>離開gyp目錄</li>
<li>連結libpomelo</li>
<li>編譯ios版函式庫</li>
<li>編譯ios模擬器版函式庫</li>
</ol>
</div>
<div>
<h4>
設定函式庫</h4>
以下要做的動作不是必要的。<br />
我這邊依據我所需要的狀況,將函式庫複製到我的Xcode專案目錄並且命名為習慣的檔名。<br />
<br />
<br />
<ol>
<li>從libpomelo的子目錄[deps/jansson/build/Default-iphoneos]與[deps/jansson/build/Default-iphonesimulator]會找到兩個同名的[libjansson.a]</li>
<li>將這兩個檔案複製到自己專案的根目錄,分別命名為[libjansson-device.a]與[libjansson-simulator.a]</li>
<li>設定的方式為點選專案的[TARGETS→Build Phases→Link Binary With Libraries],點選下面的[+]<br />
<br />
加入剛才複製過來的兩個.a檔[libjansson-device.a]與[libjansson-simulator.a]</li>
<li>從libpomelo的子目錄[deps/jansson]複製[src]目錄到自己專案的根目錄命名為[jansson]</li>
<li>專案的[TARGETS→Build Settings→Search Paths],設定[Header Search Paths],加入"$(SRCROOT)/jansson"</li>
</ol>
<h4>
使用範例</h4>
這邊只寫個小程式測試編譯後可以執行,詳細CURL用法請參考相關文章<br />
<br />
<br />
<pre><code>#include <jansson.h>
void myLib_test2(){
json_t *jdata;
char cmd_ark_id[] = "id";
char ark_id[] = "value";
jdata = json_pack("{s:s}",
cmd_ark_id,ark_id);
char *j_object;//json
j_object = json_dumps( jdata, 0 );
json_decref( jdata );
printf("%s",j_object);
}
</code></pre>
<h4>
參考文章</h4>
<ul>
<li><a href="https://github.com/NetEase/pomelo/wiki/Home-in-Chinese" target="_blank">libpomelo Wiki</a></li>
<li><a href="http://blog.csdn.net/aryang/article/details/8875603" target="_blank">pomelo学习笔记 (4) libpomelo 编译静态库加入cocos2d-x xcode 项目</a></li>
<li><a href="http://blog.csdn.net/x_genius/article/details/9467679" target="_blank">Xcode中加载pomelo静态库libpomelo.a </a><br />
<br />
</li>
<li><a href="http://blog.csdn.net/hsyj_0001/article/details/9751819" target="_blank">吐槽Mac OS 下libpomelo的安装过程 By hsyj_0001的专栏</a><br />
<br />
</li>
<li><a href="http://allen080.blogspot.tw/2013/10/xcodelibcurlxproject.html">[Xcode]簡易加入libcurl到Xproject</a><br />
<br />
</li>
</ul>
</div>
</div>
倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-1367821912304934132013-10-02T22:58:00.001-07:002013-10-03T22:45:43.549-07:00[Xcode]簡易加入libcurl到Xproject<h4>序言</h4>Curl函式庫常使用在進行<a href="http://allen080.blogspot.tw/2011/06/chttp-getpostcurl.html">Http的操作</a>,這篇文章將使用已編譯完成的libcurl(來源為<a href="http://home.comcast.net/~seiryu/" target="_blank">Nick's software</a>)加入一個Xcode的Project所需的設定。<br><br />
<h4 style="margin:5px 0px;color:rgb(51,51,51)">環境</h4><ul><li>mac mini+New iPad with iOS 6.1<br><br />
</li>
<li>Xcode 4.6<br><br />
</li>
<li><a href="http://home.comcast.net/~seiryu/libcurl-ios.html" target="_blank">libcurl for iOS 7.32.0</a>(<a href="https://docs.google.com/file/d/0B0Im4FuW_SD7NWt1RUI1ZHNCWmc/edit?usp=sharing" target="_blank">備份下載點</a>)<br><br />
</li></ul><div><h4>設定函式庫</h4><ol><li>下載ioscurl-7.32.0.tar.gz,解壓縮後可以得到[ioscurl-7.32.0]目錄</li>
<li>進入[ioscurl-7.32.0/iOScURL]目錄會找到[libcurl-device.a]與[libcurl-simulator.a]兩個檔案與一個[curl]目錄,將這三個東西複製到自己專案的根目錄。<br><br />
(同層目錄下也有一個xCode的Project可以做為設定的參考)<br><br />
<div style="display:block;text-align:left"><a href="http://imageshack.us/a/img51/5443/lk0l.jpg" imageanchor="1"><img alt="壓縮檔內的檔案" src="http://imageshack.us/a/img51/5443/lk0l.jpg" border="0"></a></div><br><br />
</li>
<li>在專案中加入所需要的函式庫。<br><br />
設定的方式為點選專案的[TARGETS→Build Phases→Link Binary With Libraries],點選下面的[+]<br><br />
加入iOS原有的[Security.framework]、[libz.dylib]與剛才複製過來的兩個.a檔[libcurl-device.a][libcurl-simulator.a]<br />
<div style="display:block;text-align:left"><a href="http://imageshack.us/a/img94/6944/t1d9.jpg" imageanchor="1"><img alt="設定後的函式庫" src="http://imageshack.us/a/img94/6944/t1d9.jpg" border="0" height="220" width="400"></a></div></li>
<li>專案的[TARGETS→Build Settings→Search Paths],設定[Header Search Paths],加入"$(SRCROOT)/curl"<br><br />
</li>
</ol></div><div><div><h4>使用範例</h4><p>這邊只寫個小程式測試編譯後可以執行,詳細CURL用法請參考相關文章<br><br />
</p><pre><code>#ifndef xcurl_myLib_h<br>#define xcurl_myLib_h<br><br>#include <curl.h><br>int myLib_test1(){<br> curl_global_init(CURL_GLOBAL_ALL);<br> CURL *curl;<br> CURLcode res;<br> curl=curl_easy_init();<br> {<br> curl_easy_setopt(curl, CURLOPT_URL,"http://www.google.com.tw");<br> res=curl_easy_perform(curl);<br> curl_easy_cleanup(curl);<br> }<br> <br> return (int)res;<br>}<br><br>#endif<br></code></pre><h4>相關文章</h4><ul><li><a href="http://allen080.blogspot.tw/2011/06/chttp-getpostcurl.html">[C++]Http Get與Post函式(Curl)</a></li>
<li><a href="http://joylocus.com/2012/01/iphone-curl/" target="_blank">编译用在iPhone的curl静态库 By JoyLocus | 玩迹</a><br><br />
</li></ul></div></div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-56926455987654982332013-03-16T19:15:00.001-07:002013-05-21T20:00:08.417-07:00[Android x86]安裝在SD卡上<h1></h1><h1>序</h1>心血來潮~想在我的NB試試Android~ <br />
不過因為原本的硬碟是空間小小的SSD~ <br />
我也不想把原本安裝在上面的Windows直接覆蓋掉~ <br />
所以就想著如果能直接把Android裝在SD卡或USB上~這樣似乎不錯~ <br />
如果能直接安裝在SD卡上更好,因為我的NB上有內建讀卡機~ <br />
這樣機器就不會凸出一個大大的USB隨身碟~ <br />
而實際上嘗試過後~雖然一開始不順利~但最後還真的可以達成~ <br />
以下是我的作法~ <br />
<h1>安裝環境</h1><ul><li>最少要有個支援USB的電腦(我的有支援用讀卡機開機~所以也能支援使用SD卡) </li>
<li>以下步驟是使用Windows7建立安裝用的USB與預訂安裝Android的SD卡 </li>
<li>SD卡~建議準備一張2G以上速度快一點的~最少要有1G會比較實用 </li>
<li>一個500MB以上的隨身碟,要當作安裝來源開機USB </li>
</ul><h1>下載檔案與工具</h1><ul><li>Android x86 <br />
我一開始是試<a href="http://www.android-x86.org/download" target="_blank">官方的版本</a>~最新版可以用的中文輸入法不好用~<br />
舊版需要抓關機用的App(如<a href="https://play.google.com/store/apps/details?id=tw.abgne.rebootcontrol&feature=search_result#?t=W251bGwsMSwxLDEsInR3LmFiZ25lLnJlYm9vdGNvbnRyb2wiXQ..">Reboot control</a>),不然我不知怎麼關機~ <br />
後來是抓非官方<a href="http://blog.gambliser.com/dl/?p=990" target="_blank">支援網路卡的版本</a>~一樣是舊版~關機的問題一樣</li>
<li><a href="http://www.partitionwizard.com/free-partition-manager.html" target="_blank">MiniTool Partition Wizard</a> </li>
<li><a href="http://unetbootin.sourceforge.net/" target="_blank">Unetbootin</a> </li>
</ul><h1>安裝步驟</h1><h2>1.分割SD卡</h2>基本上不分割也能執行~也可以在電腦上同時外接多個USB當作額外的儲存空間~ <br />
不過我比較希望我這張SD卡既能當主硬碟又能當額外的空間~ <br />
So~~~我打算把SD卡切成兩個區塊~一個當主硬碟一個當儲存空間 <br />
<ul><li>開啟MiniTool Partition Wizard(操作方法可自行參考<a href="http://zakipush.blogspot.tw/2012/01/minitool-partition-wizardext3ext4.html" target="_blank">網路上的文章</a>) </li>
<li>選擇SD卡後,把所有的空間都刪除(當然如果你裡面有資料請先移到別的地方去…) </li>
<li>我這邊希望的是資料空間也能被Windows讀取,所以第一個區塊是資料區塊。設成<strong>Primary</strong>,格式化為Fat32,空間大小隨便,但建議剩餘空間留個1G以上~最好有2G給第二個區塊 </li>
<li>第二個區塊式系統區塊,設成<strong>Primary</strong>,格式化為Ext3,空間大小為1G以上~最好有2G </li>
<li>最後點Apply,開始進行分割與格式化 </li>
</ul><h2>2.建立安裝用的USB</h2>這一步是把下載下來的Android x86 ISO檔放到USB裡做為安裝來源的開機USB~ <br />
<ul><li>開啟Unetbootin(操作方法可自行參考<a href="http://sofree.cc/unetbootin/" target="_blank">網路上的文章</a>) </li>
<li>選擇ISO檔與目標的USB,再來就開始建立 </li>
</ul><h2>3.開機設定</h2>再來就可以把USB與SD卡都插上,重新開機,然後進BIOS畫面 <br />
把第一個Boot的優先權設為USB,把第二優先權設為SD卡(讀卡機) <br />
<h2>4.安裝Android x86到SD卡</h2>使用USB開機後,會出現Live CD與安裝的選單 <br />
<ul><li>選擇最底下的[Installation - Install Android-x86 to harddisk] </li>
<li>選擇分割區,選到剛才在SD卡建立的Ext3分割區 </li>
<li>如果他問你要不要Format,使用Ext3 </li>
<li>然後會問要不要安裝GRUB開機管理程式,選擇Yes(我試過不安裝,會無法順利開機) </li>
<li>然後問要不要讓system可讀寫,選擇是 </li>
<li>再來就會開始安裝,這中間會有段時間只有藍色畫面,不要心急,等他跳出詢問要不要直接執行或是重新開機 </li>
<li>選擇重新開機,並把開機用的USB隨身碟拔除,讓它用SD卡開機 </li>
<li>再來就是耐心的等Android開機完成就大功告成了(這時候就是不成功~便成仁~禱告吧XD) </li>
</ul><h2>5.BIOS開機順序</h2><p>成功後~我把BIOS開機順序設定成 先讀讀卡機,再讀硬碟~</p><p>這樣想用Android就把SD卡插進去開機,平常還是可以用原本的windows~</p><h2></h2><h2>6.安裝檔案瀏覽器</h2><p>安裝<a href="https://play.google.com/store/apps/details?id=com.estrongs.android.pop&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS5lc3Ryb25ncy5hbmRyb2lkLnBvcCJd">ES檔案瀏覽器</a>或<a href="https://play.google.com/store/apps/details?id=com.jrummy.root.browserfree&hl=zh_TW" target="_blank">Root browser lite</a>後,就可以在mnt/USB0目錄找到SD卡中分割的區塊</p><p>之後如果外接更多儲存設備也可以這樣存取 <br />
</p><h1>後記</h1>使用上雖然還是有些小問題,像是youtube 不能用HD播放~輸入法不容易習慣~ <br />
還有一堆以ARM為基礎的App都不能裝(雖然有<a href="http://jackiechin.blogspot.tw/2013/01/android-x86.html">文章</a>有提到解決方法-<a href="http://androvm.org/blog/ex-buildroid/2012/06/18/using-arm-emulation-on-other-android-x86-distributions/">ARM emulation</a>,但我還是試不出來)<br />
但能在NB用Abdroid還是很感動~~~倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-54963260103538929902013-02-21T21:14:00.002-08:002013-02-21T21:14:50.769-08:00[Unity]加入Subversion(SVN)的步驟將Unity加入Subversion(SVN)的步驟<br />
可參考<br />
<ul>
<li><a href="http://docs.unity3d.com/Documentation/Manual/ExternalVersionControlSystemSupport.html" target="_blank">Using External Version Control Systems with Unity</a></li>
<li><a href="http://mhmmd.org/unity/correctly-using-external-vcs-with-unity3d/" target="_blank">Correctly using external Version Control Systems with Unity</a></li>
</ul>
但不能直接砍掉整個Library目錄<br />
實際步驟如下<br />
<br />
<ol>
<li><b>*建議在開始前先備份整個Unity專案目錄</b></li>
<li>在Unity開發程式中選擇Edit → Project Settings → Editor<br />
<a href="http://1.bp.blogspot.com/-8TKsjWM3xUc/USb-DsI2DlI/AAAAAAAACK4/F1PoC8t7kbU/s1600/01.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://1.bp.blogspot.com/-8TKsjWM3xUc/USb-DsI2DlI/AAAAAAAACK4/F1PoC8t7kbU/s320/01.jpg" width="196" /></a><br />
</li>
<li>Inspector中會出現Editor Settings,將Version Control Mode改為Meta Files、Asset Serialization Mode改為Force Text<br />
<a href="http://3.bp.blogspot.com/-lF3XeHLNLUo/USb-ddRuEpI/AAAAAAAACLA/UvPz-uk9nUA/s1600/02.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-lF3XeHLNLUo/USb-ddRuEpI/AAAAAAAACLA/UvPz-uk9nUA/s1600/02.jpg" /></a><br />
</li>
<li>儲存後關閉整個Unity,確保所有設定都被儲存了</li>
<li>刪除根目錄的以下附檔名檔案<br />
*.csproj<br />
*.pidb<br />
*.sln<br />
*.userprefs</li>
<li><b>保留</b>Library目錄的*.asset與AssetServerCacheV3檔案,刪除其他Library目錄的檔案與子目錄<br />
<a href="http://1.bp.blogspot.com/-p04O_Mslyls/USb-eOBvReI/AAAAAAAACLI/-CpM2fiAqvg/s1600/03.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-p04O_Mslyls/USb-eOBvReI/AAAAAAAACLI/-CpM2fiAqvg/s1600/03.jpg" /></a><br />
</li>
<li>將整個Unity專案目錄Import到SVN,並Check out出來用Unity開啟來看看有沒有問題</li>
</ol>
倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-74777231285477588912011-06-25T04:08:00.000-07:002011-06-25T04:08:00.145-07:00[MS-SQL]不具自動容錯移轉的鏡像設定<div>
<h4 style="margin:5px 0px;color:rgb(51, 51, 51)">序</h4>
<p>以下的資料庫鏡像架構大致上就是</p>
<p>應用程式==data==>主體伺服器==data==>鏡像伺服器<br>
</p>
<h4 style="margin:5px 0px;color:rgb(51, 51, 51)">環境</h4>
<p>兩台一樣環境的伺服器<br>
</p>
<ul><li>Windows Server 2003 R2</li>
<li>Microsoft SQL Server 2008 R2</li>
<li>Microsoft SQL Server Management Studio 10.0.1600.22<br>
</li></ul>
<h4>SQL Server服務啟動帳號設定
</h4>
<ol><li>在windows服務(services.msc) 列表中,找到SQL Server,右鍵選內容或雙擊<br>
<img src="http://img855.imageshack.us/img855/2489/image003dt.jpg">
</li>
<li>後選擇登入頁,在此帳戶中這裡配置登錄用戶和密碼,這個地方建議兩台伺服器都配置一組一樣的帳號,並將此帳戶加到SQL Server的管理帳戶,後續的鏡像會用這組帳號繼續設定<br>
<img src="http://img837.imageshack.us/img837/7831/image004vn.jpg"></li>
<li>SQL Server Agent 啟動帳號也一樣設置<br>
<img src="http://img155.imageshack.us/img155/9727/image005pm.jpg">
</li>
</ol>
<h4>主體伺服器備份</h4>
<ol><li>在主體伺服器用windows帳戶登入Management Studio工具,這個動作是為了後續使用語法產生SQL檔時才不會有權限錯誤</li>
<li>產生資料庫建立語法<br>
以物件總管詳細資料選取需要鏡像的資料庫,並產生Create語法(選檔案即可產生.sql檔)<br>
<img src="http://img221.imageshack.us/img221/770/image006szljvi.jpg"></li>
<li>匯出每個資料庫的備份檔
<pre><code>backup database [DataBaseName1] to disk='D:\dbbackup\[DataBaseName1].bak' with init<br>GO<br>backup database [DataBaseName2] to disk='D:\dbbackup\[DataBaseName2].bak' with init<br>GO</code></pre>
</li>
<li>匯出每個資料庫的記錄檔
<pre><code>BACKUP LOG [DataBaseName1] TO DISK = 'D:\dbbackup\[DataBaseName1].log'<br>GO<br>BACKUP LOG [DataBaseName2] TO DISK = 'D:\dbbackup\[DataBaseName2].log'<br>GO</code></pre>
</li>
</ol>
</div>
<br>
<h4>還原資料到鏡像伺服器<br>
</h4>
<ol><li>將上一步驟產生的檔案(含*.sql、*.bak、*.log)所在dbbackup資料夾複製到鏡像資料庫</li>
<li>在鏡像伺服器用windows帳戶登入Management Studio工具</li>
<li>建立資料庫:以Management Studio開啟建立資料庫用的sql檔並執行,即可產生與主體伺服器相同名稱的資料庫</li>
<li>還原資料
<pre><code>restore database [DataBaseName1] from disk='D:\backupz\[DataBaseName1].bak' with replace,norecovery<br>GO<br>restore database [DataBaseName2] from disk='D:\backupz\[DataBaseName2].bak' with replace,norecovery<br>GO</code></pre>
</li>
<li>還原記錄檔
<pre><code>RESTORE LOG [DataBaseName1] FROM DISK = 'D:\backupz\[DataBaseName1].log' WITH FILE=1, NORECOVERY<br>GO<br>RESTORE LOG [DataBaseName2] FROM DISK = 'D:\backupz\[DataBaseName2].log' WITH FILE=1, NORECOVERY<br>GO</code></pre>
</li>
<li>成功後會看到建立起來的資料庫名稱後面會出現(正在還原...)的狀態</li>
</ol>
<h4>於主體伺服器啟動鏡像服務<br>
</h4>
<div>
<ol><li>
在主體伺服器的資料庫上點右鍵,選屬性,並選擇[鏡像]頁籤。接著點選[設定安全性]鈕就會開啟[設定資料庫鏡像安全性精靈]
<br>
<a href="http://imageshack.us/photo/my-images/641/image007mz.jpg/" target="_blank"><img src="http://img641.imageshack.us/img641/3188/image007mz.th.jpg" border="0"></a><a href="http://imageshack.us/photo/my-images/193/image008bf.jpg/" target="_blank"><img src="http://img193.imageshack.us/img193/3014/image008bf.th.jpg" border="0"></a>
<br>
</li>
<li>
於見證伺服器選擇頁選擇否,不使用見證伺服器<br>
<a href="http://imageshack.us/photo/my-images/21/image009mr.jpg/" target="_blank"><img src="http://img21.imageshack.us/img21/2548/image009mr.th.jpg" border="0"></a>
<br>
</li>
<li>第一次使用鏡像設定會選擇本機的鏡像服務Port與鏡像端點名稱,此處採用預設值即可<br>
<a href="http://imageshack.us/photo/my-images/6/image010lx.jpg/" target="_blank"><img src="http://img6.imageshack.us/img6/7771/image010lx.th.jpg" border="0"></a>
<br>
</li>
<li>設定鏡像伺服器的連線資訊<br>
<a href="http://imageshack.us/photo/my-images/23/image011uv.jpg/" target="_blank"><img src="http://img23.imageshack.us/img23/4626/image011uv.th.jpg" border="0"></a>
<br>
</li>
<li>服務帳戶不用設定<br>
<a href="http://imageshack.us/photo/my-images/846/image012sc.jpg/" target="_blank"><img src="http://img846.imageshack.us/img846/9114/image012sc.th.jpg" border="0"></a>
<br>
</li>
<li>完成後就會進行設定,第一次設定時會自動產生服務端點,這時就會啟動服務的Port<br>
<a href="http://imageshack.us/photo/my-images/703/image013a.jpg/" target="_blank"><img src="http://img703.imageshack.us/img703/6905/image013a.th.jpg" border="0"></a>
<br>
</li>
<li>完成後會詢問是否要啟動鏡像,選擇不要啟動鏡像。這時如果直接啟動如果連線網域名稱錯誤就會失敗(而且還不給設定…)<br>
<a href="http://imageshack.us/photo/my-images/146/image014doa.jpg/" target="_blank"><img src="http://img146.imageshack.us/img146/7673/image014doa.th.jpg" border="0"></a>
<br>
</li>
<li>接著就可以在伺服器網路位址確認鏡像伺服器的連線資訊<br>
<a href="http://imageshack.us/photo/my-images/842/image016dt.jpg/" target="_blank"><img src="http://img842.imageshack.us/img842/223/image016dt.th.jpg" border="0"></a>
<br>
需注意的是他有個奇怪的驗證,就是預設他會把鏡像伺服器的電腦名稱帶到鏡像的位址,但他的預設格式是[電腦名稱.網域名稱],沒有網域名稱時就必須在電腦名稱後面加一個句點.,否則你就會看到下面的錯誤<br>
<a href="http://imageshack.us/photo/my-images/850/image017lx.jpg/" target="_blank"><img src="http://img850.imageshack.us/img850/6229/image017lx.th.jpg" border="0"></a>
<br>
</li>
<li>啟動成功後如下圖<br>
<a href="http://imageshack.us/photo/my-images/834/image018dj.jpg/" target="_blank"><img src="http://img834.imageshack.us/img834/9278/image018dj.th.jpg" border="0"></a>
<br>
</li>
<li>重覆此上述動作把所有資料庫的鏡像都啟動<br>
</li>
</ol>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-84611009526170572312011-06-24T01:23:00.000-07:002011-06-24T01:23:00.843-07:00[C#]MS-SQL資料庫存取函式<h4>序言</h4>
我將C#存取MS-SQL的程式包了一層方便使用。<br>
<h4 style="margin:5px 0px;color:rgb(51, 51, 51)">環境</h4>
<ul><li>VS2008</li>
<li>MS-SQL 2008<br>
</li></ul>
<h4>存取函式類別
</h4>
<div>
<pre><code>using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Text;
using System.Data;
namespace MyCommon.DAO
{
///
/// MS-SQL連線物件
///
public class MSSQLBaseIO
{
SqlConnection sqlConn = null;
///
/// 建立連線物件
///
/// 連線字串,如Data Source=localhost;Initial Catalog=dbName;User id=Account;Password=Password;
public MSSQLBaseIO(string connectionString)
{
sqlConn = new SqlConnection(connectionString);
}
///
/// 建立連線物件
///
/// 可為localhost / domainname / 或 IP
/// 若Host為IP,則需為true
/// 不設定則填0,則會用MSSQL預設port
/// 不設定則填null,express版預設為SQLEXPRESS,正式版預設為MSSQLSERVER,從服務組態可以看到
/// 資料庫名稱
/// 是否使用 Windows 整合驗証方式連線,false則必需填帳號密碼
/// 登入帳號
/// 登入密碼
/// 連線逾期,不設定則填0
public MSSQLBaseIO(string host,bool isHostIP,int port,
string instanceName, string dbName,
bool isIntegratedSecurity,
string id, string password,
int timeout)
{
StringBuilder connectionString = new StringBuilder();
if (isHostIP) connectionString.Append("Data Source=tcp:" + host);
else connectionString.Append("Data Source=" + host);
if (instanceName != null) connectionString.Append("\\" + instanceName);
if (port != 0) connectionString.Append("," + port);
connectionString.Append(";");
connectionString.Append("Initial Catalog=" + dbName + ";");
if (isIntegratedSecurity) connectionString.Append("integrated security=true;");
if (id!=null) connectionString.Append("User id=" + id + ";");
if (password!=null) connectionString.Append("Password=" + password + ";");
if (timeout>0) connectionString.Append("Connect Timeout=" + timeout + ";");
sqlConn = new SqlConnection(connectionString.ToString());
}
///
/// 取得目前連線物件
///
///
public SqlConnection getConnection()
{
return sqlConn;
}
Exception _exception = null;
///
/// 取得上次執行後的錯誤
///
///
public Exception getException(){
return _exception;
}
///
/// 關閉連線
///
public void closeConn()
{
closeConn(true);
}
///
/// 關閉連線
///
/// 是否關閉連線
public void closeConn(bool isCloseConn){
if (sqlConn != null && isCloseConn && sqlConn.State!=System.Data.ConnectionState.Closed)
{
sqlConn.Close();
}
}
///
/// 取得新的Transaction物件
///
/// Transaction物件
public SqlTransaction getNewTransaction()
{
if (sqlConn.State != System.Data.ConnectionState.Open)
sqlConn.Open();
return sqlConn.BeginTransaction();
}
///
/// 執行SQL命令,執行後會關閉SQL連線
///
/// SQL命令
/// 是否為預存程序
/// 變動筆數
public int ExecuteNonQuery(string sqlcmd, bool isStoredProcedure)
{
return ExecuteNonQuery(sqlcmd,isStoredProcedure, true);
}
///
/// 執行SQL命令
///
/// SQL命令
/// 是否為預存程序
/// 是否關閉連線
/// 變動筆數
public int ExecuteNonQuery(string sqlcmd, bool isStoredProcedure, bool isCloseConn)
{
SqlParameter[] sqlparams = null;
return ExecuteNonQuery(sqlcmd, ref sqlparams, isStoredProcedure, isCloseConn);
}
///
/// 執行SQL命令
///
/// SQL命令
/// 命令參數,可為null,參數名稱為 @參數名稱
/// 是否為預存程序
/// 是否關閉連線
/// 變動筆數
public int ExecuteNonQuery(string sqlcmd, ref SqlParameter[] sqlparams, bool isStoredProcedure, bool isCloseConn)
{
return ExecuteNonQuery(sqlcmd, ref sqlparams, isStoredProcedure, null, isCloseConn);
}
///
/// 執行SQL命令
///
/// SQL命令
/// 命令參數,可為null,參數名稱為 @參數名稱
/// 是否為預存程序
/// SqlTransaction,可為null
/// 是否關閉連線
/// 變動筆數
public int ExecuteNonQuery(string sqlcmd, ref SqlParameter[] sqlparams,bool isStoredProcedure, SqlTransaction trans, bool isCloseConn)
{
int result = -1;
_exception = null;
try
{
if (sqlConn.State != System.Data.ConnectionState.Open)
sqlConn.Open();
SqlCommand cmd;
if (trans==null)
cmd = new SqlCommand(sqlcmd, sqlConn);
else
cmd = new SqlCommand(sqlcmd, sqlConn, trans);
if(isStoredProcedure)
cmd.CommandType = CommandType.StoredProcedure;
if (sqlparams!=null)
cmd.Parameters.AddRange(sqlparams);
result = cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
_exception = ex;
}
finally
{
closeConn(isCloseConn);
}
return result;
}
///
/// 取得多列資料,執行後會關閉SQL連線
///
/// SQL命令
/// 是否為預存程序
/// 是否關閉連線
/// 多列資料
public List ExecuteReader(string sqlcmd, bool isStoredProcedure)
{
return ExecuteReader(sqlcmd, isStoredProcedure, true);
}
///
/// 取得多列資料
///
/// SQL命令
/// 是否為預存程序
/// 是否關閉連線
/// 多列資料
public List ExecuteReader(string sqlcmd, bool isStoredProcedure, bool isCloseConn)
{
SqlParameter[] sqlparams = null;
return ExecuteReader(sqlcmd, ref sqlparams, isStoredProcedure, isCloseConn);
}
///
/// 取得多列資料
///
/// SQL命令
/// 命令參數,可為null,參數名稱為 @參數名稱
/// 是否為預存程序
/// 是否關閉連線
/// 多列資料
public List ExecuteReader(string sqlcmd, ref SqlParameter[] sqlparams, bool isStoredProcedure, bool isCloseConn)
{
return ExecuteReader(sqlcmd, ref sqlparams, isStoredProcedure, null, isCloseConn);
}
///
/// 取得多列資料
///
/// SQL命令
/// 命令參數,可為null,參數名稱為 @參數名稱
/// 是否為預存程序
/// SqlTransaction,可為null
/// 是否關閉連線
/// 多列資料
public List ExecuteReader(string sqlcmd, ref SqlParameter[] sqlparams, bool isStoredProcedure, SqlTransaction trans, bool isCloseConn)
{
List result = null;
_exception = null;
SqlDataReader reader = null;
try
{
if (sqlConn.State != System.Data.ConnectionState.Open)
sqlConn.Open();
SqlCommand cmd;
if (trans == null)
cmd = new SqlCommand(sqlcmd, sqlConn);
else
cmd = new SqlCommand(sqlcmd, sqlConn, trans);
if (isStoredProcedure)
cmd.CommandType = CommandType.StoredProcedure;
if (sqlparams != null)
cmd.Parameters.AddRange(sqlparams);
reader = cmd.ExecuteReader();
object[] item;
if (reader.HasRows)
{
result = new List();
while (reader.Read())
{
item = new object[reader.FieldCount];
for (int j = 0; j < reader.FieldCount; j++)
{
item[j] = reader[j];
}
result.Add(item);
}
}
}
catch (Exception ex)
{
_exception = ex;
}
finally
{
if (reader!=null) reader.Close();
closeConn(isCloseConn);
}
return result;
}
///
/// 取得單一值,執行後會關閉SQL連線
///
/// SQL命令
/// 是否為預存程序
/// 單一值
public object ExecuteScalar(string sqlcmd, bool isStoredProcedure)
{
return ExecuteScalar(sqlcmd, isStoredProcedure, true);
}
///
/// 取得單一值
///
/// SQL命令
/// 是否為預存程序
/// 是否關閉連線
/// 單一值
public object ExecuteScalar(string sqlcmd, bool isStoredProcedure, bool isCloseConn)
{
SqlParameter[] sqlparams = null;
return ExecuteScalar(sqlcmd, ref sqlparams, isStoredProcedure, isCloseConn);
}
///
/// 取得單一值
///
/// SQL命令
/// 命令參數,可為null,參數名稱為 @參數名稱
/// 是否為預存程序
/// 是否關閉連線
/// 單一值
public object ExecuteScalar(string sqlcmd,ref SqlParameter[] sqlparams, bool isStoredProcedure, bool isCloseConn)
{
return ExecuteScalar(sqlcmd,ref sqlparams, isStoredProcedure, null, isCloseConn);
}
///
/// 取得單一值
///
/// SQL命令
/// 命令參數,可為null,參數名稱為 @參數名稱
/// 是否為預存程序
/// SqlTransaction,可為null
/// 是否關閉連線
/// 單一值
public object ExecuteScalar(string sqlcmd,ref SqlParameter[] sqlparams, bool isStoredProcedure, SqlTransaction trans, bool isCloseConn)
{
object result = null;
_exception = null;
try
{
if (sqlConn.State != System.Data.ConnectionState.Open)
sqlConn.Open();
SqlCommand cmd;
if (trans == null)
cmd = new SqlCommand(sqlcmd, sqlConn);
else
cmd = new SqlCommand(sqlcmd, sqlConn, trans);
if (isStoredProcedure)
cmd.CommandType = CommandType.StoredProcedure;
if (sqlparams != null)
cmd.Parameters.AddRange(sqlparams);
result = cmd.ExecuteScalar();
}
catch (Exception ex)
{
_exception = ex;
}
finally
{
closeConn(isCloseConn);
}
return result;
}
///
/// 取得單一列資料,執行後會關閉SQL連線
///
/// SQL命令
/// 是否為預存程序
/// 單一列資料
public object[] ExecuteReaderSingleRow(string sqlcmd, bool isStoredProcedure)
{
return ExecuteReaderSingleRow(sqlcmd, isStoredProcedure, true);
}
///
/// 取得單一列資料
///
/// SQL命令
/// 是否為預存程序
/// 是否關閉連線
/// 單一列資料
public object[] ExecuteReaderSingleRow(string sqlcmd, bool isStoredProcedure, bool isCloseConn)
{
SqlParameter[] sqlparams = null;
return ExecuteReaderSingleRow(sqlcmd, ref sqlparams, isStoredProcedure, isCloseConn);
}
///
/// 取得單一列資料
///
/// SQL命令,參數部份以 @參數名稱 標示
/// 命令參數,可為null,參數名稱為 @參數名稱
/// 是否為預存程序
/// 是否關閉連線
/// 單一列資料
public object[] ExecuteReaderSingleRow(string sqlcmd,ref SqlParameter[] sqlparams, bool isStoredProcedure, bool isCloseConn)
{
return ExecuteReaderSingleRow(sqlcmd,ref sqlparams, isStoredProcedure, null, isCloseConn);
}
///
/// 取得單一列資料
///
/// SQL命令,參數部份以 @參數名稱 標示
/// 命令參數,可為null,參數名稱為 @參數名稱
/// 是否為預存程序
/// SqlTransaction,可為null
/// 是否關閉連線
/// 單一列資料
public object[] ExecuteReaderSingleRow(string sqlcmd, ref SqlParameter[] sqlparams, bool isStoredProcedure, SqlTransaction trans, bool isCloseConn)
{
object[] result = null;
_exception = null;
SqlDataReader reader = null;
try
{
if (sqlConn.State != System.Data.ConnectionState.Open)
sqlConn.Open();
SqlCommand cmd;
if (trans == null)
cmd = new SqlCommand(sqlcmd, sqlConn);
else
cmd = new SqlCommand(sqlcmd, sqlConn, trans);
if (isStoredProcedure)
cmd.CommandType = CommandType.StoredProcedure;
if (sqlparams != null)
cmd.Parameters.AddRange(sqlparams);
reader = cmd.ExecuteReader(CommandBehavior.SingleRow);
object[] item;
if (reader.HasRows)
{
reader.Read();
item = new object[reader.FieldCount];
for (int j = 0; j < reader.FieldCount; j++)
{
item[j] = reader[j];
}
result = item;
}
}
catch (Exception ex)
{
_exception = ex;
}
finally
{
if (reader != null) reader.Close();
closeConn(isCloseConn);
}
return result;
}
}
}
</code></pre>
</div>
<div>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-90564352421808787992011-06-23T01:03:00.000-07:002011-06-23T01:03:00.658-07:00[C++]Oracle資料庫存取函式(OCCI)<div>
<div>
<div><br>
<h4>開發環境<br>
</h4>
<ul><li>VS2008</li>
<li>Oracle 10g Express Edition</li></ul>
</div>
<h4>下載OCCI函式庫</h4>
<ol><li>下載<a href="http://www.oracle.com/technetwork/database/occidownloads-083553.html" target="_blank">occivc9win32-111060-132181.zip</a>,解壓縮到自行建立的lib目錄後可以得到目錄</li>
<li>下載<a href="http://download.oracle.com/otn/nt/instantclient/112010/instantclient-sdk-win32-11.2.0.1.0.zip" target="_blank">instantclient-sdk-win32-11.2.0.1.0.zip</a>,解壓縮後可在[instantclient_11_2\sdk\]目錄找到[include]</li>
<li>將上述兩個目錄複製到某個目錄下,如[D:\Project\CPPProject\occivc9win32-111060-132181]<br>
</li>
</ol>
</div>
<h4>設定開發專案</h4>
<ol><li>將[lib]目錄中的oraocci11.dll與oraocci11d.dll都複製到[C:\WINDOWS\system32]</li>
<li>於開發用的C++專案設定屬性:展開[組態屬性→C/C++→一般],修改[其他Include目錄],指到[include]目錄<br>
<img src="http://img14.imageshack.us/img14/2223/image001oqr.jpg"></li>
<li>展開[組態屬性→連結器→一般],修改[其他程式庫目錄],指到lib目錄<br>
<img src="http://img842.imageshack.us/img842/6348/image002ark.jpg"></li>
<li>展開[組態屬性→連結器→輸入],修改[其他相依性],,增加[oraocci11d.lib]<br>
<img src="http://img822.imageshack.us/img822/1447/image003wz.jpg"></li>
</ol>
</div>
<br>
<h4>資料庫連線函式庫<br>
</h4>
<ol><li>OracleIO.h<br>
<pre><code>#pragma once
#include
namespace commonio {
class OracleIO
{
private:
oracle::occi::Environment *env;
oracle::occi::Connection *conn;
oracle::occi::Statement *stmt;
oracle::occi::ResultSet *rs;
const char* _ip;
unsigned int _port;
const char* _account;
const char* _pswd;
const char* _defaultDB;
public:
OracleIO(const char* ip,unsigned int port,const char* account,const char* pswd,const char* defaultDB);
~OracleIO(void);
/**
**取得連線
**/
oracle::occi::Connection *getConn();
void closeConn();
void closeStatement();
/**
**執行查詢
**/
oracle::occi::ResultSet *executeQuery(const char* sqlStr);
/**
**執行新增、更新、刪除
**/
unsigned int executeUpdate(const char* sqlStr);
};
};</code></pre>
</li>
<li>OracleIO.cpp<br>
<pre><code>#include "StdAfx.h"
#include "OracleIO.h"
#include "CommonFunc.h"
#include
using namespace std;
using namespace commonio;
using namespace oracle::occi;
OracleIO::OracleIO(const char* ip,unsigned int port,const char* account,const char* pswd,const char* defaultDB)
{
_ip=ip;
_port=port;
_account=account;
_pswd=pswd;
_defaultDB=defaultDB;
env = oracle::occi::Environment::createEnvironment("UTF8","UTF8",Environment::THREADED_MUTEXED);
conn=NULL;
stmt=NULL;
rs=NULL;
}
OracleIO::~OracleIO(void)
{
closeConn();
oracle::occi::Environment::terminateEnvironment(env);
}
Connection* OracleIO::getConn(){
if(conn==NULL){
string port;
commonio::CommonFunc::itostr(_port,port,10);
string connectString="//";
connectString=connectString + _ip+ ":" + port + "/" + _defaultDB;
conn = env->createConnection(_account, _pswd, connectString);
}
return conn;
}
void OracleIO::closeConn(){
if(conn!=NULL){
closeStatement();
env->terminateConnection(conn);
conn=NULL;
}
}
void OracleIO::closeStatement(){
if(stmt!=NULL){
if(rs!=NULL){
stmt->closeResultSet(rs);
rs=NULL;
}
conn->terminateStatement(stmt);
stmt=NULL;
}
}
ResultSet *OracleIO::executeQuery(const char* sqlStr){
try{
getConn();
string sql=string(sqlStr);
stmt = conn->createStatement(sql);
rs = stmt->executeQuery();
}catch (SQLException &sqlExcp){
cerr <createStatement(sql);
result=stmt->executeUpdate();
closeStatement();
}catch (SQLException &sqlExcp){
cerr <</code></pre>
</li>
<li>額外函式<br>
<ul><li>CommonFunc.h<br>
<pre><code>#pragma once
using namespace std;
namespace commonio {
class CommonFunc
{
public:
static void itostr(int value, std::string& buf, int base);
};
};</code></pre>
</li>
<li>CommonFunc.cpp<br>
<pre><code>#include "stdafx.h"
#include
#include "CommonFunc.h"
using namespace std;
using namespace commonio;
void CommonFunc::itostr(int value, std::string& buf, int base){
int i = 30;
buf = "";
for(; value && i ; --i, value /= base) buf = "0123456789abcdef"[value % base] + buf;
}</code></pre>
</li></ul>
</li>
</ol>
<div>
<div>
<h4>使用範例</h4>
<pre><code>#include "stdafx.h"
#include
#include
#include "OracleIO.h"
using namespace std;
using namespace commonio;
int main(int argc, _TCHAR* argv[])
{
OracleIO oracleio=OracleIO("localhost",1521,"oracle","oracle","XE");
/**
**更新測試Start
**/
unsigned int changeNum= oracleio.executeUpdate("update test1 set testname='test123' where testsn=1");
cout<<"changeNum:"< listOfColumns =rs->getColumnListMetaData();
for(int i=0;inext())
{
for(int i=0;igetString(i+1)<<"\t";
}
cout <</code></pre>
</div>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-65241053262011550742011-06-22T01:01:00.000-07:002011-06-22T01:01:00.622-07:00[C++]MySQL資料庫存取函式(MySQL++)<h4>序言</h4>
此篇為研究C++存取MySQL所寫的函式。<br>
<h4 style="margin:5px 0px;color:rgb(51, 51, 51)">環境</h4>
<ul><li>VS2008</li>
<li><a href="http://tangentsoft.net/mysql++/" target="_blank">mysql++-3.1.0</a></li>
<li>MySQL Server 5.1<br>
</li></ul>
<div>
<h4>編譯MySQL++函式庫</h4>
<ol><li>下載mysql++-3.1.0.tar.gz,解壓縮後可以得到[mysql++-3.1.0]目錄</li>
<li>進入[mysql++-3.1.0\vc2008\]目錄會找到[mysql++_mysqlpp.vcproj]專案,以Visual Studio 2008開啟</li>
<li>編譯時MySQL++會需要MySQL的版本定義標頭檔,函式庫預設MySQL安裝於[C:\Program Files\MySQL\MySQL Server 5.1],所以需先確認是否有[C:\Program Files\MySQL\MySQL Server 5.1\include]與[C:\Program Files\MySQL\MySQL Server 5.1\lib\opt]是否存在,如果MySQL放在其他目錄,可透過專案屬性修改<br>
</li>
<ul><li>開啟專案屬性<br>
<img src="http://img196.imageshack.us/img196/3723/image001gp.jpg">
</li>
<li>展開[組態屬性→C/C++→一般],修改[其他Include目錄],指到MySQL的安裝目錄中的include資料夾<br>
<img src="http://img38.imageshack.us/img38/9582/image002vqdu.jpg">
</li>
<li>展開[組態屬性→連結器→一般],修改[其他程式庫目錄],指到MySQL的安裝目錄中的lib\opt資料夾<br>
<img src="http://img819.imageshack.us/img819/2481/image003bs.jpg">
</li></ul>
<li>建置專案<br>
<img src="http://img856.imageshack.us/img856/9812/image004o.jpg">
</li>
<li>建置成功後會在[mysql++-3.1.0\vc2008\Debug]目錄下看到編譯完成的mysqlpp_d.dll、mysqlpp_d.lib<br>
</li>
</ol>
</div>
<div>
<div>
<h4>設定開發專案<br>
</h4>
<ol><li>將上一步產生的[mysqlpp_d.dll]複製到[C:\WINDOWS\system32]<br>
</li>
<li>於開發用的C++專案設定屬性:展開[組態屬性→C/C++→一般],修改[其他Include目錄],指到MySQL的安裝目錄中的include資料夾與mysql++函式庫的lib目錄<br>
<img src="http://img225.imageshack.us/img225/292/image005cv.jpg"></li>
<li>展開[組態屬性→連結器→一般],修改[其他程式庫目錄],指到MySQL的安裝目錄中的lib\opt資料夾與mysql++編譯後的Debug目錄<br>
<img src="http://img585.imageshack.us/img585/632/image006ed.jpg"></li>
<li>展開[組態屬性→連結器→輸入],修改[其他相依性],,增加[mysqlpp_d.lib]與 [libmysql.lib]<br>
<img src="http://img52.imageshack.us/img52/4654/image007ud.jpg"></li>
</ol>
</div>
<div>
<h4>資料庫連線函式庫<br>
</h4>
<ol><li>MySQLIO.h<br>
<pre><code>#pragma once
#include
namespace commonio {
class MySQLIO
{
private:
mysqlpp::Connection _conn;
const char* _ip;
unsigned int _port;
const char* _account;
const char* _pswd;
const char* _defaultDB;
const char* _error;
int _errnum;
public:
/**
**MySQL資料庫連線物件
**/
MySQLIO(const char* ip,unsigned int port,const char* account,const char* pswd,const char* defaultDB);
~MySQLIO(void);
/**
**錯誤訊息
**/
const char* error();
int errnum();
/**
**取得連線
**/
mysqlpp::Connection getConn(){return _conn;}
/**
**執行查詢
**/
mysqlpp::StoreQueryResult executeQuery(const char* sqlStr);
/**
**執行查詢
**/
mysqlpp::StoreQueryResult executeQuery(const char* sqlStr,mysqlpp::SQLQueryParms & param);
/**
**執行新增、更新、刪除
**/
mysqlpp::SimpleResult executeUpdate(const char* sqlStr);
/**
**執行新增、更新、刪除
**/
mysqlpp::SimpleResult executeUpdate(const char* sqlStr,mysqlpp::SQLQueryParms & param);
};
};</code></pre>
</li>
<li>
MySQLIO.cpp<br>
<pre><code>#include "stdafx.h"
#include "MySQLIO.h"
using namespace std;
using namespace commonio;
MySQLIO::MySQLIO(const char* ip,unsigned int port,const char* account,const char* pswd,const char* defaultDB):_conn(false)
{
_ip=ip;
_port=port;
_account=account;
_pswd=pswd;
_defaultDB=defaultDB;
_conn.set_option(new mysqlpp::SetCharsetNameOption("utf8") );
}
const char* MySQLIO::error(){return _error;}
int MySQLIO::errnum(){return _errnum;}
mysqlpp::StoreQueryResult MySQLIO::executeQuery(const char* sqlStr){
_error=NULL;
_errnum=0;
try{
if(!_conn.connected()) {
if(!_conn.connect(_defaultDB, _ip,
_account, _pswd,_port)){
_error=_conn.error();
_errnum=_conn.errnum();
}
}
if(_conn.connected()) {
mysqlpp::Query query = _conn.query(sqlStr);
if (mysqlpp::StoreQueryResult res = query.store()) {
query.reset();
return res;
}else{
_error=query.error();
_errnum=query.errnum();
}
}
}catch(const mysqlpp::ConnectionFailed &e){
_error=e.what();
_errnum=e.errnum();
}catch(const mysqlpp::BadQuery &e){
_error=e.what();
_errnum=e.errnum();
}catch (const mysqlpp::BadConversion & e) {
_error=e.what();
}catch (const mysqlpp::BadFieldName & e) {
_error=e.what();
}catch (const mysqlpp::BadIndex & e) {
_error=e.what();
}catch (const mysqlpp::BadInsertPolicy & e) {
_error=e.what();
}catch (const mysqlpp::BadOption & e) {
_error=e.what();
}catch (const mysqlpp::BadParamCount & e) {
_error=e.what();
}catch (const mysqlpp::Exception& e) {
_error=e.what();
}
return mysqlpp::StoreQueryResult();
}
mysqlpp::StoreQueryResult MySQLIO::executeQuery(const char* sqlStr,mysqlpp::SQLQueryParms & param){
_error=NULL;
_errnum=0;
try{
if(!_conn.connected()) {
if(!_conn.connect(_defaultDB, _ip,
_account, _pswd,_port)){
_error=_conn.error();
_errnum=_conn.errnum();
}
}
if(_conn.connected()) {
mysqlpp::Query query = _conn.query(sqlStr);
query.parse();
if (mysqlpp::StoreQueryResult res = query.store(param)) {
query.reset();
return res;
}else{
_error=query.error();
_errnum=query.errnum();
}
}
}catch(const mysqlpp::ConnectionFailed &e){
_error=e.what();
_errnum=e.errnum();
}catch(const mysqlpp::BadQuery &e){
_error=e.what();
_errnum=e.errnum();
}catch (const mysqlpp::BadConversion & e) {
_error=e.what();
}catch (const mysqlpp::BadFieldName & e) {
_error=e.what();
}catch (const mysqlpp::BadIndex & e) {
_error=e.what();
}catch (const mysqlpp::BadInsertPolicy & e) {
_error=e.what();
}catch (const mysqlpp::BadOption & e) {
_error=e.what();
}catch (const mysqlpp::BadParamCount & e) {
_error=e.what();
}catch (const mysqlpp::Exception& e) {
_error=e.what();
}
return mysqlpp::StoreQueryResult();
}
mysqlpp::SimpleResult MySQLIO::executeUpdate(const char* sqlStr){
_error=NULL;
_errnum=0;
try{
if(!_conn.connected()) {
if(!_conn.connect(_defaultDB, _ip,
_account, _pswd,_port)){
_error=_conn.error();
_errnum=_conn.errnum();
}
}
if(_conn.connected()) {
mysqlpp::Query query = _conn.query(sqlStr);
query.parse();
if (mysqlpp::SimpleResult res = query.execute()) {
query.reset();
return res;
}else{
_error=query.error();
_errnum=query.errnum();
}
}
}catch(const mysqlpp::ConnectionFailed &e){
_error=e.what();
_errnum=e.errnum();
}catch(const mysqlpp::BadQuery &e){
_error=e.what();
_errnum=e.errnum();
}catch (const mysqlpp::BadConversion & e) {
_error=e.what();
}catch (const mysqlpp::BadFieldName & e) {
_error=e.what();
}catch (const mysqlpp::BadIndex & e) {
_error=e.what();
}catch (const mysqlpp::BadInsertPolicy & e) {
_error=e.what();
}catch (const mysqlpp::BadOption & e) {
_error=e.what();
}catch (const mysqlpp::BadParamCount & e) {
_error=e.what();
}catch (const mysqlpp::Exception& e) {
_error=e.what();
}
return mysqlpp::SimpleResult();
}
mysqlpp::SimpleResult MySQLIO::executeUpdate(const char* sqlStr,mysqlpp::SQLQueryParms & param){
_error=NULL;
_errnum=0;
try{
if(!_conn.connected()) {
if(!_conn.connect(_defaultDB, _ip,
_account, _pswd,_port)){
_error=_conn.error();
_errnum=_conn.errnum();
}
}
if(_conn.connected()) {
mysqlpp::Query query = _conn.query(sqlStr);
query.parse();
if (mysqlpp::SimpleResult res = query.execute(param)) {
query.reset();
return res;
}else{
_error=query.error();
_errnum=query.errnum();
}
}
}catch(const mysqlpp::ConnectionFailed &e){
_error=e.what();
_errnum=e.errnum();
}catch(const mysqlpp::BadQuery &e){
_error=e.what();
_errnum=e.errnum();
}catch (const mysqlpp::BadConversion & e) {
_error=e.what();
}catch (const mysqlpp::BadFieldName & e) {
_error=e.what();
}catch (const mysqlpp::BadIndex & e) {
_error=e.what();
}catch (const mysqlpp::BadInsertPolicy & e) {
_error=e.what();
}catch (const mysqlpp::BadOption & e) {
_error=e.what();
}catch (const mysqlpp::BadParamCount & e) {
_error=e.what();
}catch (const mysqlpp::Exception& e) {
_error=e.what();
}
return mysqlpp::SimpleResult();
}
MySQLIO::~MySQLIO(void)
{
}</code></pre>
</li>
</ol>
</div>
<div>
<h4>使用範例<br>
</h4>
<pre><code>#include "stdafx.h"
#include
#include "MySQLIO.h"
using namespace std;
using namespace commonio;
int main(int argc, _TCHAR* argv[])
{
string data;
MySQLIO mysqlio("localhost",3306,"root",NULL,"pklogdb");
mysqlpp::SQLQueryParms params;
params << 2;
if (mysqlpp::StoreQueryResult res = mysqlio.executeQuery("select * from gametypetab where gameType=%0q",params)) {
mysqlpp::StoreQueryResult::const_iterator it;
mysqlpp::Row::const_iterator colit;
for (it = res.begin(); it != res.end(); ++it) {
mysqlpp::Row row = *it;
cout << '\t';
for (colit = row.begin(); colit != row.end(); ++colit) {
if(colit->is_null()){
cout << "\t (NULL)"<< endl;
}else{
string col(*colit);
cout << '\t' << col << endl;
}
}
cout << endl;
}
params.clear();
string value("TEST");
params<0){
cerr << "success update"<< endl;
}
}else{
cerr << "Failed to get item list: "<< endl;
return 1;
}
return 0;
}</code></pre>
<br>
</div>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-36683364745874498832011-06-21T00:36:00.000-07:002011-06-21T01:00:55.444-07:00[C++]Http Get與Post函式(Curl)<h4>序言</h4>
此篇記錄我使用Curl函式庫來達成Http的Get與Post方法。<br>
<br>
<h4>開發環境<br>
</h4>
<div>
<ul><li>VS2008</li>
<li><a href="http://curl.haxx.se/download/curl-7.21.4.zip">curl-7.21.4</a><br>
</li></ul>
</div>
<h4>編譯Curl函式庫</h4>
<ol><li>下載curl-7.21.4.zip,解壓縮後可以得到[curl-7.21.4]目錄</li>
<li>進入[curl-7.21.4]目錄會找到[vc6curl.dsw]專案,以Visual Studio 2008開啟</li>
<li>建置專案<br>
<img src="http://img641.imageshack.us/img641/5529/image001bff.jpg">
</li>
<li>建置成功後會在[curl-7.21.4\lib\DLL-Debug]目錄下看到編譯完成的libcurld.dll、libcurld_imp.lib<br>
</li>
</ol>
<h4>設定開發專案</h4>
<ol><li>將上一步產生的[libcurld.dll]複製到[C:\WINDOWS\system32]</li>
<li>於開發用的C++專案設定屬性:展開[組態屬性→C/C++→一般],修改[其他Include目錄],指到[curl-7.21.4]目錄中的include資料夾<br>
<img src="http://img842.imageshack.us/img842/7420/image002uo.jpg"></li>
<li>展開[組態屬性→連結器→一般],修改[其他程式庫目錄],指到[curl-7.21.4\lib\DLL-Debug]目錄<br>
<img src="http://img863.imageshack.us/img863/4884/image003lx.jpg"></li>
<li>展開[組態屬性→連結器→輸入],修改[其他相依性],,增加[libcurld_imp.lib]<br>
<img src="http://img10.imageshack.us/img10/7594/image004fa.jpg"><br>
</li>
</ol>
<br>
<h4>Http連線函式庫</h4>
<ol><li>HttpIO.h<br>
<pre><code>#pragma once
#include
using namespace std;
namespace commonio {
class HttpIO
{
public:
/**
**post方法
**isRedirect:是否依head redirect
**param:傳參數,如val1=123&val2=abc
**timeout:等待回應逾期時間(秒),為不限制
**/
static string doPost(string URL,bool isRedirect,string param="",long timeout=0);
/**
**get方法
**isRedirect:是否依head redirect
**timeout:等待回應逾期時間(秒),為不限制
**/
static string doGet(string URL,bool isRedirect,long timeout=0);
};
};</code></pre>
</li>
<li>HttpIO.cpp<br>
<pre><code>#include "StdAfx.h"
#include
//#include
#include
#include "HttpIO.h"
using namespace std;
using namespace commonio;
// This is the writer call back function used by curl
size_t writer (char *data, size_t size, size_t nmemb, std::string *buffer)
{
size_t result = 0;
if (buffer != NULL)
{
buffer->append (data, size * nmemb);
result = size * nmemb;
}
return result;
}
string HttpIO::doPost(string URL,bool isRedirect,string param,long timeout)
{
CURL *curl;
CURLcode cc;
string bufferdata;
string error;
//string user_agent("Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
if ((curl = curl_easy_init()) == NULL)
exit(1);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
curl_easy_setopt(curl, CURLOPT_URL, URL.c_str()); // URL used for posting
//curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent);
if(isRedirect) curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //Redirect
if(timeout>0) curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); //times out after second
curl_easy_setopt(curl, CURLOPT_POST, 1);//Tell libcurl to use POST
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, param.c_str());
curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt (curl, CURLOPT_WRITEDATA,&bufferdata);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); //Debug
//cc=curl_easy_setopt(curl, CURLOPT_HEADER, 1); //Debug
cc = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if(cc == CURLE_OK)
{
string data;
data=bufferdata;
bufferdata="";
return data;
}
else
{
//cout << "Error: [" << cc << "] - "<< error;
string data("");
return data;
}
}
string HttpIO::doGet(string URL,bool isRedirect,long timeout)
{
CURL *curl;
CURLcode cc;
string bufferdata;
string error;
if ((curl = curl_easy_init()) == NULL)
exit(1);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
curl_easy_setopt(curl, CURLOPT_URL, URL.c_str()); // URL used for posting
if(isRedirect) curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); //Redirect
if(timeout>0) curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); //times out after second
curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt (curl, CURLOPT_WRITEDATA,&bufferdata);
//cc=curl_easy_setopt(curl, CURLOPT_HEADER, 1); //Debug
cc = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if(cc == CURLE_OK)
{
string data;
data=bufferdata;
bufferdata="";
return data;
}
else
{
//cout << "Error: [" << cc << "] - "<< error;
string data("");
return data;
}
}</code></pre>
</li>
<li>額外函式</li>
<ul><li>CommonFunc.h<br>
<pre><code>#pragma once
using namespace std;
namespace commonio {
class CommonFunc
{
public:
static void str_split(const string& str,
vector& tokens,
const string& delimiters = " ");
static vector> paramToArray(string param);
};
};</code></pre>
</li>
<li>CommonFunc.cpp<br>
<pre><code>#include "stdafx.h"
#include
#include
#include "CommonFunc.h"
using namespace std;
using namespace commonio;
void CommonFunc::str_split(const string& str,
vector& tokens,
const string& delimiters){
// Skip delimiters at beginning.
string::size_type lastPos = str.find_first_not_of(delimiters, 0);
// Find first "non-delimiter".
string::size_type pos = str.find_first_of(delimiters, lastPos);
while (string::npos != pos || string::npos != lastPos)
{
// Found a token, add it to the vector.
tokens.push_back(str.substr(lastPos, pos - lastPos));
// Skip delimiters. Note the "not_of"
lastPos = str.find_first_not_of(delimiters, pos);
// Find next "non-delimiter"
pos = str.find_first_of(delimiters, lastPos);
}
}
vector> CommonFunc::paramToArray(string param){
vector> arr;
vector p;
CommonFunc::str_split(param,p,"&");
if (param.find("&")>-1) {
vector p2;
int j = 0;
for (unsigned int i = 0; i < p.size(); i++) {
if (p[i].find_first_of("amp;")==0) {
p2[j - 1]=p2[j - 1] + "&" + p[i].substr(4);
j--;
}
p2.push_back(p[i]);
j++;
}
p=p2;
}
for (unsigned int i = 0; i < p.size(); i++) {
vector item;
CommonFunc::str_split(p[i],item,"=");
if (item.size() == 2) {
arr.push_back(item);
}
}
return arr;
}</code></pre>
</li></ul>
</ol>
<h4>使用範例程式</h4>
<pre><code>#include "stdafx.h"
#include
#include
#include "HttpIO.h"
using namespace std;
using namespace commonio;
int main(int argc, _TCHAR* argv[])
{
string data=HttpIO::doGet("http://www.google.com",false);
cout << '\t' << data << endl;
return 0;
}</code></pre>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-56706608347968021602011-03-29T18:59:00.000-07:002011-12-25T21:13:43.520-08:00[Java]Http Get與Post函式2(HttpURLConnection)<h4>序言</h4>
之前我發的一篇[<a href="http://allen080.blogspot.com/2010/03/javahttp-getpost.html">Http Get與Post函式</a>]中已經實現了可維持Session狀態的HTTP連線函式,但我發現了Apache提供的這個Client在Windows下會有連線數上限的問題(聽說好像<a href="http://weng32002.blogspot.com/2010/06/maxuserport-tcptimedwaitdelay.html" target="_blank">調整XP連線數可以解決</a>)。<br>
另外,有的時候使用HTTP連線也不一定需要維持Session狀態,這時候其實就不需要另外加入Apache的http client的JAR。<br>
因此我還是整理一下如果一個不維持Session狀態的HTTP Client連線怎麼達成。<br>
<br>
<h4>函式原始碼</h4>
參數轉換函式
<pre><code>package common.control;<br><br>import java.io.BufferedReader;<br>import java.io.IOException;<br>import java.io.InputStream;<br>import java.io.InputStreamReader;<br>import java.io.UnsupportedEncodingException;<br>import java.net.URLEncoder;<br>import java.util.ArrayList;<br>import java.util.HashMap;<br><br>public class HTTPParseFunc {<br><br> /**<br> * hashMapToString<br> * <br> * @param map<br> * @param charset編碼<br> * ,如HTTP.UTF_8<br> * @return<br> * @throws UnsupportedEncodingException<br> */<br> @SuppressWarnings("unchecked")<br> public static String hashMapToString(HashMap<String, String> map,<br> String charset) throws UnsupportedEncodingException {<br> StringBuffer result = new StringBuffer();<br> java.util.Iterator it = map.entrySet().iterator();<br> boolean isfirst = true;<br> while (it.hasNext()) {<br> java.util.Map.Entry entry = (java.util.Map.Entry) it.next();<br> if (isfirst) {<br> isfirst = false;<br> } else {<br> result.append("&");<br> }<br> result<br> .append(URLEncoder.encode(entry.getKey().toString(),<br> charset));<br> result.append("=");<br> result.append(URLEncoder.encode(entry.getValue().toString(),<br> charset));<br> }<br> return result.toString();<br> }<br> /**<br> * 將inputStream轉為String<br> * <br> * @param is<br> * inputStream<br> * @param charset<br> * 編碼,如HTTP.UTF_8<br> * @return inputStream的內容<br> * @throws UnsupportedEncodingException<br> */<br> public static String inputStream2String(InputStream is, String charset)<br> throws UnsupportedEncodingException {<br> BufferedReader in = new BufferedReader(new InputStreamReader(is,<br> charset));<br> StringBuffer buffer = new StringBuffer();<br> String line = "";<br> try {<br> boolean isfirst = true;<br> while ((line = in.readLine()) != null) {<br> if (!isfirst) {<br> buffer.append("\n");<br> } else {<br> isfirst = false;<br> }<br> buffer.append(line);<br> }<br> } catch (IOException e) {<br> e.printStackTrace();<br> }<br><br> return buffer.toString();<br> }<br><br> /**<br> * HTTP 傳輸參數分割<br> * @param param 如name1=value1&name2=value2<br> * @return<br> * @throws UnsupportedEncodingException<br> */<br> public static ArrayList<String[]> paramToArray(String param)<br> throws UnsupportedEncodingException {<br> ArrayList<String[]> arr = null;<br> String[] p = param.split("&");<br> if (param.toLowerCase().contains("&amp;")) {<br> ArrayList<String> p2 = new ArrayList<String>();<br> int j = 0;<br> for (int i = 0; i < p.length; i++) {<br> if (p[i].toLowerCase().startsWith("amp;")) {<br> p2.set(j - 1, p2.get(j - 1) + "&amp;" + p[i].substring(4));<br> j--;<br> }<br> p2.add(p[i]);<br> j++;<br> }<br> p2.toArray(p);<br> }<br><br> for (int i = 0; i < p.length; i++) {<br> String[] item = p[i].split("=");<br> if (item.length == 2) {<br> if (arr == null)<br> arr = new ArrayList<String[]>();<br> // item[0]=URLDecoder.decode(item[0],charset);<br> // item[1]=URLDecoder.decode(item[1],charset);<br> arr.add(item);<br> }<br> }<br> return arr;<br> }<br>}<br><br></code></pre>
連線參數模型<br>
<pre><code>package common.model;<br><br>public class HTTPResponse {<br> String html=null;<br> Integer statusCode=null;<br> public String getHtml() {<br> return html;<br> }<br> public void setHtml(String html) {<br> this.html = html;<br> }<br> public Integer getStatusCode() {<br> return statusCode;<br> }<br> public void setStatusCode(Integer statusCode) {<br> this.statusCode = statusCode;<br> }<br>}<br><br></code></pre>
<br>
HTTP連線函式
<pre><code>package common;<br><br>import java.io.BufferedReader;<br>import java.io.IOException;<br>import java.io.PrintWriter;<br>import java.io.UnsupportedEncodingException;<br>import java.net.HttpURLConnection;<br>import java.net.Proxy;<br>import java.net.URL;<br>import java.util.HashMap;<br><br>import common.control.HTTPParseFunc;<br>import common.model.HTTPResponse;<br><br><br><br>public class HTTPBaseIO2 {<br> public enum Method {<br> get, post<br> }<br> /**<br> * 送出Request<br> * @param urlpath URL<br> * @param method HTTPBaseIO2.Method.get/post<br> * @param params HashMap<Name, Value><br> * @param charset UTF-8<br> * @param timeout 連線逾時null:不設限/millisecond<br> * @return 回傳的html<br> * @throws UnsupportedEncodingException<br> */<br> public static HTTPResponse doSend(String urlpath, Method method,<br> HashMap<String, String> params, String charset,boolean isAutoRedirect, Integer timeout,Proxy proxy) throws UnsupportedEncodingException {<br> HTTPResponse result=new HTTPResponse();<br> String param=null;<br> if(params!=null){<br> param=HTTPParseFunc.hashMapToString(params, charset);<br> }<br> if(method==Method.post){<br> result=sendPost(urlpath,param,charset,isAutoRedirect,timeout,proxy);<br> }else{<br> result=sendGet(urlpath,param,charset,isAutoRedirect,timeout,proxy);<br> }<br> return result;<br> }<br> /**<br> * 向指定URL發送GET方法的請求<br> * <br> * @param url<br> * 發送請求的URL<br> * @param param<br> * 請求參數,請求參數應該是name1=value1&name2=value2的形式。<br> * @return URL所代表遠程資源的響應<br> */<br> public static HTTPResponse sendGet(String url, String params, String charset,boolean isAutoRedirect, Integer timeout,Proxy proxy) {<br> HTTPResponse result=new HTTPResponse();<br> HttpURLConnection conn=null;<br> BufferedReader in = null;<br> try {<br> String urlName = url;<br> if(params!=null) urlName+= "?" + params;<br> URL realUrl = new URL(urlName);<br><br> HttpURLConnection.setFollowRedirects(isAutoRedirect);<br> // 打開和URL之間的連接 <br> if(proxy!=null) <br> conn = (HttpURLConnection)realUrl.openConnection(proxy);<br> else<br> conn = (HttpURLConnection)realUrl.openConnection();<br> if(timeout!=null) conn.setConnectTimeout(timeout);<br> // 設置通用的請求屬性<br> conn.setRequestProperty("accept", "*/*");<br> conn.setRequestProperty("connection", "Keep-Alive");<br> conn.setRequestProperty("user-agent",<br> "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");<br> // 建立實際的連接<br> conn.connect();<br> result.setHtml(HTTPParseFunc.inputStream2String(conn.getInputStream(), charset));<br> } catch (Exception e) {<br> e.printStackTrace();<br> result=null;<br> }<br> // 使用finally塊來關閉輸入流<br> finally {<br> try {<br> if (conn != null){<br> if(conn.getResponseCode()!=HttpURLConnection.HTTP_OK)<br> result=null;<br> result.setStatusCode(conn.getResponseCode());<br> }<br> } catch (Exception e) {<br> }<br> try {<br> if (in != null) {<br> in.close();<br> }<br> if (conn != null){<br> conn.disconnect();<br> }<br> } catch (IOException ex) {<br> ex.printStackTrace();<br> }<br> }<br> return result;<br> }<br><br> /**<br> * 向指定URL發送POST方法的請求<br> * <br> * @param url<br> * 發送請求的URL<br> * @param param<br> * 請求參數,請求參數應該是name1=value1&name2=value2的形式。<br> * @return URL所代表遠程資源的響應<br> */<br> public static HTTPResponse sendPost(String url, String params, String charset,boolean isAutoRedirect, Integer timeout,Proxy proxy) {<br> HTTPResponse result=new HTTPResponse();<br> PrintWriter out = null;<br> BufferedReader in = null;<br> HttpURLConnection conn=null;<br> try {<br> URL realUrl = new URL(url);<br> // 打開和URL之間的連接 <br><br> HttpURLConnection.setFollowRedirects(isAutoRedirect);<br> if(proxy!=null) <br> conn = (HttpURLConnection)realUrl.openConnection(proxy);<br> else<br> conn = (HttpURLConnection)realUrl.openConnection();<br> if(timeout!=null) conn.setConnectTimeout(timeout);<br> // 設置通用的請求屬性<br> conn.setRequestProperty("accept", "*/*");<br> conn.setRequestProperty("connection", "Keep-Alive");<br> conn.setRequestProperty("user-agent",<br> "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");<br> // 發送POST請求必須設置如下兩行<br> conn.setDoOutput(true);<br> conn.setDoInput(true);<br> // 獲取URLConnection對象對應的輸出流<br> out = new PrintWriter(conn.getOutputStream());<br> // 發送請求參數<br> if(params!=null) out.print(params);<br> // flush輸出流的緩衝<br> out.flush();<br> result.setHtml(HTTPParseFunc.inputStream2String(conn.getInputStream(), charset));<br> <br> } catch (Exception e) {<br> e.printStackTrace();<br> result=null;<br> }<br> // 使用finally塊來關閉輸出流、輸入流<br> finally {<br> try {<br> if (conn != null){<br> if(conn.getResponseCode()!=HttpURLConnection.HTTP_OK)<br> result=null;<br> result.setStatusCode(conn.getResponseCode());<br> }<br> } catch (Exception e) {<br> }<br> try {<br> if (out != null) {<br> out.close();<br> }<br> if (in != null) {<br> in.close();<br> }<br> } catch (IOException ex) {<br> ex.printStackTrace();<br> }<br> if (conn != null){<br> conn.disconnect();<br> }<br> }<br> return result;<br> }<br> <br><br>}<br><br></code></pre>
<h4>使用範例程式</h4>
<pre><code>package common.test;<br><br>import java.util.HashMap;<br><br><br>import org.junit.After;<br>import org.junit.Before;<br>import org.junit.Test;<br><br>import common.HTTPBaseIO2;<br>import common.model.HTTPResponse;<br><br>public class HTTPBaseIO2Test {<br><br> @Before<br> public void setUp() throws Exception {<br> }<br><br> @After<br> public void tearDown() throws Exception {<br> }<br><br> @Test<br> public void testDoGet() {<br> String urltest = "http://localhost:8080/Test/Test1" ;<br> String charset="UTF-8";<br> HashMap<String, String> params=new HashMap<String, String>();<br> try {<br> params.put("val", "測試&測試");<br> HTTPResponse html=HTTPBaseIO2.doSend(urltest, HTTPBaseIO2.Method.get, params, charset,true,null,null);<br> System.out.println("testDoGet:"+html.getHtml());<br> } catch (Exception e) {<br> e.printStackTrace();<br> }<br> }<br><br> @Test<br> public void testDoPost() {<br> String urltest = "http://localhost:8080/Test/Test1" ;<br> String charset="UTF-8";<br> HashMap<String, String> params=new HashMap<String, String>();<br> try {<br> params.put("val", "測試1&測試1");<br> HTTPResponse html=HTTPBaseIO2.doSend(urltest, HTTPBaseIO2.Method.post, params, charset,true,null,null);<br> System.out.println("testDoPost:"+html.getHtml());<br> params.clear();<br> params.put("val", "測試2&測試2");<br> html=HTTPBaseIO2.doSend(urltest, HTTPBaseIO2.Method.post, params, charset,true,null,null);<br> System.out.println("testDoPost:"+html.getHtml());<br> } catch (Exception e) {<br> e.printStackTrace();<br> }<br> }<br><br>}<br></code></pre>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com2tag:blogger.com,1999:blog-2698062899592178296.post-89081092796556578872010-12-30T19:11:00.000-08:002010-12-30T19:12:36.565-08:00[CentOS]JBoss5.1安裝<h4>序言</h4>
此篇簡單的記錄JBoss在CentOS的安裝步驟。<br>
<h4 style="margin: 5px 0px; color: rgb(51, 51, 51);">環境</h4>
<ul><li>OS:<a href="http://isoredirect.centos.org/centos/4/isos/x86_64/">CentOS 4.8</a></li>
<li><span>JVM:JDK 1.6.0 update 20 (<a href="http://allen080.blogspot.com/2010/12/centosjdkjava.html">安裝過程參考</a>)<br>
</span></li></ul>
<div>
<h4>安裝步驟<br>
</h4>
<ol><li>到<a href="http://www.jboss.org/jbossas/downloads.html">官方網站</a>下載JBoss的5.1.0版的zip檔如[jboss-5.1.0.GA.zip]</li>
<li>到[/usr/local/]目錄下解壓縮這個zip檔
<pre><code>#cd /usr/local/<br>#unzip jboss-5.1.0.GA.zip</code></pre>
</li>
<li>建立環境變數[JBOSS_HOME],在這邊有兩種方式選一種來就可以了
<ul><li>修改[/etc/profile],可以用如[vi /etc/profile]命令修改,增加已下內容在最後一行:
<pre><code>export JBOSS_HOME=/usr/local/jboss-5.1.0.GA<br>export PATH=$PATH:$JBOSS_HOME/bin</code></pre>
</li>
<li>建立一個[jboss.sh]在[/etc/profile.d]目錄,如[vi /etc/profile.d/jboss.sh],內容如下:
<pre><code>JBOSS_HOME=/usr/local/jboss-5.1.0.GA<br>PATH=$PATH:$JBOSS_HOME/bin<br>export JBOSS_HOME PATH</code></pre>
</li></ul>
</li>
<li>登出再登入OS</li>
<li>執行JBoss看看有沒有辦法啟動,測試網址為<a href="http://localhost:8080/" target="_blank">http://localhost:8080/</a>
<pre><code>#sh $JBOSS_HOME/bin/run.sh -b 0.0.0.0</code></pre>
<ul><li>如果看到以下錯誤訊息而無法啟動,試著修改[/usr/local/jboss-5.1.0.GA/bin/run.conf]這個檔案中的 java [-Xmx]與[-XX:MaxPermSize]這兩個參數的大小
<pre><code>Error occurred during initialization of VM<br>Could not reserve enough space for object heap<br>Could not create the Java virtual machine.</code></pre>
</li></ul>
</li>
<li>如果要將JBoss已背景方式執行,並在OS啟動時自動啟動,可參考
<a href="http://community.jboss.org/wiki/startjbossonbootwithlinux" target="_blank">http://community.jboss.org/wiki/startjbossonbootwithlinux</a>或
<a href="http://amjet.dyndns.biz/blog/IT/?p=297" target="_blank">http://amjet.dyndns.biz/blog/IT/?p=297</a>
<ul>
<li>增加jboss帳號與修改目錄權限
<pre><code>#useradd jboss<br>#cd /usr/local/jboss-5.1.0.GA<br>#chmod -R 700 ./</code></pre>
</li>
<li>修改[/usr/local/jboss-5.1.0.GA/bin/run.conf]檔,將以下內容加在最後一行
<pre><code>JAVA_HOME=/usr/java/latest<br>JBOSS_HOME=/usr/local/jboss-5.1.0.GA<br>JBOSS_HOST=0.0.0.0<br>JAVAPTH=/usr/java/latest</code></pre>
</li>
<li>修改[/usr/local/jboss-5.1.0.GA/bin/jboss_init_redhat.sh]檔,將以下內容加在第一行
<pre><code>. /usr/local/jboss-5.1.0.GA/bin/run.conf</code></pre>
</li>
<li>修改[/etc/rc.local]檔,將以下內容加在最後一行
<pre><code>/usr/local/jboss-5.1.0.GA/bin/jboss_init_redhat.sh start</code></pre>
</li>
<li>如果你想開啟/關閉JBoss就執行以下命令
<pre><code>/usr/local/jboss-5.1.0.GA/bin/jboss_init_redhat.sh start<br>/usr/local/jboss-5.1.0.GA/bin/jboss_init_redhat.sh stop</code></pre>
</li>
</ul>
</li>
</ol>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-34230986454207517122010-12-29T18:51:00.000-08:002011-01-25T23:14:39.666-08:00[CentOS]JDK(Java)安裝<h4>序言</h4>
此篇簡單的記錄JDK在CentOS的安裝步驟,下一篇將會搭配這個Java環境安裝JBoss。<br>
<h4 style="margin: 5px 0px; color: rgb(51, 51, 51);">環境</h4>
<ul><li>OS:<a href="http://isoredirect.centos.org/centos/4/isos/x86_64/">CentOS 4.8</a><br>
</li></ul>
<div>
<h4>安裝步驟<br>
</h4>
<ol><li>到<a href="http://www.oracle.com/technetwork/java/javaee/downloads/index.html">官方網站</a>下載JDK的Linux版的RPM檔如[jdk-6u20-linux-i586-rpm.bin]</li>
<li>執行安裝命令[sh jdk-6u20-linux-i586-rpm.bin],此時會要求你同意授權條件。安裝完成後預設的安裝路徑會帶版號,如[/usr/java/jdk1.6.0_20]。建立一個jdk的目錄連結。<br>
<pre><code>#sh jdk-6u20-linux-i586-rpm.bin
#cd /usr/local
#ln –s /usr/java/jdk1.6.0_20 jdk</code></pre>
</li>
<li>將此JVM加入系統可用Java<br>
<pre><code>#alternatives --install /usr/bin/java java /usr/java/latest 99</code></pre>
</li>
<li>修改系統預設Java,執行此命令會要你選擇可用的Java編號<br>
<pre><code>#alternatives --config java</code></pre>
</li>
<li>輸入已下命令確認是否有出現JAVA版本
<pre><code>#java –version</code></pre>
</li>
<li>建立環境變數[JAVA_HOME],在這邊有兩種方式選一種來就可以了
<ul><li>修改[/etc/profile],可以用如[vi /etc/profile]命令修改,內容如下:
<pre><code>export JAVA_HOME=/usr/java/latest
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin</code></pre>
</li>
<li>建立一個[java.sh]在[/etc/profile.d]目錄,如[vi /etc/profile.d/java.sh],內容如下:
<pre><code>JAVA_HOME=/usr/java/latest
CLASSPATH=.:$JAVA_HOME/lib.tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH</code></pre>
</li></ul>
</li>
<li>登出再登入OS</li>
<li>輸入已下命令確認是否有出現環境變數值
<pre><code>#echo $JAVA_HOME</code></pre>
</li>
</ol>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-23319277570621698522010-12-28T23:35:00.000-08:002010-12-28T23:37:00.945-08:00[CentOS]MySQL安裝<h4>序言</h4>
我依據我自己的環境記錄下我的安裝步驟以供自己參考。<br>
<h4 style="margin: 5px 0px; color: rgb(51, 51, 51);">環境</h4>
<ul><li>OS:<a href="http://isoredirect.centos.org/centos/4/isos/x86_64/">CentOS 4.8</a><br>
</li></ul>
<div>
<h4>安裝步驟<br>
</h4>
<ol><li>到<a href="http://dev.mysql.com/downloads/mysql">官方網站</a>下載MySQL的Linux版的TAR檔如[mysql-5.1.45-linux-i686-glibc23.tar.gz]</li>
<li>依據官方安裝步驟如下,執行最後一步會啟動MySQL<br>
<pre><code>#groupadd mysql<br>#useradd -g mysql mysql<br>#cd /usr/local<br>#gunzip < /path/to/mysql-5.1.45-linux-i686-glibc23.tar.gz | tar xvf -<br>#ln -s /usr/local/mysql-5.1.45-linux-i686-glibc23 mysql<br>#cd mysql<br>#chown -R mysql .<br>#chgrp -R mysql .<br>#scripts/mysql_install_db --user=mysql<br>#chown -R root .<br>#chown -R mysql data<br>#bin/mysqld_safe --user=mysql &</code></pre>
</li>
<li>如果有其他非本機的Client要連現這台DB需建立帳號,如果不綁IP安全性(代表從任何IP都能以該帳號連線)的帳號建立方式如下
<ul><li>進入mysql命令模式
<pre><code># /usr/local/mysql/bin/mysql -u root</code></pre>
</li>
<li>建立帳號
<pre><code>mysql>grant all on *.* to 帳號@ identified by '密碼' with grant option;<br>mysql>FLUSH PRIVILEGES;<br>mysql>quit;</code></pre>
</li></ul>
</li>
<li>關閉MySQL
<pre><code>#/usr/local/mysql/bin/mysqladmin -u root shutdown</code></pre>
</li>
<li>啟動MySQL
<pre><code>#/usr/local/mysql/bin/mysqld_safe &</code></pre>
</li>
<li>資料庫參數設定檔應該是在/etc/my.cnf,如果沒有可以從/usr/local/mysql-5.1.45-linux-i686-glibc23/support-files底下的*.cnf中挑適合的放在/etc/my.cnf<br>
<ul><li>my-innodb-heavy-4G.cnf: 這是一個針對 4G RAM(主要運行只有 InnoDB 表的 MySQL 並使用幾個連接數執行複雜的查詢)。</li>
<li>my-huge.cnf: 適合 1GB - 2GB RAM的主機使用。</li>
<li>my-large.cnf: 適合 512MB RAM的主機使用。</li>
<li>my-medium.cnf: 只有 32MB - 64MB RAM 的主機使用,或者有 128MB RAM 但需要運行其他伺服器,例如 web server。</li>
<li>my-small.cnf: 記憶體少於 64MB 時適用這個,MySQL 會佔用較少資源。 <br>
</li></ul>
</li>
<li>將MySQL設為在OS啟動時自動啟動
<pre><code>#cp /usr/local/mysql-5.1.45-linux-i686-glibc23/support-files/mysql.server /etc/rc.d/init.d/mysqld
#chmod 700 /etc/init.d/mysqld
#chkconfig --add mysqld
#chkconfig --level 345 mysqld on
</code></pre>
</li>
</ol>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-90996711012127086542010-12-28T22:28:00.000-08:002011-04-15T00:25:57.891-07:00[4Shared]網路硬碟上傳下載教學(Desktop程式版)<h4>序言</h4>
幾年前曾經為了分享照片給別人,所以我曾經開發過一個<a href="http://allen080.blogspot.com/2007/04/friend-share.html">FriendShare</a>的網站。<br>
不過當時是因為自己有個上傳速度夠快的環境所以架站很方便,這個網站也隨著這樣的環境消失而消失了。<br>
後來我找了幾個免費的網路硬碟服務想看看有沒有能方便使用,限制的部份與我的使用習慣較不抵觸的環境,但一直都沒有結論。<br>
最近分享照片時我心血來潮又找了一回,發現<a href="http://www.4shared.com/">4shared</a>的網路評價不錯,限制又比較符合我所想的。<br>
除了網頁上傳下載外,它自己也有提供上傳下載的程式可用(連手機版的都有,可惜還沒有Android版)~<br>
我試了一下還滿好用的,不過網路上對程式版使用這部份的網路教學好像沒看到,所以我就乾脆自己寫。<br>
希望有要分享照片的朋友能學會使用,以後就不用MSN傳半天傳不到我手裡了。<br>
<br>
以下我分成三部份來跟大家介紹這個網路硬碟的桌面程式使用方式<br>
<ul><li><a href="#4shared0">服務限制</a></li>
<li><a href="#4shared1">桌面程式安裝與帳號申請</a>
</li>
<li><a href="#4shared2">上傳教學</a></li>
<li><a href="#4shared3">下載教學</a>
</li></ul>
<br>
<h4><a name="4shared0">服務限制</a></h4>
<div>在大家很開心的分享檔案之前,我建議還是要看一下免費帳號的限制,免得被砍帳號都不知道:<br>
<ul><li>三十天內沒登入,你就會被砍帳號與檔案。只要你沒被砍帳號,檔案都有效~<br>
(基本上我想分享檔案後30天內大概想要檔案的人都抓完了,所以真的被砍帳號下回要分享時再申請一次帳號就不成問題了)<br>
</li>
<li>空間限制:每個帳號10G,上傳的一個檔案上限200MB(<a href="http://www.4shared.com/premium.jsp?ref=header">付費帳號</a>就不同了)<br>
</li>
</ul>
完整內容請參考官方的<a href="http://www.4shared.com/terms.jsp">使用條款</a><br>
<br>
</div>
<h4><a name="4shared1">桌面程式安裝與帳號申請</a></h4>
<div><a href="http://img210.imageshack.us/i/000ny.jpg/" target="_blank"><img src="http://img210.imageshack.us/img210/6573/000ny.th.jpg" border="0"></a><br>
</div>
<div style="margin-left: 40px;">到<a href="http://www.4shared.com/">http://www.4shared.com/</a>首頁的下載<a href="http://dc159.4shared.com/download/50786419/76ca898d/4shared_Desktop_320.exe">4shared 桌面程式</a>,下載完後開使安裝<br>
</div>
<div>
<a href="http://img830.imageshack.us/i/002nw.jpg/" target="_blank"><img src="http://img830.imageshack.us/img830/6079/002nw.th.jpg" border="0"></a>
<a href="http://img810.imageshack.us/i/003fp.jpg/" target="_blank"><img src="http://img810.imageshack.us/img810/7145/003fp.th.jpg" border="0"></a>
<a href="http://img5.imageshack.us/i/004qdb.jpg/" target="_blank"><img src="http://img5.imageshack.us/img5/9904/004qdb.th.jpg" border="0"></a><br>
</div>
<div style="margin-left: 40px;">安裝過程中有出現是不是要安裝Tool bar,這個看個人,我圖上的操作是不安裝<br>
</div>
<div>
<a href="http://img88.imageshack.us/i/005ws.jpg/" target="_blank"><img src="http://img88.imageshack.us/img88/1677/005ws.th.jpg" border="0"></a>
<a href="http://img3.imageshack.us/i/006moep.jpg/" target="_blank"><img src="http://img3.imageshack.us/img3/3548/006moep.th.jpg" border="0"></a>
<a href="http://img225.imageshack.us/i/007us.jpg/" target="_blank"><img src="http://img225.imageshack.us/img225/982/007us.th.jpg" border="0"></a><br>
<div style="margin-left: 40px;">安裝完成後啟動程式<br>
</div>
<a href="http://img833.imageshack.us/i/008ycg.jpg/" target="_blank"><img src="http://img833.imageshack.us/img833/5008/008ycg.th.jpg" border="0"></a>
<a href="http://img821.imageshack.us/i/009yb.jpg/" target="_blank"><img src="http://img821.imageshack.us/img821/4225/009yb.th.jpg" border="0"></a>
<a href="http://img808.imageshack.us/i/010qh.jpg/" target="_blank"><img src="http://img808.imageshack.us/img808/8022/010qh.th.jpg" border="0"></a><br>
<div style="margin-left: 40px;">程式剛啟動時回讓你選【我是4Shared新手】,就是要註冊一個帳號。註冊時選擇計劃【Free】就是免費帳號<br>
</div>
<a href="http://img403.imageshack.us/i/011us.jpg/" target="_blank"><img src="http://img403.imageshack.us/img403/8712/011us.th.jpg" border="0"></a>
<a href="http://img140.imageshack.us/i/012uk.jpg/" target="_blank"><img src="http://img140.imageshack.us/img140/9760/012uk.th.jpg" border="0"></a>
<a href="http://img833.imageshack.us/i/013xhu.jpg/" target="_blank"><img src="http://img833.imageshack.us/img833/7450/013xhu.th.jpg" border="0"></a><br>
<div style="margin-left: 40px;">或是你已經有帳號就選登錄現有帳戶。<br>
登入成功後,會顯示使用提示,然後告訴你它有個同步用的資料夾讓你可以指定,這些看看就選跳過與結束就可以了,這看個人使用需求自己玩玩看吧。<br>
<br>
</div>
</div>
<h4 ><a name="4shared2">上傳教學</a></h4>
<div><a href="http://img547.imageshack.us/i/001bg.jpg/" target="_blank"><img src="http://img547.imageshack.us/img547/6549/001bg.th.jpg" border="0"></a><br>
上傳的時候壓縮時選一下分割檔為200Mb,這樣上傳才不會失敗。<br>
<a href="http://img5.imageshack.us/i/014jai.jpg/" target="_blank"><img src="http://img5.imageshack.us/img5/652/014jai.th.jpg" border="0"></a>然後在右下角的上傳區選擇要上傳的檔案(也可以點upload鈕選檔案或目錄)<br>
<a href="http://img84.imageshack.us/i/015or.jpg/" target="_blank"><img src="http://img84.imageshack.us/img84/2603/015or.th.jpg" border="0"></a>選好檔案就會看到它開始上傳了<br>
<a href="http://img27.imageshack.us/i/016dw.jpg/" target="_blank"><img src="http://img27.imageshack.us/img27/206/016dw.th.jpg" border="0"></a>上傳完成就會出現在上面的區塊,這時想要把上傳的檔案分享給別人,只要右鍵選獲得鍊結<br>
<a href="http://img534.imageshack.us/i/017eya.jpg/" target="_blank"><img src="http://img534.imageshack.us/img534/1489/017eya.th.jpg" border="0"></a>然後選擇下面的連結,再點複製,就會得到檔案連結,就可以把這個下載連結告訴要分享的人囉。<br>
<br>
</div>
<h4><a name="4shared3">下載教學</a></h4>
<div>(最近發現JDownloader這個工具可以很方便的下載4Shared的檔案,教學與下載文可參考<a href="http://www.inote.tw/2009/06/jdownloader.html" target="_blank">[下載&教學] JDownloader 0.9.581 中文免安裝版 ~ 最強的免費空間下載器 by 海芋</a>)</div>
<div><a href="http://img691.imageshack.us/i/018vo.jpg/" target="_blank"><img src="http://img691.imageshack.us/img691/5039/018vo.th.jpg" border="0"></a>拿到別人分享的連結一打開,就會出現這個畫面。這時你有兩種下載的方式:<br>
第一種就是選【現在下載】(這個方式要等倒數,沒耐心請直接往下看第二種方式)<br>
<a href="http://img690.imageshack.us/i/019pvj.jpg/" target="_blank"><img src="http://img690.imageshack.us/img690/7946/019pvj.th.jpg" border="0"></a>就會進到一個倒數的畫面<br>
<a href="http://img836.imageshack.us/i/020dq.jpg/" target="_blank"><img src="http://img836.imageshack.us/img836/4610/020dq.th.jpg" border="0"></a>倒數結束就會出現【現在下載檔案】可以點選下載。<br>
<a href="http://img691.imageshack.us/i/018vo.jpg/" target="_blank"><img src="http://img691.imageshack.us/img691/5039/018vo.th.jpg" border="0"></a>第二種就是點選加到我的帳戶(如果檔案本來就是你的就沒這項,你就直接到程式介面就能下載了)<br>
<a href="http://img404.imageshack.us/i/021is.jpg/" target="_blank"><img src="http://img404.imageshack.us/img404/7063/021is.th.jpg" border="0"></a>然後沒登入的話就會要你登入,登入後會看到一個網頁版的檔案管理畫面,不過我們要下載是用程式下載,所以回到桌面程式畫面。<br>
<a href="http://img208.imageshack.us/i/022fq.jpg/" target="_blank"><img src="http://img208.imageshack.us/img208/352/022fq.th.jpg" border="0"></a>這時如果你的檔案中沒出現剛才的檔案就右鍵選單選【Reflash】<br>
<a href="http://img526.imageshack.us/i/023ee.jpg/" target="_blank"><img src="http://img526.imageshack.us/img526/2946/023ee.th.jpg" border="0"></a>然後就可以選想下載的檔案來下載了。<br>
<a href="http://img137.imageshack.us/i/024et.jpg/" target="_blank"><img src="http://img137.imageshack.us/img137/852/024et.th.jpg" border="0"></a>第一次下載會問你要下載到哪<br>
<a href="http://img687.imageshack.us/i/025wte.jpg/" target="_blank"><img src="http://img687.imageshack.us/img687/4149/025wte.th.jpg" border="0"></a>這就是下載中的樣子</div>
<h4>總結</h4>
<div>上手後就超簡單的,當然如果不安裝桌面程式的人也可以用網頁登入管理檔案或是找<a href="http://www.4shared.com/file/mnekDfdp/4shared_Desktop335.html">免安裝版</a>的來用<br>
</div>
<h4>相關連結</h4>
<div>
<ul><li>
<a href="http://sofree.cc/4shared/" rel="bookmark" title="閱讀:4shared 中文介面,免費10GB網路硬碟!">4shared 中文介面,免費10GB網路硬碟!--網頁版使用By</a><a href="http://sofree.cc/author/s9011514/" title="由 香腸 發表">香腸</a>
</li></ul>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-34234377320477496752010-03-29T23:27:00.000-07:002011-03-29T19:31:53.762-07:00[Java]Http Get與Post函式(Apache HttpClient)<h4>序言</h4>
要達到基本的Http get與post方法取得網站內容,<a href="http://allen080.blogspot.com/2011/03/javahttp-getpost2httpurlconnection.html">Java內的URLConnection就可以達成</a>。<br>
但我實作時發現它太過於底層,以致於我不知該如何做到關於Session狀態的延續,也就是不能夠在完成登入後,保留住登入狀態然後進入下個動作。<br>
於是就尋求別的作法,最後發現了Apache有提供了<a href="http://hc.apache.org/httpclient-3.x/" target="_blank">HttpClient</a>套件的JAR檔,能讓我們用更簡單的方式達成工作。<br>
在此參考網路上的文章:<a href="http://blog.csdn.net/jadesun/archive/2006/11/23/1406959.aspx">用HttpClient來模擬瀏覽器GET,POST</a>,加上可自動轉導的功能,包成函式。<br>
另外再加上可用三種類型來設定傳遞的參數,並控制其連線與中斷狀態。<br>
<br>
<h4>下載套件</h4>
<div>到<a href="http://hc.apache.org/downloads.cgi" target="_blank">HttpClient Download</a>下載套件,選擇Binary with dependencies的版本(如<a href="http://ftp.twaren.net/Unix/Web/apache/httpcomponents/httpclient/binary/httpcomponents-client-4.0.1-bin-with-dependencies.zip" target="_blank">4.0.1.zip</a>),<br>
我們需要的JAR在該壓縮檔中的lib目錄下。會用到的JAR檔有三個:<br>
<ul><li>commons-logging-1.1.1.jar</li>
<li>httpclient-4.0.1.jar</li>
<li>httpcore-4.0.1.jar</li></ul>
</div>
<h4>函式原始碼</h4>
參數轉換函式
<pre><code>package common.control;<br><br>import java.io.BufferedReader;<br>import java.io.IOException;<br>import java.io.InputStream;<br>import java.io.InputStreamReader;<br>import java.io.UnsupportedEncodingException;<br>import java.net.URLEncoder;<br>import java.util.ArrayList;<br>import java.util.HashMap;<br><br>public class HTTPParseFunc {<br><br> /**<br> * hashMapToString<br> * <br> * @param map<br> * @param charset編碼<br> * ,如HTTP.UTF_8<br> * @return<br> * @throws UnsupportedEncodingException<br> */<br> @SuppressWarnings("unchecked")<br> public static String hashMapToString(HashMap<String, String> map,<br> String charset) throws UnsupportedEncodingException {<br> StringBuffer result = new StringBuffer();<br> java.util.Iterator it = map.entrySet().iterator();<br> boolean isfirst = true;<br> while (it.hasNext()) {<br> java.util.Map.Entry entry = (java.util.Map.Entry) it.next();<br> if (isfirst) {<br> isfirst = false;<br> } else {<br> result.append("&");<br> }<br> result<br> .append(URLEncoder.encode(entry.getKey().toString(),<br> charset));<br> result.append("=");<br> result.append(URLEncoder.encode(entry.getValue().toString(),<br> charset));<br> }<br> return result.toString();<br> }<br> /**<br> * 將inputStream轉為String<br> * <br> * @param is<br> * inputStream<br> * @param charset<br> * 編碼,如HTTP.UTF_8<br> * @return inputStream的內容<br> * @throws UnsupportedEncodingException<br> */<br> public static String inputStream2String(InputStream is, String charset)<br> throws UnsupportedEncodingException {<br> BufferedReader in = new BufferedReader(new InputStreamReader(is,<br> charset));<br> StringBuffer buffer = new StringBuffer();<br> String line = "";<br> try {<br> boolean isfirst = true;<br> while ((line = in.readLine()) != null) {<br> if (!isfirst) {<br> buffer.append("\n");<br> } else {<br> isfirst = false;<br> }<br> buffer.append(line);<br> }<br> } catch (IOException e) {<br> e.printStackTrace();<br> }<br><br> return buffer.toString();<br> }<br><br> /**<br> * HTTP 傳輸參數分割<br> * @param param 如name1=value1&name2=value2<br> * @return<br> * @throws UnsupportedEncodingException<br> */<br> public static ArrayList<String[]> paramToArray(String param)<br> throws UnsupportedEncodingException {<br> ArrayList<String[]> arr = null;<br> String[] p = param.split("&");<br> if (param.toLowerCase().contains("&amp;")) {<br> ArrayList<String> p2 = new ArrayList<String>();<br> int j = 0;<br> for (int i = 0; i < p.length; i++) {<br> if (p[i].toLowerCase().startsWith("amp;")) {<br> p2.set(j - 1, p2.get(j - 1) + "&amp;" + p[i].substring(4));<br> j--;<br> }<br> p2.add(p[i]);<br> j++;<br> }<br> p2.toArray(p);<br> }<br><br> for (int i = 0; i < p.length; i++) {<br> String[] item = p[i].split("=");<br> if (item.length == 2) {<br> if (arr == null)<br> arr = new ArrayList<String[]>();<br> // item[0]=URLDecoder.decode(item[0],charset);<br> // item[1]=URLDecoder.decode(item[1],charset);<br> arr.add(item);<br> }<br> }<br> return arr;<br> }<br>}<br><br></code></pre>
HTTP連線函式
<pre><code>package common;<br><br>import java.io.IOException;<br>import java.io.UnsupportedEncodingException;<br>import java.util.HashMap;<br>import java.util.List;<br><br>import org.apache.http.Header;<br>import org.apache.http.HttpEntity;<br>import org.apache.http.HttpHost;<br>import org.apache.http.HttpResponse;<br>import org.apache.http.HttpStatus;<br>import org.apache.http.NameValuePair;<br>import org.apache.http.client.ClientProtocolException;<br>import org.apache.http.client.entity.UrlEncodedFormEntity;<br>import org.apache.http.client.methods.HttpGet;<br>import org.apache.http.client.methods.HttpPost;<br>import org.apache.http.client.methods.HttpUriRequest;<br>import org.apache.http.conn.params.ConnRoutePNames;<br>import org.apache.http.entity.StringEntity;<br>import org.apache.http.impl.client.DefaultHttpClient;<br>import org.apache.http.params.HttpConnectionParams;<br>import org.apache.http.params.HttpParams;<br><br>import common.control.HTTPParseFunc;<br><br>public class HTTPBaseIO {<br> public enum Method {<br> get, post<br> }<br><br> private DefaultHttpClient httpclient = null;<br> private boolean isClosedConn = false;<br> private String newuri = null;<br> private int statuscode = HttpStatus.SC_NO_CONTENT;<br><br> private HttpHost proxy = null;<br><br> private Integer timeout=null;<br> <br> public HTTPBaseIO(){<br> <br> }<br> public HTTPBaseIO(String proxyIP,int proxyPort){<br> setProxy(proxyIP,proxyPort);<br> }<br> public HTTPBaseIO(HttpHost proxy){<br> setProxy(proxy);<br> }<br> <br> /**<br> * 取得使用的proxy<br> */<br> public HttpHost getProxy() {<br> return proxy;<br> }<br><br> /**<br> * 設定proxy<br> */<br> public void setProxy(HttpHost proxy) {<br> this.proxy = proxy;<br> }<br><br> /**<br> * 設定proxy<br> * <br> * @param ip<br> * proxy的IP(hostname)<br> * @param port<br> * proxy的Port<br> */<br> public void setProxy(String ip, int port) {<br> if(ip!=null)<br> proxy = new HttpHost(ip, port);<br> }<br><br> /**<br> * 取得回應後所得到的代碼,可參考org.apache.http.HttpStatus類別<br> * <br> * @return org.apache.http.HttpStatus<br> */<br> public int getStatuscode() {<br> return statuscode;<br> }<br><br> /**<br> * 如果是轉導的狀態所得到的URI<br> * <br> * @return<br> */<br> public String getNewuri() {<br> return newuri;<br> }<br><br> public void resetNewuri() {<br> newuri = null;<br> }<br><br> /**<br> * 取得連線物件<br> * <br> * @return<br> */<br> public DefaultHttpClient getHttpclient() {<br> return httpclient;<br> }<br><br> /**<br> * 設定連線物件<br> * <br> * @param httpclient<br> */<br> public void setHttpclient(DefaultHttpClient httpclient) {<br> this.httpclient = httpclient;<br> }<br><br> /**<br> * 是否已關閉連線<br> * <br> * @return<br> */<br> public boolean isClosedConn() {<br> return isClosedConn;<br> }<br><br> /**<br> * 關閉連線<br> */<br> public void closeConn() {<br> closeConn(true);<br> }<br><br> /**<br> * 關閉連線<br> * <br> * @param isCloseConn<br> * 是否關閉<br> */<br> public void closeConn(boolean isCloseConn) {<br> if (isCloseConn && httpclient != null && !isClosedConn) {<br> httpclient.getConnectionManager().shutdown();<br> httpclient = null;<br> isClosedConn = true;<br> }<br> }<br><br> public void setHttpConnectionFactoryTimeout(Integer milliseconds){<br> timeout=milliseconds;<br> }<br> <br> /**<br> * 取得網頁內容<br> * <br> * @param urlpath<br> * 網址<br> * @param method<br> * Method.get or Method.post<br> * @param params<br> * 參數<br> * @param charset<br> * 編碼,如HTTP.UTF_8<br> * @param isAutoRedirect<br> * 如果網頁回應狀態為轉導到新網頁,且Header的location有值,則自己以location所指網址取得內容<br> * @param isCloseConn<br> * 是否關閉連線<br> * @return 失敗回傳null,成功回傳網頁HTML<br> * @throws ClientProtocolException<br> * @throws IOException<br> */<br> public String doSend(String urlpath, Method method, String params,<br> String charset, boolean isAutoRedirect, boolean isCloseConn)<br> throws ClientProtocolException, IOException {<br> return doSendBase(urlpath, method, StringToHttpEntity(params, charset),<br> charset, isAutoRedirect, isCloseConn);<br> }<br><br> /**<br> * 取得網頁內容<br> * <br> * @param urlpath<br> * 網址<br> * @param method<br> * Method.get or Method.post<br> * @param params<br> * 參數<br> * @param charset<br> * 編碼,如HTTP.UTF_8<br> * @param isAutoRedirect<br> * 如果網頁回應狀態為轉導到新網頁,且Header的location有值,則自己以location所指網址取得內容<br> * @param isCloseConn<br> * 是否關閉連線<br> * @return 失敗回傳null,成功回傳網頁HTML<br> * @throws ClientProtocolException<br> * @throws IOException<br> */<br> public String doSend(String urlpath, Method method,<br> List<NameValuePair> params, String charset, boolean isAutoRedirect,<br> boolean isCloseConn) throws ClientProtocolException, IOException {<br> return doSendBase(urlpath, method, ListToHttpEntity(params, charset),<br> charset, isAutoRedirect, isCloseConn);<br> }<br><br> /**<br> * 取得網頁內容<br> * <br> * @param urlpath<br> * 網址<br> * @param method<br> * Method.get or Method.post<br> * @param params<br> * 參數<br> * @param charset<br> * 編碼,如HTTP.UTF_8<br> * @param isAutoRedirect<br> * 如果網頁回應狀態為轉導到新網頁,且Header的location有值,則自己以location所指網址取得內容<br> * @param isCloseConn<br> * 是否關閉連線<br> * @return 失敗回傳null,成功回傳網頁HTML<br> * @throws ClientProtocolException<br> * @throws IOException<br> */<br> public String doSend(String urlpath, Method method,<br> HashMap<String, String> params, String charset,<br> boolean isAutoRedirect, boolean isCloseConn)<br> throws ClientProtocolException, IOException {<br> return doSendBase(urlpath, method,<br> HashMapToHttpEntity(params, charset), charset, isAutoRedirect,<br> isCloseConn);<br> }<br><br> /**<br> * 取得網頁內容<br> * <br> * @param urlpath<br> * 網址<br> * @param method<br> * Method.get or Method.post<br> * @param params<br> * 參數<br> * @param charset<br> * 編碼,如HTTP.UTF_8<br> * @param isAutoRedirect<br> * 如果網頁回應狀態為轉導到新網頁,且Header的location有值,則自己以location所指網址取得內容<br> * @param isCloseConn<br> * 是否關閉連線<br> * @return 失敗回傳null,成功回傳網頁HTML<br> * @throws ClientProtocolException<br> * @throws IOException<br> */<br> public String doSendBase(String urlpath, Method method, HttpEntity params,<br> String charset, boolean isAutoRedirect, boolean isCloseConn)<br> throws ClientProtocolException, IOException {<br> String responseBody = null;<br> HttpUriRequest httpgetpost = null;<br><br> statuscode = HttpStatus.SC_NO_CONTENT;<br> try {<br> if (httpclient == null || isClosedConn())<br> httpclient = new DefaultHttpClient();<br><br> if (proxy != null)<br> httpclient.getParams().setParameter(<br> ConnRoutePNames.DEFAULT_PROXY, proxy);<br><br> if(timeout!=null){<br> HttpParams param = httpclient.getParams();<br> HttpConnectionParams.setConnectionTimeout(param, timeout);<br> HttpConnectionParams.setSoTimeout(param, timeout);<br> }<br> <br> <br> if (method == Method.post) {<br> httpgetpost = new HttpPost(urlpath);<br> if (params != null) {<br> ((HttpPost) httpgetpost).setEntity(params);<br> }<br> } else {<br> if (params != null) {<br> urlpath += "?"<br> + HTTPParseFunc.inputStream2String(params.getContent(), charset);<br> }<br> httpgetpost = new HttpGet(urlpath);<br> }<br><br> HttpResponse response = httpclient.execute(httpgetpost);<br> statuscode = response.getStatusLine().getStatusCode();<br> if ((statuscode == HttpStatus.SC_MOVED_TEMPORARILY)<br> || (statuscode == HttpStatus.SC_MOVED_PERMANENTLY)<br> || (statuscode == HttpStatus.SC_SEE_OTHER)<br> || (statuscode == HttpStatus.SC_TEMPORARY_REDIRECT)) {<br> Header header = response.getFirstHeader("location");<br><br> if (header != null) {<br> newuri = header.getValue();<br> if ((newuri == null) || (newuri.equals("")))<br> newuri = "/";<br> if (isAutoRedirect) {<br> httpgetpost.abort();<br> httpgetpost = null;<br> responseBody = doSendBase(newuri, Method.get, null,<br> charset, true, false);<br> }<br> }<br> } else if (statuscode == HttpStatus.SC_OK) {<br> responseBody = HTTPParseFunc.inputStream2String(response.getEntity()<br> .getContent(), charset);<br> }<br> } catch (ClientProtocolException e) {<br> throw e;<br> } catch (IOException e) {<br> throw e;<br> } catch (Exception e) {<br> e.printStackTrace();<br> } finally {<br> if (httpgetpost != null) {<br> httpgetpost.abort();<br> httpgetpost = null;<br> }<br> closeConn(isCloseConn);<br> }<br> return responseBody;<br> }<br><br> /**<br> * List<NameValuePair>轉為HttpEntity<br> * <br> * @param nvps<br> * @param charset<br> * 編碼,如HTTP.UTF_8<br> * @return<br> * @throws UnsupportedEncodingException<br> */<br> public static HttpEntity ListToHttpEntity(List<NameValuePair> nvps,<br> String charset) throws UnsupportedEncodingException {<br> HttpEntity result = null;<br> if (nvps != null && nvps.size() > 0) {<br> result = new UrlEncodedFormEntity(nvps, charset);<br><br> }<br> return result;<br> }<br><br> /**<br> * String to HttpEntity(<br> * <br> * @param nvps<br> * @param charset<br> * 編碼,如HTTP.UTF_8<br> * @return<br> * @throws UnsupportedEncodingException<br> */<br> public static HttpEntity StringToHttpEntity(String nvps, String charset)<br> throws UnsupportedEncodingException {<br> HttpEntity result = null;<br> if (nvps != null) {<br> StringEntity reqEntity = new StringEntity(nvps, charset);<br> reqEntity.setContentType("application/x-www-form-urlencoded");<br> result = reqEntity;<br> }<br> return result;<br> }<br><br> /**<br> * HashMap To HttpEntity<br> * <br> * @param nvps<br> * @param charset<br> * 編碼,如HTTP.UTF_8<br> * @return<br> * @throws UnsupportedEncodingException<br> */<br> public static HttpEntity HashMapToHttpEntity(HashMap<String, String> nvps,<br> String charset) throws UnsupportedEncodingException {<br> HttpEntity result = null;<br> if (nvps != null) {<br> result = new StringEntity(HTTPParseFunc.hashMapToString(nvps, charset), charset);<br> try {<br> result = StringToHttpEntity(HTTPParseFunc.inputStream2String(result<br> .getContent(), charset), charset);<br> } catch (IllegalStateException e) {<br> e.printStackTrace();<br> } catch (IOException e) {<br> e.printStackTrace();<br> }<br> }<br> return result;<br> }<br><br>}<br><br></code></pre>
<h4>使用範例程式</h4>
<pre><code>package common.test;<br><br>import static org.junit.Assert.*;<br><br>import java.util.ArrayList;<br>import java.util.HashMap;<br>import java.util.List;<br><br>import org.apache.http.NameValuePair;<br>import org.apache.http.message.BasicNameValuePair;<br>import org.apache.http.protocol.HTTP;<br>import org.junit.After;<br>import org.junit.Before;<br>import org.junit.Test;<br><br>import common.HTTPBaseIO;<br>import common.control.HTTPParseFunc;<br><br>public class HTTPBaseIOTest {<br><br> @Before<br> public void setUp() throws Exception {<br> }<br><br> @After<br> public void tearDown() throws Exception {<br> }<br><br> @Test<br> public void testDoGet() {<br> String urltest = "http://www.google.com.tw";<br> String charset = "UTF-8";<br> HTTPBaseIO.Method method = HTTPBaseIO.Method.get;<br> HTTPBaseIO reqClient = new HTTPBaseIO();<br> try {<br> String html = reqClient.doSendBase(urltest, method, null, charset,<br> false, false);<br> System.out.println(html);<br> if (html == null)<br> fail("Client get nothing");<br> } catch (Exception e) {<br> e.printStackTrace();<br> } finally {<br> reqClient.closeConn();<br> }<br> }<br><br> @Test<br> public void testDoPost() {<br> String urlserv1 = "http://localhost/Test1/Serv1";<br> String urlserv2 = "http://localhost/Test1/Serv2";<br> String charset = HTTP.UTF_8;<br> HTTPBaseIO.Method method = HTTPBaseIO.Method.post;<br> HTTPBaseIO reqClient = new HTTPBaseIO();<br> try {<br> HashMap<String, String> map = new HashMap<String, String>();<br> map.put("jobname", "login");<br> map.put("id", "aaa");<br> map.put("pswd", "1234");<br> String html = reqClient.doSend(urlserv1, method, map, charset,<br> false, false);<br> System.out.println(html);<br><br> ArrayList<String[]> arr = HTTPParseFunc.paramToArray(html);<br> for (int i = 0; i < arr.size(); i++)<br> System.out.println(arr.get(i)[0] + "=" + arr.get(i)[1]);<br> if (html == null)<br> fail("Login get nothing");<br><br> String param = "jobname=getname";<br> html = reqClient.doSend(urlserv1, method, param, charset, false,<br> false);<br> System.out.println(html);<br> if (html == null)<br> fail("getname get nothing");<br><br> List<NameValuePair> nvps = new ArrayList<NameValuePair>();<br> nvps.add(new BasicNameValuePair("jobname", "loadserv2"));<br> nvps.add(new BasicNameValuePair("name", "aaa"));<br> reqClient.resetNewuri();<br> html = reqClient.doSend(urlserv1, method, nvps, charset, true,<br> false);<br> if (html == null)<br> fail("loadserv2 get nothing");<br> nvps.clear();<br> if (reqClient.getNewuri() != null && html != null) {<br> nvps.add(new BasicNameValuePair("jobname", "getname2"));<br> html = reqClient.doSend(urlserv2, method, nvps, charset, false,<br> false);<br> System.out.println(html);<br> if (html == null)<br> fail("Name get nothing");<br> nvps.clear();<br> }<br> nvps.clear();<br><br> nvps.add(new BasicNameValuePair("jobname", "Logout"));<br> html = reqClient.doSend(urlserv1, method, nvps, charset, false,<br> false);<br> System.out.println(html);<br> if (html == null)<br> fail("Logout get nothing");<br> nvps.clear();<br> } catch (Exception e) {<br> e.printStackTrace();<br> } finally {<br> reqClient.closeConn();<br> }<br> }<br><br>}<br><br></code></pre>
<h4>總結</h4>
<div>在範例的地方我假設了兩個servlet用來接收傳遞的參數,這部份可能不能直接執行,不過函式我測試過是沒問題的。<br>
使用時可選擇用Hashmap、String、或是List作為參數設定,我分別在範例中都使用過了。<br>
轉跳時可用getNewuri函式來確認是否有取得轉跳的網址,用回傳的html來確認是否有抓到回應的內容。<br>
PS.我發現了Apache提供的這個Client在Windows下會有連線數上限的問題(聽說好像<a href="http://weng32002.blogspot.com/2010/06/maxuserport-tcptimedwaitdelay.html" target="_blank">調整XP連線數可以解決</a>)。
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-71836045742922447062010-03-04T00:40:00.000-08:002010-03-04T00:42:10.591-08:00[JBoss]Java的工作排程套件-Quartz<h4>序言</h4>
作為一個Application Server,JBoss裡的應用程式開發起來主要都是被動的等待Client呼叫啟動。但實際應用上還是有可能需要有個程序能夠在特定時間執行某些命令,例如於午夜12點整進行資料的Reset這種工作。<br>
在不依賴作業系統或是另外執行一支程式處裡工作的狀況,其實JBoss預設就有推薦使用的工作排程套件-<a href="http://www.quartz-scheduler.org/" target="_blank">Quartz</a>。<br>
就Quartz的功能而言,有的功能是與Java內建的Timer重複的,但它功能更多更強大,所以相對的要做一些設定才能使用。<br>
以下我就舉幾個我用的方法來一探Quartz的設定(當然,這不見得是最好的作法)。<br>
<h4 style="margin: 5px 0px; color: rgb(51, 51, 51);">開發環境</h4>
<ul><li>Java Runtime: <a href="http://www.google.com/url?q=http%3A%2F%2Fjava.sun.com%2Fjavase%2Fdownloads%2Fwidget%2Fjdk6.jsp&sa=D&sntz=1&usg=AFrqEzdPJz81hrgmUHXlApvWSf8oHWWb_g" target="_blank">JDK 6 update 17</a><br>
</li>
<li>Java IDE: <a href="http://www.google.com/url?q=http%3A%2F%2Fwww.eclipse.org%2Fdownloads%2Fdownload.php%3Ffile%3D%2Ftechnology%2Fepp%2Fdownloads%2Frelease%2Fgalileo%2FSR1%2Feclipse-jee-galileo-SR1-win32.zip&sa=D&sntz=1&usg=AFrqEzcCcRl_IZKN_G9yVdJ8Oa-6mC9XFg" target="_blank">Eclipse Java EE IDE for Web Developers</a></li>
<li>Application Server: <a href="http://www.google.com/url?q=http%3A%2F%2Fwww.jboss.org%2Fjbossas%2Fdownloads%2F&sa=D&sntz=1&usg=AFrqEzf7hKBBjNkjAP4URHVDInE_TsZeRA">JBoss 5.1.0 GA</a></li>
<li>Quartz:<a href="http://terracotta.org/dl/oss-download-destination?name=quartz-1.7.3.tar.gz&bucket=TCreleases&file=quartz-1.7.3.tar.gz" target="_blank">1.7.3</a><br>
</li></ul>
<div>
<h4 style="margin: 5px 0px; color: rgb(51, 51, 51);">JBoss設定</h4>
<div>
JBoss內建就有Quartz的套件,但版本很老舊,從網路上得到的資訊來看,可能會有一些問題存在。<br>
因此建議的作法是把內建的套件刪除掉,換上新的版本。<br>
</div>
<div>
<ol><li>刪除Jboss下common\lib\目錄的quartz.jar檔</li>
<li>刪除Jboss下server發佈目錄下的quartz-ra.rar,如jboss\server\default\deploy目錄的quartz-ra.rar</li>
<li>quartz套件的壓縮檔打開,將裡面的quartz-all-1.7.3.jar檔案複製到jboss\common\lib(或jboss\server\default\lib)</li>
</ol>
</div>
<div>
<h4>Quartz設定檔</h4>
</div>
<div>Quartz 提供了兩種不同的方式用來把排程工作存在記憶體(RAMJobStore)或資料庫(JDBCJobStore。)中。<br>
<ul><li>RAMJobStore:是預設的方法,因為所有資料都存在記憶體中,所以速度最快,但是如果伺服器停止後,所有排程的工作都會消失</li>
<li>JDBCJobStore:透過 JDBC 把所有工作排成資訊存在資料庫中,但代價就是效能降低和設定複雜度的提高(尤其是有參數要透過JobDataMap在工作執行時使用時)。</li></ul>
在這邊我使用最簡單的RAMJobStore來進行工作排程。<br>
這時會需要建立一個設定檔【quartz-service.xml】來設定工作排程套件的參數。這個檔案會放在JBoss的發佈目錄下,如jboss\server\default\deploy</div>
<pre><code><?xml version="1.0" encoding="UTF-8"?><br><br><server><br><br> <mbean code="org.quartz.ee.jmx.jboss.QuartzService" name="user:service=QuartzService,name=QuartzService"><br> <attribute name="JndiName">Quartz</attribute><br> <attribute name="StartScheduler">true</attribute><br> <attribute name="Properties"><br> org.quartz.scheduler.instanceName = DefaultQuartzScheduler<br> org.quartz.scheduler.rmi.export = false<br> org.quartz.scheduler.rmi.proxy = false<br> org.quartz.scheduler.xaTransacted = false<br> <br> org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool<br> org.quartz.threadPool.threadCount = 5<br> org.quartz.threadPool.threadPriority = 4<br><br> org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore <br> </attribute><br> </mbean><br><br></server></code></pre>
<h4>工作類別</h4>
<div>工作要執行的內容必須實作【org.quartz.Job】介面,如<br>
</div>
<pre><code>package control;<br><br>import org.quartz.Job;<br>import org.quartz.JobDataMap;<br>import org.quartz.JobExecutionContext;<br>import org.quartz.JobExecutionException;<br><br>public class MyJob implements Job {<br> static int jobs=0;<br> @Override<br> public void execute(JobExecutionContext arg0) throws JobExecutionException {<br> JobDataMap dataMap = arg0.getJobDetail().getJobDataMap();<br> Object data1 =dataMap.get("data1");<br> Object data2 =dataMap.get("data2");<br> System.out.println("Start MyJob");<br> System.out.println("data1="+data1);<br> System.out.println("data2="+data2);<br> }<br><br>}</code></pre>
<h4>排程工作</h4>
<div>排程的方式有兩種,一種是設定多久執行工作一次(SimpleTrigger),一種是設定什麼時間要執行工作一次(CronTrigger)。</div>
<div>兩者最主要差別在於描述方式。相同的是兩者都可以設定排程啟動時間,結束時間,重複次數等設定。<br>
<ul><li>使用SimpleTrigger</li></ul>
</div>
<pre><code> String groupName = "Default"; //工作群組<br> String jobName = "MySimpleJob"; //工作名稱<br> InitialContext ctx;<br> ctx = new InitialContext();<br> Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");<br> //如果工作已排程,則刪除同樣工作群組-工作名稱的工作<br> if (scheduler.getJobDetail(jobName, groupName) != null) {<br> scheduler.deleteJob(jobName, groupName);<br> }<br> JobDetail jobDetail = new JobDetail(jobName, groupName,MyJob.class); //設定工作執行的類別為MyJob<br> //設定要傳給工作的參數<br> jobDetail.getJobDataMap().put("data1", "Job1");<br> jobDetail.getJobDataMap().put("data2", jobName);<br> SimpleTrigger simpleTrigger = new SimpleTrigger(jobName, groupName); //Trigger也會設定群組與名稱,但我不確定是有什麼功用<br> simpleTrigger.setRepeatCount(-1); //設定-1無限次重複,如果設為0則就只會執行一次<br> simpleTrigger.setRepeatInterval(15*60*1000); //每15分鐘做一次<br> <br> Calendar curCal = Calendar.getInstance();<br> curCal.add(Calendar.MINUTE, 10);<br> simpleTrigger.setStartTime(curCal.getTime()); //現在時間的10分鐘後啟動工作,如果不設定的話排程開始就會執行第一次<br> <br> scheduler.scheduleJob(jobDetail, simpleTrigger);<br> if (!scheduler.isShutdown()) {<br> scheduler.start();<br> }</code></pre>
<div>
<ul><li>使用CronTrigger</li></ul>
</div>
<pre><code> String groupName = "Default"; //工作群組<br> String jobName = "MyCronJob"; //工作名稱<br> InitialContext ctx;<br> ctx = new InitialContext();<br> Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");<br> //如果工作已排程,則刪除同樣工作群組-工作名稱的工作<br> if (scheduler.getJobDetail(jobName, groupName) != null) {<br> scheduler.deleteJob(jobName, groupName);<br> }<br> JobDetail jobDetail = new JobDetail(jobName, groupName,MyJob.class); //設定工作執行的類別為MyJob<br> //設定要傳給工作的參數<br> jobDetail.getJobDataMap().put("data1", "Job2");<br> jobDetail.getJobDataMap().put("data2", jobName);<br> CronTrigger trigger = new CronTrigger(jobName, groupName,"0 0 0 * * ?"); //每天0點整執行<br> scheduler.scheduleJob(jobDetail, trigger);<br> if (!scheduler.isShutdown()) {<br> scheduler.start();<br> }</code></pre>
<h4>在應用程式第一次被呼叫時排程工作</h4>
<div>在Java Web Application中目前我還沒找到方法能在Jboss啟動時呼叫某個function,只能想到兩種方式當有第一個人啟動這個網站中的網頁時進行第一次的初始設定。<br>
第一種方法是在static instance建立時在被New的物件建構函式中寫要做的工作,像是下面的程式。<br>
但這種做法最大壞處是你沒辦法餵給它關於Web的Session、ServletContext等資訊,因為他是在Web內容還沒建立起來時就產生的。<br>
</div>
<pre><code>import java.util.Calendar;<br><br>import javax.naming.InitialContext;<br><br>import org.quartz.JobDetail;<br>import org.quartz.Scheduler;<br>import org.quartz.SimpleTrigger;<br><br>public class InitJob {<br> private static InitJob instance=new InitJob();<br> private InitJob(){<br> try {<br> String groupName = "Default"; //工作群組<br> String jobName = "MySimpleJob"; //工作名稱<br> InitialContext ctx;<br> ctx = new InitialContext();<br> Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");<br> //如果工作已排程,則刪除同樣工作群組-工作名稱的工作<br> if (scheduler.getJobDetail(jobName, groupName) != null) {<br> scheduler.deleteJob(jobName, groupName);<br> }<br> JobDetail jobDetail = new JobDetail(jobName, groupName,MyJob.class); //設定工作執行的類別為MyJob<br> //設定要傳給工作的參數<br> jobDetail.getJobDataMap().put("data1", "Job1");<br> jobDetail.getJobDataMap().put("data2", jobName);<br> SimpleTrigger simpleTrigger = new SimpleTrigger(jobName, groupName); //Trigger也會設定群組與名稱,但我不確定是有什麼功用<br> simpleTrigger.setRepeatCount(-1); //設定-1無限次重複,如果設為0則就只會執行一次<br> simpleTrigger.setRepeatInterval(15*60*1000); //每15分鐘做一次<br> <br> Calendar curCal = Calendar.getInstance();<br> curCal.add(Calendar.MINUTE, 10);<br> simpleTrigger.setStartTime(curCal.getTime()); //現在時間的10分鐘後啟動工作,如果不設定的話排程開始就會執行第一次<br> <br> scheduler.scheduleJob(jobDetail, simpleTrigger);<br> if (!scheduler.isShutdown()) {<br> scheduler.start();<br> }<br> } catch (Exception e) {<br> System.err.println(e.getMessage());<br> }<br> }<br>}</code></pre>
<div>第二種方法是在Session建立時,設定一個Static 布林變數來判斷是否是第一次啟動,然後在裡面執行要做的工作,像是下面的程式。但相對付出的代價就是每個人進來時都會判斷一次。<br>
如果要用這種方法就要再專案的web.xml中增加listener標籤,如<br>
<pre><code><?xml version="1.0" encoding="UTF-8"?><br><web-app...><br>...<br> <listener><br> <listener-class>control.InitSession</listener-class><br> </listener><br>...<br></web-app></code></pre>
程式如下<br>
</div>
<pre><code>package control;<br><br>import javax.naming.InitialContext;<br>import javax.servlet.ServletContext;<br>import javax.servlet.http.HttpSession;<br>import javax.servlet.http.HttpSessionEvent;<br>import javax.servlet.http.HttpSessionListener;<br><br>import org.quartz.CronTrigger;<br>import org.quartz.JobDetail;<br>import org.quartz.Scheduler;<br><br>public class InitSession implements HttpSessionListener {<br> static boolean isInited=false;<br> @Override<br> public void sessionCreated(HttpSessionEvent arg0) {<br> if(!isInited){<br> //可取得Web相關的資訊<br> ServletContext servletContext = arg0.getSession().getServletContext();<br> HttpSession session = arg0.getSession();<br> //工作設定<br> String groupName = "Default"; //工作群組<br> String jobName = "MyCronJob"; //工作名稱<br> InitialContext ctx;<br> ctx = new InitialContext();<br> Scheduler scheduler = (Scheduler) ctx.lookup("Quartz");<br> //如果工作已排程,則刪除同樣工作群組-工作名稱的工作<br> if (scheduler.getJobDetail(jobName, groupName) != null) {<br> scheduler.deleteJob(jobName, groupName);<br> }<br> JobDetail jobDetail = new JobDetail(jobName, groupName,MyJob.class); //設定工作執行的類別為MyJob<br> //設定要傳給工作的參數<br> jobDetail.getJobDataMap().put("data1", "Job2");<br> jobDetail.getJobDataMap().put("data2", jobName);<br> CronTrigger trigger = new CronTrigger(jobName, groupName,"0 0 0 * * ?"); //每天0點整執行<br> scheduler.scheduleJob(jobDetail, trigger);<br> if (!scheduler.isShutdown()) {<br> scheduler.start();<br> }<br> isInited=true;<br> }<br> }<br><br> @Override<br> public void sessionDestroyed(HttpSessionEvent arg0) { <br> }<br>}<br></code></pre>
<h4>總結</h4>
以上就是在JBoss上面我使用Quartz的使用經驗,至於是否有更好的作法或是我的作法有什麼缺陷,歡迎留言告訴我,謝謝
<h4>參考資料</h4>
<div>
<ul><li><a href="http://www.oracle.com/technology/products/jdev/howtos/10g/jaassec/index.htm" target="_blank">官方文件</a></li>
<li><a target="_blank" href="http://tanyankai.javaeye.com/blog/552017">關於Trigger的簡體中文說明</a> by 孺子牛<br>
</li></ul>
</div>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com6tag:blogger.com,1999:blog-2698062899592178296.post-51828945923654294732010-02-01T01:32:00.000-08:002011-06-21T01:15:27.630-07:00[Java]MySQL/Oracle資料庫存取函式<h4>序言</h4>
延續<a href="http://allen080.blogspot.com/2010/01/jaas-jboss.html">上一篇</a>,這篇針對MySQL資料庫的存取寫出的函式提供給大家參考,開發環境與資料庫連接器的設定可參考上一篇。<br>
我在這邊有兩種建立連線物件的方式,預設是來自JNDI的連線設定,另一種是直接產生的方式,可在建立物件時做選擇。<br>
使用範例的部分我改用JUnit來進行我自己的原始碼驗證,大家可直接參考呼叫的方式。<br>
PS.2011/6/21 更新,加入Oracle的連線方法(但分頁查詢的函式只能用在MySQL)
<h4>原始碼函式類別</h4>
<pre><code>package common;<br><br>import java.sql.Connection;<br>import java.sql.DriverManager;<br>import java.sql.PreparedStatement;<br>import java.sql.ResultSet;<br>import java.sql.ResultSetMetaData;<br>import java.sql.SQLException;<br>import java.sql.Statement;<br>import java.util.ArrayList;<br><br>import javax.naming.InitialContext;<br>import javax.naming.NamingException;<br>import javax.sql.DataSource;<br><br>public class DBBaseIO {<br> private static boolean _isDebug=false;<br> public enum DBType{<br> MySQL<br> ,Oracle<br> }<br> <br> public static void setDebug(boolean isDebug) {<br> _isDebug = isDebug;<br> }<br><br> public static boolean isIsdebug() {<br> return _isDebug;<br> }<br><br> private Connection con = null; // Database objects<br> public Connection getConnection() {<br> return con;<br> }<br><br> private Statement stat = null;<br> private ResultSet rs = null;<br> private PreparedStatement pst = null;<br> private boolean isClosed=false;<br> public boolean isClosedConn(){<br> return isClosed;<br> }<br> <br> protected void finalize () {<br> if(!isClosed)CloseConn();<br> }<br> <br>/**<br> * 建立資料庫存取物件(使用JNDI XML設定,名稱為MySqlDS)<br> * @throws SQLException<br> * @throws NamingException<br> */<br> public DBBaseIO() throws SQLException, NamingException {<br> setupConnMySQLByXML();<br> }<br> /**<br> * 建立資料庫存取物件(使用JNDI XML設定)<br> * @param dsName 設定名稱<br> * @throws SQLException<br> * @throws NamingException<br> */<br> public DBBaseIO(String dsName) throws SQLException, NamingException {<br> setupConnMySQLByXML(dsName);<br> }<br> /**<br> * <br> * @param sourceType<br> * @throws ClassNotFoundException<br> * @throws SQLException<br> * @throws NamingException<br> */<br> public DBBaseIO(int sourceType) throws ClassNotFoundException, SQLException, NamingException{<br> switch(sourceType){<br> case 0:<br> setupConnMySQL("localhost:3306", "root", "", "mysql");<br> break;<br> case 1:<br> setupConnMySQLByXML();<br> break;<br> } <br> }<br> /**<br> * 建立資料庫存取物件<br> * <br> * @param str_SQLIP<br> * 資料庫IP<br> * @param str_SQLID<br> * 登入帳號<br> * @param str_SQLPSWD<br> * 登入密碼<br> * @param str_SQLDefaultDBName<br> * 預設資料庫<br> * @throws SQLException <br> * @throws ClassNotFoundException <br> */<br> public DBBaseIO(String str_SQLIP, String str_SQLID, String str_SQLPSWD,<br> String str_SQLDefaultDBName) throws ClassNotFoundException, SQLException {<br> setupConnMySQL(str_SQLIP, str_SQLID, str_SQLPSWD, str_SQLDefaultDBName);<br> }<br> /**<br> * 建立資料庫存取物件<br> * <br> * @param dbtype<br> * 資料庫類型<br> * @param str_SQLIP<br> * 資料庫IP<br> * @param str_SQLID<br> * 登入帳號<br> * @param str_SQLPSWD<br> * 登入密碼<br> * @param str_SQLDefaultDBName<br> * 預設資料庫<br> * @throws SQLException <br> * @throws ClassNotFoundException <br> */<br> public DBBaseIO(DBType dbtype,String str_SQLIP, String str_SQLID, String str_SQLPSWD,<br> String str_SQLDefaultDBName) throws ClassNotFoundException, SQLException {<br> if(dbtype==DBType.MySQL)<br> setupConnMySQL(str_SQLIP, str_SQLID, str_SQLPSWD, str_SQLDefaultDBName);<br> else if(dbtype==DBType.Oracle)<br> setupConnOracle(str_SQLIP, str_SQLID, str_SQLPSWD, str_SQLDefaultDBName);<br> else<br> throw new ClassNotFoundException("DBType un-define");<br> }<br> private void setupConnMySQLByXML() throws NamingException, SQLException{setupConnMySQLByXML("MySqlDS"); }<br> private void setupConnMySQLByXML(String name) throws NamingException, SQLException{<br> if(isIsdebug()){<br> System.out.println("DataSource:"+"java:/" + name);<br> }<br> <br> try{ <br> InitialContext ctx = new InitialContext();<br> DataSource ds = (DataSource)ctx.lookup("java:/" + name);<br> con = ds.getConnection();<br> } catch (NamingException e) {<br> System.err.println("Connection XML Load Error :" + e.toString());<br> throw e;<br> } catch (SQLException e) {<br> System.err.println("Get Connection Error :" + e.toString());<br> throw e;<br> }<br> }<br><br> private void setupConnMySQL(String str_SQLIP, String str_SQLID,<br> String str_SQLPSWD, String str_SQLDefaultDBName) throws ClassNotFoundException,SQLException {<br> if(isIsdebug()){<br> System.out.println("DataSource:"+"jdbc:mysql://" + str_SQLIP + "/"<br> + str_SQLDefaultDBName<br> + "?useUnicode=true&characterEncoding=UTF8");<br> System.out.println("ID:"+str_SQLID+"\tPassword:"+str_SQLPSWD);<br> System.out.println("JDBC Driver:" + "com.mysql.jdbc.Driver");<br> }<br> try {<br> Class.forName("com.mysql.jdbc.Driver");<br> <br> con = DriverManager.getConnection("jdbc:mysql://" + str_SQLIP + "/"<br> + str_SQLDefaultDBName<br> + "?useUnicode=true&characterEncoding=UTF8", str_SQLID,<br> str_SQLPSWD);<br> <br> } catch (ClassNotFoundException e) {<br> System.err.println("DriverClassNotFound :" + e.toString());<br> throw e;<br> }<br> catch (SQLException x) {<br> System.err.println("Exception :" + x.toString());<br> throw x;<br> }<br> }<br> private void setupConnOracle(String str_SQLIP, String str_SQLID,<br> String str_SQLPSWD, String str_SQLDefaultDBName) throws ClassNotFoundException,SQLException {<br> if(isIsdebug()){<br> System.out.println("DataSource:"+"jdbc:oracle:thin:"+str_SQLID+"/"+str_SQLPSWD+"@//" + str_SQLIP + "/"<br> + str_SQLDefaultDBName);<br> }<br> try {<br> Class.forName("oracle.jdbc.OracleDriver");<br> <br> con = DriverManager.getConnection("jdbc:oracle:thin:"+str_SQLID+"/"+str_SQLPSWD+"@//" + str_SQLIP + "/"<br> + str_SQLDefaultDBName);<br> <br> } catch (ClassNotFoundException e) {<br> System.err.println("DriverClassNotFound :" + e.toString());<br> throw e;<br> }<br> catch (SQLException x) {<br> System.err.println("Exception :" + x.toString());<br> throw x;<br> }<br> }<br><br> /**<br> * 執行insert update delete等更新指令用<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @return 資料庫變動筆數<br> */<br> public int executeUpdate(String str_SQL) throws SQLException,NullPointerException {<br> return executeUpdate(str_SQL, null);<br> }<br><br> /**<br> * 執行insert update delete等更新指令用<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @param param<br> * 參數設定,SQL語法中以?指定,順序即為?的順序,如 where name=? (此參數可為null)<br> * @return 資料庫變動筆數<br> */<br> public int executeUpdate(String str_SQL, Object[] param) throws SQLException ,NullPointerException{<br> return executeUpdate(str_SQL, param, true);<br> }<br><br> /**<br> * 執行insert update delete等更新指令用<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @param param<br> * 參數設定,SQL語法中以?指定,順序即為?的順序,如 where name=? (此參數可為null)<br> * @param isCloseConn<br> * 是否關閉連線<br> * @return 資料庫變動筆數<br> */<br> public int executeUpdate(String str_SQL, Object[] param, boolean isCloseConn) throws SQLException,NullPointerException {<br> if(isIsdebug()){<br> System.out.println("executeUpdate:"+str_SQL);<br> if(param!=null)<br> for(int i=0;i<param.length;i++)<br> System.out.println("Parameter "+ i +":"+param[i]);<br> System.out.println("isCloseConn :"+isCloseConn);<br> }<br> <br> int result = 0;<br> if (con != null) {<br> try {<br> int i = 0;<br> if (param == null) {<br> stat = con.createStatement();<br> result = stat.executeUpdate(str_SQL);<br> } else {<br> pst = con.prepareStatement(str_SQL);<br> for (i = 0; i < param.length; i++) {<br> pst.setObject(i + 1, param[i]);<br> }<br> result = pst.executeUpdate();<br> try {<br> pst.clearParameters();<br> } catch (Exception e) {<br> CloseConn();<br> }<br> }<br> } catch (SQLException e) {<br> System.err.println("executeUpdate Exception :" + e.toString());<br> throw e;<br> } finally {<br> CloseConn(isCloseConn);<br> }<br> } else {<br> System.err.println("Connection is null");<br> throw new NullPointerException("Connection is null");<br> }<br> return result;<br> }<br> <br> <br> /**<br> * 批次執行SQL指令使用<br> * <br> * @param str_SQL<br> * 查詢語法的陣列<br> * @param isCloseConn<br> * 是否關閉連線<br> * @return 資料庫變動筆數的陣列<br> */<br> public int[] executeBatch(String[] str_SQL, boolean isCloseConn) throws SQLException,NullPointerException {<br> if(isIsdebug()){<br> System.out.println("executeBatch:"+str_SQL);<br> }<br> <br> int[] result=null;<br> if (con != null) {<br> try {<br> int i = 0;<br> stat = con.createStatement();<br> for (i = 0; i < str_SQL.length; i++) {<br> stat.addBatch(str_SQL[i]);<br> }<br> result=stat.executeBatch();<br> if(isIsdebug()){<br> System.out.println("executeBatch result:");<br> for (i = 0; i < result.length; i++) {<br> System.out.println(i+":"+result[i]);<br> }<br> }<br> } catch (SQLException e) {<br> System.err.println("executeBatch Exception :" + e.toString());<br> throw e;<br> } finally {<br> CloseConn(isCloseConn);<br> }<br> } else {<br> System.err.println("Connection is null");<br> throw new NullPointerException("Connection is null");<br> }<br> return result;<br> }<br> <br> /**<br> * 批次執行SQL指令使用<br> * @param str_SQL 查詢語法<br> * @param param 以相同數量的參數形成的ArrayList<br> * @param isCloseConn 是否關閉連線<br> * @return 資料庫變動筆數的陣列<br> * @throws SQLException<br> * @throws NullPointerException<br> */<br> public int[] addBatch(String str_SQL, ArrayList<Object[]> param, boolean isCloseConn) throws SQLException,NullPointerException {<br><br> int i = 0;<br> int j = 0;<br> if(isIsdebug()){<br> System.out.println("executeBatch:"+str_SQL);<br> if(param!=null)<br> for (i = 0; i < param.size(); i++) {<br> for (j = 0;j < param.get(i).length; j++) {<br> System.out.println("Parameter "+ i+","+j +":"+param.get(i)[j]);<br> }<br> }<br> }<br> <br> int[] result=null;<br> if (con != null) {<br> try {<br> pst = con.prepareStatement(str_SQL);<br> for (i = 0; i < param.size(); i++) {<br> for (j = 0;j < param.get(i).length; j++) {<br> pst.setObject(j + 1, param.get(i)[j]);<br> }<br> pst.addBatch();<br> }<br> result=pst.executeBatch(); <br> if(isIsdebug()){<br> System.out.println("executeBatch result:");<br> for (i = 0; i < result.length; i++) {<br> System.out.println(i+":"+result[i]);<br> }<br> }<br> } catch (SQLException e) {<br> System.err.println("executeBatch Exception :" + e.toString());<br> throw e;<br> } finally {<br> CloseConn(isCloseConn);<br> }<br> } else {<br> System.err.println("Connection is null");<br> throw new NullPointerException("Connection is null");<br> }<br> <br> return result;<br> }<br> <br> /**<br> * 查詢資料<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @return 每列一筆資料,每筆資料的欄位存於 Object Array中<br> */<br> public ArrayList<Object[]> executeQuery(String str_SQL) throws SQLException,NullPointerException {<br> return executeQuery(str_SQL, null);<br> }<br> /**<br> * 查詢資料<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @param param<br> * 參數設定,SQL語法中以?指定,順序即為?的順序,如 where name=? (此參數可為null)<br> * @return 每列一筆資料,每筆資料的欄位存於 Object Array中<br> */<br> public ArrayList<Object[]> executeQuery(String str_SQL, Object[] param) throws SQLException,NullPointerException {<br> return executeQuery(str_SQL, param, true);<br> }<br><br> /**<br> * 查詢資料<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @param param<br> * 參數設定,SQL語法中以?指定,順序即為?的順序,如 where name=? (此參數可為null)<br> * @param isCloseConn<br> * 是否關閉連線<br> * @return 每列一筆資料,每筆資料的欄位存於 Object Array中<br> */<br> public ArrayList<Object[]> executeQuery(String str_SQL, Object[] param,<br> boolean isCloseConn) throws SQLException,NullPointerException {<br> if(isIsdebug()){<br> System.out.println("executeQuery:"+str_SQL);<br> if(param!=null)<br> for(int i=0;i<param.length;i++)<br> System.out.println("Parameter "+ i +":"+param[i]);<br> System.out.println("isCloseConn :"+isCloseConn);<br> }<br> ArrayList<Object[]> result = new ArrayList<Object[]>();<br> if (con != null) {<br> try {<br> int i = 0;<br> if (param == null) {<br> stat = con.createStatement();<br> rs = stat.executeQuery(str_SQL);<br> } else {<br> pst = con.prepareStatement(str_SQL);<br> for (i = 0; i < param.length; i++) {<br> pst.setObject(i + 1, param[i]);<br> }<br> rs = pst.executeQuery();<br> pst.clearParameters();<br> }<br><br> ArrayList<Object> arr;<br> ResultSetMetaData rsMetaData = rs.getMetaData();<br> int numberOfColumns = rsMetaData.getColumnCount();<br> while (rs.next()) {<br> arr = new ArrayList<Object>();<br> for (i = 1; i < numberOfColumns + 1; i++) {<br> arr.add(rs.getObject(i));<br> }<br> result.add(arr.toArray());<br> }<br> } catch (SQLException e) {<br> System.err.println("executeQuery Exception :" + e.toString());<br> throw e;<br> } finally {<br> CloseConn(isCloseConn);<br> }<br> } else {<br> System.err.println("Connection is null");<br> throw new NullPointerException("Connection is null");<br> }<br> return result;<br> }<br><br> /**<br> * 查詢資料(請記得要關閉Result Set)<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @return 回傳查詢得到的result set<br> */<br> public ResultSet executeQueryResultset(String str_SQL) throws SQLException,NullPointerException {<br> return executeQueryResultset(str_SQL,null);<br> }<br> /**<br> * 查詢資料(請記得要關閉Connection)<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @param param<br> * 參數設定,SQL語法中以?指定,順序即為?的順序,如 where name=? (此參數可為null)<br> * @return 回傳查詢得到的result set<br> */<br> public ResultSet executeQueryResultset(String str_SQL, Object[] param) throws SQLException,NullPointerException {<br> if(isIsdebug()){<br> System.out.println("executeQuery:"+str_SQL);<br> if(param!=null)<br> for(int i=0;i<param.length;i++)<br> System.out.println("Parameter "+ i +":"+param[i]);<br> }<br> <br> ResultSet result = null;<br> if (con != null) {<br> try {<br> int i = 0;<br> if (param == null) {<br> stat = con.createStatement();<br> rs = stat.executeQuery(str_SQL);<br> } else {<br> pst = con.prepareStatement(str_SQL);<br> for (i = 0; i < param.length; i++) {<br> pst.setObject(i + 1, param[i]);<br> }<br> rs = pst.executeQuery();<br> pst.clearParameters();<br> }<br><br> result=rs;<br> } catch (SQLException e) {<br> System.err.println("executeQueryResultset Exception :" + e.toString());<br> throw e;<br> }<br> } else {<br> System.err.println("Connection is null");<br> throw new NullPointerException("Connection is null");<br> }<br> return result;<br> }<br> <br> /**<br> * 查詢資料,並傳回查詢所傳回的結果集第一個資料列的第一個資料行<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @return 每列一筆資料,每筆資料的欄位存於 Object Array中<br> */<br> public Object executescalar(String str_SQL) throws SQLException,NullPointerException {<br> return executescalar(str_SQL, null);<br> }<br> /**<br> * 查詢資料,並傳回查詢所傳回的結果集第一個資料列的第一個資料行<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @param param<br> * 參數設定,SQL語法中以?指定,順序即為?的順序,如 where name=? (此參數可為null)<br> * @return 每列一筆資料,每筆資料的欄位存於 Object Array中<br> */<br> public Object executescalar(String str_SQL, Object[] param) throws SQLException,NullPointerException {<br> return executescalar(str_SQL, param, true);<br> }<br><br> /**<br> * 查詢資料,並傳回查詢所傳回的結果集第一個資料列的第一個資料行<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @param param<br> * 參數設定,SQL語法中以?指定,順序即為?的順序,如 where name=? (此參數可為null)<br> * @param isCloseConn<br> * 是否關閉連線<br> * @return 每列一筆資料,每筆資料的欄位存於 Object Array中<br> */<br> public Object executescalar(String str_SQL, Object[] param,<br> boolean isCloseConn) throws SQLException,NullPointerException {<br> if(isIsdebug()){<br> System.out.println("executeQuery:"+str_SQL);<br> if(param!=null)<br> for(int i=0;i<param.length;i++)<br> System.out.println("Parameter "+ i +":"+param[i]);<br> System.out.println("isCloseConn :"+isCloseConn);<br> }<br> Object result = null;<br> if (con != null) {<br> try {<br> int i = 0;<br> if (param == null) {<br> stat = con.createStatement();<br> rs = stat.executeQuery(str_SQL);<br> } else {<br> pst = con.prepareStatement(str_SQL);<br> for (i = 0; i < param.length; i++) {<br> pst.setObject(i + 1, param[i]);<br> }<br> rs = pst.executeQuery();<br> pst.clearParameters();<br> }<br><br> ResultSetMetaData rsMetaData = rs.getMetaData();<br> int numberOfColumns = rsMetaData.getColumnCount();<br> if (rs.next() && numberOfColumns>=1) {<br> result=rs.getObject(1);<br> }<br> } catch (SQLException e) {<br> System.err.println("executescalar Exception :" + e.toString());<br> throw e;<br> } finally {<br> CloseConn(isCloseConn);<br> }<br> } else {<br> System.err.println("Connection is null");<br> throw new NullPointerException("Connection is null");<br> }<br> return result;<br> }<br><br><br> /**<br> * 執行SQL<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @return 是否成功<br> */<br> public boolean execute(String str_SQL) throws SQLException,NullPointerException {<br> return execute(str_SQL, null);<br> }<br><br> /**<br> * 執行SQL<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @param param<br> * 參數設定,SQL語法中以?指定,順序即為?的順序,如 where name=? (此參數可為null)<br> * @return 是否成功<br> */<br> public boolean execute(String str_SQL, Object[] param) throws SQLException,NullPointerException {<br> return execute(str_SQL, param, true);<br> }<br><br> /**<br> * 執行SQL<br> * <br> * @param str_SQL<br> * 查詢語法<br> * @param param<br> * 參數設定,SQL語法中以?指定,順序即為?的順序,如 where name=? (此參數可為null)<br> * @param isCloseConn<br> * 是否關閉連線<br> * @return 是否成功<br> */<br> public boolean execute(String str_SQL, Object[] param, boolean isCloseConn) throws SQLException,NullPointerException {<br> if(isIsdebug()){<br> System.out.println("executeQuery:"+str_SQL);<br> if(param!=null)<br> for(int i=0;i<param.length;i++)<br> System.out.println("Parameter "+ i +":"+param[i]);<br> System.out.println("isCloseConn :"+isCloseConn);<br> }<br> boolean result = false;<br> if (con != null) {<br> try {<br> int i = 0;<br> if (param == null) {<br> stat = con.createStatement();<br> result = stat.execute(str_SQL);<br> } else {<br> pst = con.prepareStatement(str_SQL);<br> for (i = 0; i < param.length; i++) {<br> pst.setObject(i + 1, param[i]);<br> }<br> result = pst.execute();<br> pst.clearParameters();<br> }<br> } catch (SQLException e) {<br> System.err.println("execute Exception :" + e.toString());<br> throw e;<br> } finally {<br> CloseConn(isCloseConn);<br> }<br> } else {<br> System.err.println("Connection is null");<br> throw new NullPointerException("Connection is null");<br> }<br> return result;<br> }<br>/**<br> * 關閉連線<br> */<br> public void CloseConn() {<br> CloseConn(true);<br> }<br><br> /**<br> * 關閉連線<br> * @param isCloseConn 是否關閉Connection<br> */<br> public void CloseConn(boolean isCloseConn) {<br> if(isIsdebug()){<br> System.out.println("CloseConn:"+isCloseConn);<br> }<br> try {<br> if (rs != null) {<br> rs.close();<br> rs = null;<br> }<br> if (stat != null) {<br> stat.close();<br> stat = null;<br> }<br> if (pst != null) {<br> pst.close();<br> pst = null;<br> }<br> } catch (SQLException e) {<br> //System.err.println("Close Exception :" + e.toString());<br> } finally {<br> try {<br> if (con != null && isCloseConn) {<br> con.close();<br> isClosed=true;<br> }<br> } catch (SQLException e) {<br> //System.err.println("Close Exception :" + e.toString());<br> }<br> }<br> }<br> <br> <br> int allpage=0;<br> <br> public int getAllpage() {<br> return allpage;<br> }<br> public void setAllpage(int allpage) {<br> this.allpage = allpage;<br> }<br> /**<br> * 查詢分頁資料<br> * @param colunms<br> * @param from<br> * @param where<br> * @param group<br> * @param order<br> * @param fpage<br> * @param pages<br> * @return<br> * @throws SQLException<br> * @throws NullPointerException<br> */<br> public ArrayList<Object[]> selectPage(String colunms,String from,String where,String group,String having,String order,int fpage,int pages) throws SQLException,NullPointerException{<br> return selectPage(colunms,from,where,group,having,order,fpage,pages,null);<br> }<br> /**<br> * 查詢分頁資料<br> * @param colunms<br> * @param from<br> * @param where<br> * @param group<br> * @param order<br> * @param fpage<br> * @param pages<br> * @param param<br> * @return<br> * @throws SQLException<br> * @throws NullPointerException<br> */<br> public ArrayList<Object[]> selectPage(String colunms,String from,String where,String group,String having,String order,int fpage,int pages, Object[] param) throws SQLException,NullPointerException{<br> return selectPage(colunms,from,where,group,having,order,fpage,pages,param,true);<br> }<br>/**<br> * 查詢分頁資料<br> * @param colunms<br> * @param from<br> * @param where<br> * @param group<br> * @param order<br> * @param fpage<br> * @param pages<br> * @param param<br> * @param isCloseConn<br> * @return<br> * @throws SQLException<br> * @throws NullPointerException<br> */<br> public ArrayList<Object[]> selectPage(String colunms,String from,String where,String group,String having,String order,int fpage,int pages, Object[] param, boolean isCloseConn) throws SQLException,NullPointerException{<br> return selectPage(colunms, from, where, group, having, order, fpage, pages, true, 0, param, isCloseConn);<br> }<br> /**<br> * 查詢分頁資料<br> * @param colunms<br> * @param from<br> * @param where<br> * @param group<br> * @param having<br> * @param order<br> * @param fpage<br> * @param pages<br> * @param isCountPage<br> * @param allpageCount<br> * @param param<br> * @param isCloseConn<br> * @return<br> * @throws SQLException<br> * @throws NullPointerException<br> */<br> public ArrayList<Object[]> selectPage(String colunms,String from,String where,String group,String having,String order,int fpage,int pages,boolean isCountPage,int allpageCount, Object[] param, boolean isCloseConn) throws SQLException,NullPointerException{<br> ArrayList<Object[]> result=null;<br> try{<br> String sql;<br> if(!isCountPage){<br> allpage=allpageCount;<br> }else{<br> int intRowCount;<br> sql="select count(*) from (select ";<br> if(colunms!=null){<br> sql+="" + colunms + " \n ";<br> }else{<br> sql+="* \n "; <br> }<br> sql+="from " + from.toString() + " \n ";<br> if(where!=null){<br> sql+="where " + where + " \n ";<br> }<br> if(group!=null){<br> sql+="group by " + group + " \n ";<br> }<br> if(having!=null){<br> sql+="having " + group + " \n ";<br> }<br> sql+=") selectcount \n ";<br> <br> Object temp=executescalar(sql,param,false);<br> if(temp==null){<br> return result;<br> }<br> intRowCount=Integer.parseInt(temp.toString());<br> allpage=(intRowCount+fpage-1) / fpage;<br> }<br> int spage;<br> <br> if(pages > allpage ){// pages == 0){<br> pages = 1;<br> } <br> spage=(pages-1)*fpage; <br> //sql="select " + colunms + " \n from " + from + " \n where " + where + " \n order by " + order + " \n limit "+ spage +","+fpage ;<br> sql="select ";<br> if(colunms!=null){<br> sql+= colunms + " \n ";<br> }else{<br> sql+="* \n "; <br> }<br> sql+="from " + from + " \n ";<br> if(where!=null){<br> sql+="where " + where + " \n ";<br> }<br> if(group!=null){<br> sql+="group by " + group + " \n ";<br> }<br> if(having!=null){<br> sql+="having " + group + " \n ";<br> }<br> if(order!=null){<br> sql+="order by " + order + " \n ";<br> }<br> sql+="limit "+ spage +","+fpage;<br> result=executeQuery(sql, param, false);<br> } catch (NullPointerException e) {<br> System.err.println("NullPointerException Exception :" + e.toString());<br> throw e;<br> } catch (SQLException e) {<br> System.err.println("SQLException Exception :" + e.toString());<br> throw e;<br> } finally {<br> CloseConn(isCloseConn);<br> }<br> return result;<br> }<br> <br>}<br><br></code></pre>
<h4>使用範例程式</h4>
<pre><code>package common.test;<br><br>import static org.junit.Assert.*;<br><br>import java.sql.ResultSet;<br>import java.sql.ResultSetMetaData;<br>import java.util.ArrayList;<br><br>import org.junit.After;<br>import org.junit.Before;<br>import org.junit.Test;<br><br>import common.DBBaseIO;<br><br>public class DBBaseIOTest {<br><br> DBBaseIO dbio;<br> int m_id;<br> <br> String m_name;<br> @Before<br> public void setUp() throws Exception {<br> dbio=new DBBaseIO(0);<br> m_id=20100111;<br> m_name="tester" + m_id;<br> }<br><br> @After<br> public void tearDown() throws Exception {<br> dbio.CloseConn();<br> dbio=null;<br> }<br><br> @Test<br> public void testExecuteString() {<br> String msg="\n# testExecuteString\n Drop and Create :\t TestTable" + m_id;<br> System.out.println(msg);//DROP TABLE IF EXISTS TestTable" + m_id + "; <br> String str_Sql = "CREATE TABLE TestTable" + m_id + " ( " + <br> "`test_id` int(10) unsigned NOT NULL auto_increment, " +<br> "`member_id` int(10) unsigned NOT NULL, "+<br> "`member_name` varchar(45) NOT NULL, " +<br> "PRIMARY KEY (`test_id`) "+<br> ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; ";<br> try{<br> dbio.execute(str_Sql);<br> <br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> }<br> }<br> <br> @Test<br> public void testExecuteUpdateString() {<br> String msg="\n# testExecuteUpdateString\n Insert :\tID=" + m_id + "\tName=" + m_name;<br> System.out.println(msg);<br> String str_Sql="Insert into TestTable" + m_id + " (member_id,member_name) values('" + m_id + "','" + m_name + "')";<br> try{<br> int result=dbio.executeUpdate(str_Sql);<br> if(result<=0){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + result);<br> }<br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> } <br> }<br><br> @Test<br> public void testExecuteQueryString() {<br> String msg="\n# testExecuteQueryString\n Select ALL :";<br> System.out.println(msg);<br> String str_Sql="Select * from TestTable" + m_id + "";<br> try{<br> ArrayList<Object[]> result=dbio.executeQuery(str_Sql);<br> if(result.size()<=0){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + result);<br> }else{<br> for(int i=0;i<result.size();i++){<br> for(int j=0;j<result.get(i).length;j++){<br> System.out.print(result.get(i)[j] + "\t");<br> }<br> System.out.println();<br> }<br> }<br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> }<br> }<br><br> @Test<br> public void testexecuteQueryResultset() {<br> String msg="\n# testexecuteQueryResultset\n Select ALL :";<br> System.out.println(msg);<br> String str_Sql="Select * from TestTable" + m_id + "";<br> try{<br> <br> ResultSet rs=dbio.executeQueryResultset(str_Sql);<br> ResultSetMetaData rsMetaData = rs.getMetaData();<br> int numberOfColumns = rsMetaData.getColumnCount();<br> while (rs.next()) {<br> for (int i = 1; i < numberOfColumns + 1; i++) {<br> System.out.print(rs.getObject(i) + "\t");<br> }<br> System.out.println();<br> }<br> <br> dbio.CloseConn();<br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> }<br> }<br> <br> @Test<br> public void testselectPage() {<br> String msg="\n# testselectPage\n Insert 98 User";<br> System.out.println(msg);<br> String str_Sql="";<br> try{<br> <br> for(int i=1;i<=98;i++){<br> str_Sql="Insert into TestTable" + m_id + " (member_id,member_name) values('" + m_id + i + "','" + m_name + "_" + i + "')";<br> int result=dbio.executeUpdate(str_Sql,null,false);<br> if(result<=0){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + result);<br> }<br> }<br> str_Sql="";<br> ArrayList<Object[]> result=dbio.selectPage("member_id,member_name", "TestTable" + m_id, null, "member_id", 10, 10, null, true);<br> if(result.size()<=0){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + result);<br> }else{<br> for(int i=0;i<result.size();i++){<br> for(int j=0;j<result.get(i).length;j++){<br> System.out.print(result.get(i)[j] + "\t");<br> }<br> System.out.println();<br> }<br> }<br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> }<br> <br> <br> }<br> <br><br> @Test<br> public void testExecuteUpdateStringObjectArray() {<br> m_name+="_Updateed";<br> String msg="\n# testExecuteUpdateStringObjectArray\n Update :\tID=" + m_id + "\tName=" + m_name;<br> System.out.println(msg);<br> String str_Sql="Update TestTable" + m_id + " Set member_name=? WHERE member_id=?";<br> Object[] param={m_name,m_id};<br> try{<br> int result=dbio.executeUpdate(str_Sql,param);<br> if(result<=0){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + result);<br> }<br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> } <br> }<br><br> @Test<br> public void testExecuteQueryStringObjectArray() {<br> String msg="\n# testExecuteQueryStringObjectArray\n Select :\tID=" + m_id;<br> System.out.println(msg);<br> String str_Sql="Select * from TestTable" + m_id + " where member_id=?";<br> Object[] param={m_id}; <br> try{<br> ArrayList<Object[]> result=dbio.executeQuery(str_Sql,param);<br> if(result.size()<=0){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + result);<br> }else{<br> for(int i=0;i<result.size();i++){<br> for(int j=0;j<result.get(i).length;j++){<br> System.out.print(result.get(i)[j] + "\t");<br> }<br> System.out.println();<br> }<br> }<br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> }<br> }<br><br> @Test<br> public void testExecuteUpdateStringObjectArrayBoolean() {<br> String msg="\n# testExecuteUpdateStringObjectArrayBoolean\n Delete :\tID=" + m_id + "\tName=" + m_name;<br> System.out.println(msg);<br> String str_Sql="Delete from TestTable" + m_id + " WHERE member_id=?";<br> Object[] param={m_id};<br> try{<br> int result=dbio.executeUpdate(str_Sql,param,false);<br> if(result<=0){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + result);<br> }<br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> }finally{<br> dbio.CloseConn();<br> }<br> }<br><br> @Test<br> public void testExecuteQueryStringObjectArrayBoolean() {<br> String msg="\n# testExecuteQueryStringObjectArrayBoolean\n Select :\tID=" + m_id;<br> System.out.println(msg);<br> String str_Sql="Select * from TestTable" + m_id + " where member_id=?";<br> Object[] param={m_id};<br> try{<br> ArrayList<Object[]> result=dbio.executeQuery(str_Sql,param,false);<br> if(result.size()>0){<br> for(int i=0;i<result.size();i++){<br> for(int j=0;j<result.get(i).length;j++){<br> System.out.print(result.get(i)[j] + "\t");<br> }<br> System.out.println();<br> }<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + result);<br> }<br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> }finally{<br> dbio.CloseConn();<br> }<br> }<br><br><br><br> <br><br> @Test<br> public void testExecuteStringObjectArrayBoolean() {<br> String msg="\n# testExecuteStringObjectArrayBoolean\n Drop :\t TestTable_" + m_id;<br> System.out.println(msg);<br> String str_Sql="DROP TABLE IF EXISTS TestTable" + m_id + ";" ;<br> <br> try{<br> dbio.execute(str_Sql,null,false);<br> <br> }catch(Exception e){<br> fail(msg + "\n\n" + str_Sql + "\n\nResult:" + e.getMessage());<br> }finally{<br> dbio.CloseConn();<br> }<br> }<br><br> <br><br>}<br><br></code></pre>
<h4>總結</h4>
<div>我在開發時採用ArrayList把資料給回傳回來,因此相反的就沒有辦法回傳欄位名稱(不過我想你在寫SQL時應該已經可以指定自己要用的欄位名稱了吧)。<br>
<h4>相關文章</h4>
<ul><li><a href="http://allen080.blogspot.com/2009/04/vbnet20.html">[程式]VB.Net2.0資料庫通用存取函式</a><br>
</li></ul>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-74891013993187556162010-01-25T01:06:00.000-08:002010-01-25T01:32:18.233-08:00[JAAS] JBoss下動態網站使用資料庫設定認證授權<h4>序言</h4>
雖說我以前一直很不想再Try Java Tool弄很久~因為開發速度還是微軟順手些,但看來我還是逃脫不了。<br>
總之~這篇是最近我實作時的紀錄,主要是要用Java預設的安全機制,完成網站的認證授權(也就是登入登出、 Login and Logout)。<br>
通常書到用時方恨少,這句話這時就應驗了,腦中有的資訊太少,所以這個東西花了我不少功夫。<br>
如果有任何不標準的用法,請見諒,很多都是我從網路找來的資訊組合而成的,我很懶得去查官方的英文文件(官方文件有很多其實也沒寫的很詳細...)。<br>
歡迎有更標準的用法的話,請留下文章、連結等資料指正我。<br>
<h4 style="margin: 5px 0px; color: rgb(51, 51, 51);">開發環境</h4>
<ul><li>Java Runtime: <a href="http://www.google.com/url?q=http%3A%2F%2Fjava.sun.com%2Fjavase%2Fdownloads%2Fwidget%2Fjdk6.jsp&sa=D&sntz=1&usg=AFrqEzdPJz81hrgmUHXlApvWSf8oHWWb_g" target="_blank">JDK 6 update 17</a><br>
</li>
<li>Java IDE: <a href="http://www.google.com/url?q=http%3A%2F%2Fwww.eclipse.org%2Fdownloads%2Fdownload.php%3Ffile%3D%2Ftechnology%2Fepp%2Fdownloads%2Frelease%2Fgalileo%2FSR1%2Feclipse-jee-galileo-SR1-win32.zip&sa=D&sntz=1&usg=AFrqEzcCcRl_IZKN_G9yVdJ8Oa-6mC9XFg" target="_blank">Eclipse Java EE IDE for Web Developers</a></li>
<li>Application Server: <a href="http://www.google.com/url?q=http%3A%2F%2Fwww.jboss.org%2Fjbossas%2Fdownloads%2F&sa=D&sntz=1&usg=AFrqEzf7hKBBjNkjAP4URHVDInE_TsZeRA">JBoss 5.1.0 GA</a></li>
<li>Database: <a href="http://www.google.com/url?q=http%3A%2F%2Fdev.mysql.com%2Fdownloads%2Fmysql%2F&sa=D&sntz=1&usg=AFrqEzdRexOVkE1Z8iskCNtDpzXUAXMRDw">MySQL 5.1.42 win32</a></li>
<li>DB Cconnector: <a href="http://www.google.com/url?q=http%3A%2F%2Fdev.mysql.com%2Fdownloads%2Fconnector%2Fj%2F&sa=D&sntz=1&usg=AFrqEzci1lVcvbqZniA5UIao4qK2lkHvXQ" target="_blank">mysql-connector-java-5.1.10</a><br>
</li></ul>
<div>
<h4 style="margin: 5px 0px; color: rgb(51, 51, 51);">JBoss設定</h4>
<div>
<ol><li>資料庫連接器:將資料庫連接器【mysql-connector-java-5.1.10-bin.jar】放在Jboss的伺服器函式庫資料夾,如【jboss\server\default\lib】</li>
<li>資料庫連線設定:連線設定檔是用xml定義的,可直接複製JBoss提供的範本(位於【jboss\docs\examples\jca\mysql-ds.xml】)到【jboss\server\default\deploy】,並將資料庫設為你的MySQL連線設定。(如果用其他資料庫的話,在範本資料夾裡大都有範例)<br>
這邊比較需要注意的是等下要用到的名稱<br>
<ul><li>jndi-name:等下設定驗證方式時會用到的名稱,例如下面範例的【MySqlDS】</li></ul>
<pre><code><?xml version="1.0" encoding="UTF-8"?><br><br><!-- See http://www.jboss.org/community/wiki/Multiple1PC for information about local-tx-datasource --><br><!-- $Id: mysql-ds.xml 88948 2009-05-15 14:09:08Z jesper.pedersen $ --><br><!-- Datasource config for MySQL using 3.0.9 available from:<br>http://www.mysql.com/downloads/api-jdbc-stable.html<br>--><br><br><datasources><br> <local-tx-datasource><br> <jndi-name>MySqlDS</jndi-name><br> <connection-url>jdbc:mysql://mysql-hostname:3306/jbossdb</connection-url><br> <driver-class>com.mysql.jdbc.Driver</driver-class><br> <user-name>x</user-name><br> <password>y</password><br> <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter</exception-sorter-class-name><br> <!-- should only be used on drivers after 3.22.1 with "ping" support<br> <valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.MySQLValidConnectionChecker</valid-connection-checker-class-name><br> --><br> <!-- sql to call when connection is created<br> <new-connection-sql>some arbitrary sql</new-connection-sql><br> --><br> <!-- sql to call on an existing pooled connection when it is obtained from pool - MySQLValidConnectionChecker is preferred for newer drivers<br> <check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql><br> --><br><br> <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) --><br> <metadata><br> <type-mapping>mySQL</type-mapping><br> </metadata><br> </local-tx-datasource><br></datasources><br><br></code></pre>
<br>
另外,如果覺得連線密碼這樣寫明碼太危險,可參考<a href="http://www.google.com/url?q=http%3A%2F%2Fcommunity.jboss.org%2Fwiki%2Fencryptingdatasourcepasswords&sa=D&sntz=1&usg=AFrqEze4ZlOPgvBUsWhvMqw_ntUyAKfaUg" target="_blank">JBoss community的文件</a>加密儲存
</li>
<li>驗證方式設定:在JBoss的設定目錄下【jboss\server\default\conf】,有個【login-config.xml】,這個就是設定帳號驗證的方式(如果沒有這個檔也可以自己新增)<br>
裡面的參數<br>
<ul><li>UserAA: 我設定的驗證來源名稱,這個在專案中會做對應的設定。</li>
<li>dsJndiName: 這邊就會對應到上一個設定的資料庫來源名稱MySqlDS</li>
<li>principalsQuery:這邊要寫查詢帳號密碼的SQL</li>
<li>rolesQuery:這邊要寫使用者角色的查詢SQL,角色會關係到後面網站權限的設定,第一個資料【roleName】所查詢出來的值我們這邊假設可能會有admin與guest,第二個資料是群組,我目前也不清楚是做什麼的,先依據官方範例給固定文字<br>
</li></ul>
<pre><code><?xml version='1.0'?><br><policy><br> <application-policy name="UserAA"> <br> <authentication> <br> <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag = "required"> <br> <module-option name = "dsJndiName">java:/MySqlDS</module-option> <br> <module-option name = "principalsQuery">SELECT passwd FROM userdb.usersTab where userID=?</module-option> <br> <module-option name = "rolesQuery">SELECT roleName,'Roles' FROM userdb.userRolesTab where userID=?</module-option> <br> </login-module> <br> </authentication> <br></application-policy><br></policy></code></pre>
</li>
</ol>
</div>
<div>
<h4>MySQL</h4>
</div>
<div>
以下使用SQL script建立所需的資料庫與資料表,我將同時產生兩個預設的帳號分別屬於不同的權限角色,以下比較需要注意的部份是<br>
<ul><li>主要用到的資料來源是UsersTab資料表中的兩個欄位userID、passwd,還有UserRolesTab的兩個欄位userID、roleName,這部份不知道是不是有型態限制或是長度限制的問題,我用別的規格下去可能就無法認證。</li>
<li>往下的Trigger是可有可無的,是我建立還方便管理資料庫用的</li>
<li>最下面的insert是預設帳號與角色資料的建立</li>
<ul><li>boss/0000:角色為admin</li>
<li>test/0000:角色為guest<br>
</li></ul></ul>
</div>
<pre><code>CREATE DATABASE IF NOT EXISTS `userdb` /*!40100 DEFAULT CHARACTER SET utf8 */;<br><br><br>DROP TABLE IF EXISTS `userdb`.`UsersTab`;<br>CREATE TABLE `userdb`.`UsersTab` (<br> `userID` varchar(64) NOT NULL,<br> `passwd` varchar(64) NOT NULL,<br> `createtime` datetime DEFAULT NULL,<br> `updatetime` datetime DEFAULT NULL,<br> PRIMARY KEY (`userID`)<br>) ENGINE=MyISAM DEFAULT CHARSET=utf8;<br><br><br>DROP TABLE IF EXISTS `userdb`.`UserRolesTab`;<br>CREATE TABLE `userdb`.`UserRolesTab` (<br> `userID` varchar(64) NOT NULL,<br> `roleName` varchar(32) NOT NULL DEFAULT 'guest',<br> `createtime` datetime DEFAULT NULL,<br> PRIMARY KEY (`userID`,`roleName`)<br>) ENGINE=MyISAM DEFAULT CHARSET=utf8;<br><br><br>DELIMITER $$<br>drop TRIGGER IF EXISTS `userdb`.UsersTab_Insert$$<br>CREATE TRIGGER `userdb`.UsersTab_Insert BEFORE INSERT ON `userdb`.UsersTab FOR EACH ROW<br>BEGIN<br> if new.createtime is null then<br> Set new.createtime = now();<br> end if;<br> if new.updatetime is null then<br> Set new.updatetime = now();<br> end if;<br>END$$<br><br>drop TRIGGER IF EXISTS `userdb`.UsersTab_Update$$<br>CREATE TRIGGER `userdb`.UsersTab_Update BEFORE UPDATE ON `userdb`.UsersTab FOR EACH ROW<br>BEGIN<br> if new.updatetime is null or old.updatetime=new.updatetime then<br> Set new.updatetime = now();<br> end if;<br>END$$<br><br>drop TRIGGER IF EXISTS `userdb`.UsersTab_Delete$$<br>CREATE TRIGGER `userdb`.UsersTab_Delete AFTER DELETE ON `userdb`.UsersTab FOR EACH ROW<br>BEGIN<br> delete from `userdb`.UserRolesTab where userID=old.userID;<br>END$$<br><br>drop TRIGGER IF EXISTS `userdb`.UserRolesTab_Insert$$<br>CREATE TRIGGER `userdb`.UserRolesTab_Insert BEFORE INSERT ON `userdb`.UserRolesTab FOR EACH ROW<br>BEGIN<br> if new.createtime is null then<br> Set new.createtime = now();<br> end if;<br>END$$<br>DELIMITER ;<br><br>insert into userdb.UsersTab (userID,passwd) values('boss','0000');<br>insert into userdb.UserRolesTab (userID,roleName) values('boss','admin');<br><br>insert into userdb.UsersTab (userID,passwd) values('test','0000');<br>insert into userdb.UserRolesTab (userID,roleName) values('test','guest');</code></pre>
<h4>Dynmic Web Project</h4>
<div>動態網站的設定主要是在【WEB-INF】資料夾中新增一個【jboss-web.xml】,內容如下</div>
<pre><code><?xml version="1.0" encoding="UTF-8"?><br><!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.3V2//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_3_2.dtd"><br><br><jboss-web><br> <security-domain>java:/jaas/UserAA</security-domain> <br></jboss-web> </code></pre>
<div>然後修改【web.xml】。這邊我採用Form認證的方式,也就是用網頁提供Login的介面。<br>
<ul><li>security-constraint:這一段是設定哪些路徑可由哪些Role來存取,也就是權限設定。這部份有用到的角色一定要在下面的【security-role】有定義到。另外如果想設定成只有有登入的人才能存取,可將【role-name】設定成【*】。</li>
<li>login-config:這一段就是定義Login的方式與參照頁面(另依種方式設定為BASIC)<br>
</li></ul>
</div>
<pre><code><?xml version="1.0" encoding="UTF-8"?><br><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"><br> ...<br> <security-constraint><br> <web-resource-collection><br> <web-resource-name></web-resource-name><br> <url-pattern>/test/*</url-pattern><br> </web-resource-collection><br> <auth-constraint><br> <role-name>admin</role-name><br> </auth-constraint><br> </security-constraint><br> <security-constraint><br> <web-resource-collection><br> <web-resource-name></web-resource-name><br> <url-pattern>/Login</url-pattern><br> <url-pattern>/Logout</url-pattern><br> </web-resource-collection><br> <auth-constraint><br> <role-name>*</role-name><br> </auth-constraint><br> </security-constraint><br> <login-config><br> <auth-method>FORM</auth-method><br> <realm-name></realm-name><br> <form-login-config><br> <form-login-page>/login.jsp</form-login-page><br> <form-error-page>/login.jsp?msg=Incorrect</form-error-page><br> </form-login-config><br> </login-config><br> <security-role><br> <role-name>admin</role-name><br> </security-role><br> <security-role><br> <role-name>guest</role-name><br> </security-role><br> ...<br></web-app></code></pre>
<h4>JSP & Servlet</h4>
<div>再來我針對登入部份的網頁進行開發,主要會建立JSP:login.jsp與Servlet:Login、Logout。<br>
實際上真正的登入網頁會是login.jsp,但因為如果使用者直接輸入login.jsp的網址後,進行登入成功後系統會不知該導到哪一頁(似乎也沒辦法設定預設導頁,網路上是有<a href="http://roneiv.wordpress.com/2008/02/18/jaas-authentication-mechanism-is-it-possible-to-force-j_security_check-to-go-to-a-specific-page/" target="_blank">另一種作法</a>如果有需要可自行參考)。<br>
我這邊是自己想了個比較簡單的邏輯性解法,就是做一個Login的Servlet裡面直接會跳到首頁作為預設網頁,<br>
然後將這個Login servlet設定必須登入才能存取(也就是上一步的web.xml中設定的),讓登入的連結以這個Servlet為主就會自動導自login.jsp。</div>
<div>login.jsp:</div>
<pre><code><%@ page language="java" contentType="text/html; charset=UTF-8"<br> pageEncoding="UTF-8"%><br><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><br><html><br><head><br><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><br><title>Login</title><br></head><br><body><br><br> <h2 align="center">Login</h2> <br> <table border="0" align="center"><br> <tr><br> <td><br> <form method="POST" action="j_security_check"><br> <div>User ID :<br> <input type="text"<br> name="j_username"><br> </div><br> <div>Password :<br> <input type="password"<br> name="j_password"><br> </div><br> <div><input type="submit" value="Log In"></div><br> <br> <div style="color: red;"><%=(request.getParameter("msg")!=null)?request.getParameter("msg"):"" %></div><br> <br> </form><br> </td><br> </tr><br> </table><br><br></body><br></html></code></pre>
<div>Login servlet</div>
<pre><code>package view;<br><br>import java.io.IOException;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br><br>/**<br> * Servlet implementation class Login<br> */<br>public class Login extends HttpServlet {<br> private static final long serialVersionUID = 1L;<br> <br> /**<br> * @see HttpServlet#HttpServlet()<br> */<br> public Login() {<br> super();<br> // TODO Auto-generated constructor stub<br> }<br><br> /**<br> * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)<br> */<br> protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br> response.sendRedirect(request.getContextPath() + "/index.jsp");<br> }<br>}<br><br></code></pre>
<div>Logout servlet</div>
<pre><code>package view;<br><br>import java.io.IOException;<br><br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br><br><br>public class Logout extends HttpServlet {<br> private static final long serialVersionUID = 1L;<br> <br> /**<br> * @see HttpServlet#HttpServlet()<br> */<br> public Logout() {<br> super();<br> }<br><br> protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {<br> request.getSession().invalidate();<br> response.sendRedirect(request.getContextPath() + "/");<br> }<br>}</code></pre>
<h4>總結</h4>
以上設定完成後,就可以進到你的應用程式,然後存取Login servlet看看能不能正常登入登出了。<br>
在這邊補充一些資訊,如果要在程式中取得登入者後的帳號,可以用【request.getUserPrincipal()】來取得Principal物件,如果不是null就可以呼叫該物件的getName()方法。<br>
不過我個人比較喜歡用另外一個物件【org.jboss.security.SecurityAssociation】中的【getPrincipal()】也可以。<br>
如果是要判斷使用者的角色,可使用【request.isUserInRole("admin")】方法來知道該使用者是否屬於admin這個角色。<br>
<h4>參考資料</h4>
<div>
<ul><li><a href="http://www.oracle.com/technology/products/jdev/howtos/10g/jaassec/index.htm" target="_blank">Declarative J2EE authentication and authorization with JAAS</a></li></ul>
</div>
</div>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-13699538476459625412009-10-31T19:44:00.000-07:002009-11-17T18:56:42.415-08:00[分享]PHP版網頁原始碼處理函式<h4>序言</h4>
這是我依<a href="http://allen080.blogspot.com/2009/05/vbnet20.html">VB.Net的網頁原始碼處理函式</a>翻過來的PHP版程式,可以取得網頁後,再針對特定標簽進行切割處理。
<div>
<h4 style="margin: 5px 0px; color: rgb(51, 51, 51);">函式原始碼</h4>
<div>我將以下原始碼存在【myClass】目錄的【HTMLParser.php】檔
</div>
<pre><code><?php<br> Class HTMLParser{<br> function getHTML($url,$method="GET",$param=NULL,$noCashe=False){<br> //$param = array("name" => 'tim',"content" => 'test');<br> <br> if($noCashe){<br> $cashe="Cache-Control: no-cache\r\n";<br> }else{<br> $cashe="";<br> }<br> if($method=="GET" and $param!=NULL){<br> $data="";<br> foreach ($param as $k => $v) {<br> if($data!="") $data.="&";<br> $data.= "$k=".htmlentities($v);<br> }<br> $url.="?".$data;<br> }<br> <br> if($method=="POST" and $param!=NULL){<br> $data = http_build_query($param); <br> $contentLength="Content-length:".strlen($data)."\r\n";<br> $opts = array(<br> 'http'=>array(<br> 'method'=>$method,<br> 'header'=>"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)\r\n"<br> . "Accept-language: zh-tw\r\n"<br> . "Content-Typ: application/x-www-form-urlencoded\r\n"<br> . $cashe . $contentLength, <br> 'content' => $data<br> )<br> );<br> }else{<br> $opts = array(<br> 'http'=>array(<br> 'method'=>$method,<br> 'header'=>"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)\r\n"<br> . "Accept-language: zh-tw\r\n"<br> . "Content-Typ: application/x-www-form-urlencoded\r\n"<br> . $cashe<br> )<br> );<br><br> } <br> $context = stream_context_create($opts);<br> // Open the file using the HTTP headers set above<br> return file_get_contents($url, false, $context);<br> //return file_get_contents($url);<br> }<br> //取得網頁的Body區段<br> function getHTMLBody($url,$postValue=NULL,$noCashe= False){<br> $html=NULL;<br> $htmlBody=NULL;<br> if($postValue!=NULL){<br> $html = $this->getHTML($url,"POST",$postValue,$noCashe);<br> }else{<br> $html = $this->getHTML($url,"GET", $postValue,$noCashe);<br> }<br> If(html!=NULL) $this->getHTMLTagContain($html, "body", $htmlBody);<br> <br> return $htmlBody;<br> }<br> //取得HTML中第一個符合的標籤內容的指標,並將取得的標籤內容寫入參數中<br> function getHTMLTagContain($html,$tag,&$contain=NULL,&$indexEnd= -1){<br> $tag = strtolower($tag);<br> $contain = NULL; <br> $indexBegin= -1;<br> $indexEnd = -1;<br> $indexbBegin= -1;<br> If($html !=NULL){ <br> $indexBegin = strpos(strtolower($html),"<" . $tag);<br> if (gettype($indexBegin)!="integer") $indexBegin=-1;<br> If($indexBegin > -1){<br> $indexbBegin = strpos($html,">",$indexBegin);<br> if (gettype($indexbBegin)!="integer"){<br> $indexbBegin=-1;<br> }else{<br> $indexbBegin+=1;<br> }<br> $findTag=False;<br> $indexEnd=$indexbBegin;<br> $lastStart=$indexbBegin;<br> $stopLimit2 = 9999;<br> do{<br> $indexEnd=strpos(strtolower($html),"</" . $tag,$indexEnd);<br> if(gettype($indexEnd)!="integer") $indexEnd=-1;<br> If ($indexEnd > -1){<br> if(gettype(strpos(substr($html,$lastStart, $indexEnd - $lastStart),"<" . $tag))=="integer"){<br> $lastStart=$indexEnd;<br> $indexEnd=$indexEnd+strlen("</" . $tag); <br> $findTag=True;<br> }else{<br> $findTag=False;<br> }<br> }else{<br> $findTag=False;<br> }<br> $stopLimit2--;<br> }while($findTag AND $stopLimit2>0);<br> If ($indexEnd > -1){<br> $contain = substr($html,$indexbBegin, $indexEnd - $indexbBegin);<br> <br> $indexEnd= strpos($html,">",$indexEnd);<br> if(gettype($indexEnd)!="integer"){<br> $indexEnd=-1;<br> }else{<br> $indexEnd+=1;<br> }<br> }<br> }<br> }<br> //echo $contain;<br> Return $indexbBegin;<br> }<br> //取得HTML中第一個符合的標籤屬性的指標,並將取得的標籤內容與該屬性內容寫入參數中<br> function getHTMLTagAtt($html,$tag,$attName,&$att=NULL,&$contain=NULL,&$indexEnd= -1){<br> $tag = strtolower($tag);<br> $attName = strtolower($attName);<br> $contain = NULL;<br> $att = NULL;<br> $indexEnd = -1; <br> $indexBegin= -1;<br> $indexaBegin= -1; <br> $indexbEnd = -1;<br> If($html !=NULL){<br> $indexBegin = 0;<br> $stopLimit1 = 9999;<br> do{<br> $indexbEnd = -1;<br> $indexBegin = strpos(strtolower($html),"<" . $tag,$indexBegin);<br> if (gettype($indexBegin)!="integer") $indexBegin=-1;<br> If($indexBegin > -1){<br> $indexbEnd= strpos($html,">",$indexBegin);<br> if (gettype($indexbEnd)!="integer") $indexbEnd=-1;<br> If($indexbEnd > -1){<br> $indexaBegin = strpos(strtolower(str_replace("\"", "'",substr($html,0, $indexbEnd))),$attName . "='",$indexBegin);<br> if(gettype($indexaBegin)!="integer") $indexaBegin=-1;<br> If($indexaBegin > -1){<br> $sign = substr($html,$indexaBegin + strlen($attName . "="), 1);<br> $indexaBegin+=strlen($attName . "='");<br> $indexaEnd= strpos(substr($html,0, $indexbEnd),$sign,$indexaBegin);<br> if(gettype($indexaEnd)!="integer") $indexaEnd=-1;<br> If($indexaEnd > -1){<br> $att = substr($html,$indexaBegin, $indexaEnd - $indexaBegin);<br> }<br> }else{<br> $indexBegin = $indexbEnd + 1;<br> continue;<br> }<br> $indexbEnd+=1;<br> }<br> <br> $findTag=False;<br> $indexEnd=$indexbEnd;<br> $lastStart=$indexbEnd;<br> $stopLimit2 = 9999;<br> do{<br> $indexEnd=strpos(strtolower($html),"</" . $tag,$indexEnd);<br> if(gettype($indexEnd)!="integer") $indexEnd=-1;<br> If ($indexEnd > -1){<br> if(gettype(strpos(substr($html,$lastStart, $indexEnd - $lastStart),"<" . $tag))=="integer"){<br> $lastStart=$indexEnd;<br> $indexEnd=$indexEnd+strlen("</" . $tag); <br> $findTag=True;<br> }else{<br> $findTag=False;<br> }<br> }else{<br> $findTag=False;<br> }<br> $stopLimit2--;<br> }while($findTag==True AND $stopLimit2>0); <br> If ($indexEnd > -1){<br> $contain = substr($html,$indexbEnd, $indexEnd - $indexbEnd);<br> $indexEnd= strpos($html,">",$indexEnd);<br> if(gettype($indexEnd)!="integer"){<br> $indexEnd=-1;<br> }else{<br> $indexEnd+=1;<br> }<br> }<br> }else{<br> break;<br> }<br> $stopLimit1--;<br> }while($att == NULL AND $stopLimit1>0); <br> }<br> Return $indexbEnd;<br> }<br> }<br>?></code></pre>
<br>
<h4>使用範例</h4>
<p><code><?php<br>
include 'myClass/HTMLParser.php';<br>
$htmlParser=new HTMLParser();<br>
$url = "http://allen080.blogspot.com/2009/05/vbnet20.html";<br>
//取得整個網頁的HTML<br>
$htmlAll = $htmlParser->getHTML($url);<br>
//取得網頁Body的部份<br>
$htmlBody = $htmlParser->getHTMLBody($url);<br>
If ($htmlBody!=NULL){<br>
$indexEnd = strpos($htmlBody,"<span class='item-control blog-admin'>");<br>
if(gettype($indexEnd)!="integer") $indexEnd=-1;<br>
$valueAttribute = NULL;<br>
$valueContain = NULL;<br>
If($indexEnd > 0){<br>
$htmlBody = substr($htmlBody,$indexEnd);<br>
//取得a標籤1的內容<br>
$htmlParser->getHTMLTagContain($htmlBody, "span", $valueContain, $indexEnd);<br>
echo "span標籤的內容: " . $valueContain ."<BR>\n";<br>
//$htmlBody = substr($htmlBody,$indexEnd);<br>
//取得a標籤2的內容與href的屬性<br>
$htmlParser->getHTMLTagAtt($htmlBody, "a", "onclick", $valueAttribute, $valueContain, $indexEnd);<br>
echo "a標籤的內容與onclick的屬性: " . $valueAttribute ."\t" . ",內容:" . $valueContain;<br>
}<br>
} <br>
?><br>
<br>
</code></p>
<br>
<h4>執行結果</h4>
<p><code>span標籤的內容: <br>
<a class='quickedit' href='http://www.blogger.com/rearrange?blogID=2698062899592178296&widgetType=HTML&widgetId=HTML1&action=editWidget' onclick='return _WidgetManager._PopupConfig(document.getElementById("HTML1"));' target='configHTML1' title='編輯'><br>
<img alt='' height='18' src='http://img1.blogblog.com/img/icon18_wrench_allbkg.png' width='18'/><br>
</a><br>
<BR><br>
a標籤的內容與onclick的屬性: return _WidgetManager._PopupConfig(document.getElementById("HTML1")); ,內容:<br>
<img alt='' height='18' src='http://img1.blogblog.com/img/icon18_wrench_allbkg.png' width='18'/><br>
<br>
</code></p>
<br>
</div>
<h4>總結</h4>
<div>這是我為了練習php時寫出的東西~</div>
<div>我個人是覺得滿好用的~</div>
<div>不過有部份邏輯滿複雜的~所以我也不敢保證完全正確或是適用於各種網頁~</div>
<div>如果有人用有發現更好的改進方式請跟我說。</div>
<h4><font size="3" color="#000000"><span style="font-size: 13px; font-weight: normal; line-height: 16px;"><font size="4" color="#333333"><span style="font-size: 15px; line-height: normal;"><b><br>
</b></span></font></span></font></h4>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-48343048474336856502009-10-29T22:16:00.000-07:002009-11-01T21:56:41.972-08:00[PHP]字串處理函式<h4>序言</h4>
字串處理是常用的功能,大多數語言對這部份也有許多大同小異的函式,以下列出比較常用或我覺得特別需注意的函式。 <br>
<h4>尋找字串</h4>
strpos($string,$find[,$start]):尋找第一個在字串中出現的字詞,傳回0開始的數字位置。【$string】是被找的字串,【$find】是尋找的目標字詞,【$start】是代表尋找的起始位置。→<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.strpos.php&sa=D&sntz=1&usg=AFrqEzcjrSVukUf9SP3KCEhkIW0NxMgYDg" target="_blank">官方文</a>件<br>
這個函式有一個極需注意的部份,就在於它的回傳值,找到的話會回傳位置,也就是個0開始的數字;但沒找到的話就機車了,以VB為例的IndexOf函式是類似這個函式的功能,如果沒找到會回傳【-1】,但在PHP不同版本中,會回傳的值居然是False,那就算了,聽說這是4.0b3版以後的PHP是這樣,更早之前的PHP甚至聽說回傳的連False都不是。於是就有人想出了判斷型態的方法,具體實現方式如下
<p><code><?php<br>
//尋找第一個在字串中出現的字詞<br>
function str_indexof($string,$find,$start=0){<br>
$index=strpos($string,$find,$start);<br>
if(gettype($index)!="integer") $index=-1;<br>
return $index;<br>
}<br>
<br>
$string='abcdefghijk';<br>
$find='l';<br>
echo str_indexof($string,$find) . "\n"; //-1<br>
$find='a';<br>
echo str_indexof($string,$find,3) . "\n"; //-1<br>
$find='i';<br>
echo str_indexof($string,$find,3) . "\n"; //8<br>
?><br>
</code></p>
<br>
<h4>子字串</h4>
substr($string[[,$start],$length]):取得子字串,傳回子字串內容。【$string】是來源字串,【$start】是代表尋找的起始位置,【$length】是子字串長度。→<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.substr.php&sa=D&sntz=1&usg=AFrqEzcaTsM2Tr-xE05nIwk-LemQZ0CKhQ" style="color:rgb(0, 0, 204);text-decoration:none" target="_blank">官方文</a>件<br>
這個函式需注意的部份在於它對中文字(UTF-8)會以每個字3字元的方式計算,所以切割時如果是中文字就要以3的倍數遞增。有另外的函式可對含中文的函式做計算找子字串,但如果是用上面談到的strpos函式來找指標,那就可以不用擔心這個問題。具體實現方式如下
<p><code><?php<br>
$string = '這是substr的測試';<br>
echo substr($string,0,13) . "\n"; //這是substr�<br>
$string = '這是mb_substr的測試';<br>
echo mb_substr($string,0,13,'UTF-8') . "\n"; //這是mb_substr的測<br>
?><br>
</code></p>
<br>
<h4>字串長度</h4>
strlen($string):傳回字串長度。【$string】是來源字串。→<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.strlen.php&sa=D&sntz=1&usg=AFrqEzc83ti9dmGlTRVFL0-Z3cSnqDzpVw" target="_blank">官方文件</a><br>
這個函式與上面一樣對中文字(UTF-8)會以每個字3字元的方式計算。
<br>
<h4>轉換大小寫</h4>
strtoupper($string):回傳轉換為英文大寫字串。strtolower($string):取得轉換為英文小寫字串。【$string】是來源字串。→<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.strtoupper.php&sa=D&sntz=1&usg=AFrqEzdpE8zjxG3EFGC3Oyek4vqJV6AeXA" target="_blank">官方文件</a><br>
這個函式與上面一樣對中文字(UTF-8)會以每個字3字元的方式計算。
<br>
<h4>文字切割</h4>
split($pattern,$string[,$limit]):將字串依分割條件切割為陣列,回傳結果陣列。【$pattern】是分割條件,可為字串或是正規表達式。【$string】是來源字串。【$limit】最多切出幾個元素。<br>
這個函式較直得注意的有兩點,一個是參數順序,居然不是來源字串...;第二個是分割條件【$pattern】可用正規表達式,有關於正規表達式可參考<a href="http://www.google.com/url?q=http%3A%2F%2Fkm.tceb.edu.tw%2F%257Ewsx%2Fphp%2Fch6-2.htm&sa=D&sntz=1&usg=AFrqEzezuBA09F_6a6kE98tyaSu0dXX0dw" target="_blank">相關連結</a>。→<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.split.php&sa=D&sntz=1&usg=AFrqEzeKLQQL9-sQoJg5R4LJmn98tf0yRw" style="color:rgb(0, 0, 204);text-decoration:none" target="_blank">官方文件</a><br>
<br>
<h4>文字驗證</h4>
ereg($pattern,$string[,&$arrResult]):依正規表達式驗證字串格式(比對字串時有大小寫之分),回傳True符合或False不符合。→<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.ereg.php&sa=D&sntz=1&usg=AFrqEzchIlJIIIW74xTxRzNY7hx3bccK1w" style="color:rgb(0, 0, 204);text-decoration:none" target="_blank">官方文件</a><br>
eregi($pattern,$string[,&$arrResult]):功能同上,但比對字串時沒有大小寫之分。
<br>
【$pattern】是驗證條件正規表達式。【$string】是來源字串。【$arrResult】符合的文字。<br>
這個函式較直得注意的一樣有兩點,一個是參數順序;第二個是驗證條件【$pattern】為正規表達式,如【^[a-z0-9-]{3,8}$】如果要完整比對字串的話,要記得開頭用與結尾分別用【^】與【$】把條件框住,【[a-z0-9-]】代表小寫a~z與0~9及減號都是可用的字元,【{3,8}】代表上數字元可重複的次數為3~8次,可參考<a href="http://www.google.com/url?q=http%3A%2F%2Fkm.tceb.edu.tw%2F%257Ewsx%2Fphp%2Fch6-2.htm&sa=D&sntz=1&usg=AFrqEzezuBA09F_6a6kE98tyaSu0dXX0dw" target="_blank">相關連結</a>。<br>
相關連結<br>
<ul><li><a href="http://www.google.com/url?q=http%3A%2F%2Fwww.php.net%2Fmanual%2Fen%2Findex.php&sa=D&sntz=1&usg=AFrqEzeNK8UtnyMxGelntRdd5snAhmuIJw" target="_blank">PHP官方開發手冊</a>:英文開發手冊。</li>
<li><a href="http://www.google.com/url?q=http%3A%2F%2Fwww.w3school.com.cn%2Fphp%2Fphp_ref_string.asp&sa=D&sntz=1&usg=AFrqEzchsn0Pdti0JGKz5nomFH5luPQm3Q" target="_blank">W3School</a>:簡體中文的網站開發程式語言文件,雖然有些不夠完整,不過很適合當工具書或初學參考(除了PHP,其他還有許多網頁語言)。</li></ul>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-25253985462790873782009-10-29T20:25:00.000-07:002009-10-29T20:25:00.119-07:00[PHP]陣列、檔案讀寫<h4>陣列</h4>
PHP的Array也是我覺得很特別的東西,感覺有點像VB中HashTable的機制。<br>
從程式中可注意到,要取得Array中的元素個數可用【count($dataArr)】。<br>
新增元素的方法也很多元,也能動態新增。→<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Flanguage.types.array.php&sa=D&sntz=1&usg=AFrqEzfrjkXBZnuKGitjJsFR0LlC8LqyBw" target="_blank">官方文件</a>
<p><code><?php<br>
echo "\nArray 1<br>\n";<br>
$dataArr = array('abc','test');<br>
for($i=0;$i<count($dataArr);$i++){<br>
echo $i."\t".$dataArr[$i] . "<br>\n";<br>
}<br>
echo "\nArray 2<br>\n";<br>
$dataArr = array();<br>
$dataArr[]='abc';<br>
$dataArr[]='test';<br>
for($i=0;$i<count($dataArr);$i++){<br>
echo $i."\t".$dataArr[$i] . "<br>\n";<br>
}<br>
echo "\nArray 3<br>\n";<br>
$dataArr = array();<br>
$dataArr['name']='abc';<br>
$dataArr['content']='test';<br>
for($i=0;$i<count($dataArr);$i++){<br>
echo $i."\t".$dataArr[$i] . "<br>\n";<br>
}<br>
foreach($dataArr as $value){<br>
echo $value . "<br>\n";<br>
}<br>
foreach($dataArr as $key => $value){<br>
echo $key."\t".$value . "<br>\n";<br>
}<br>
echo "\nArray 4<br>\n";<br>
$dataArr = array('name' => 'abc','content' => 'test');<br>
foreach($dataArr as $key => $value){<br>
echo $key."\t".$value . "<br>\n";<br>
}<br>
?><br>
</code></p>
結果:
<p><code>Array 1<br><br>
0 abc<br><br>
1 test<br><br>
<br>
Array 2<br><br>
0 abc<br><br>
1 test<br><br>
<br>
Array 3<br><br>
<br>
0 <br><br>
1 <br><br>
abc<br><br>
test<br><br>
name abc<br><br>
content test<br><br>
<br>
Array 4<br><br>
name abc<br><br>
content test<br><br>
<br>
</code></p>
<h4>檔案存取</h4>
檔案存取是我常會用的功能,以下列出我的寫法與常用函式:<a href="http://www.google.com/url?q=http%3A%2F%2Fwww.php.net%2Fmanual%2Fen%2Fref.filesystem.php&sa=D&sntz=1&usg=AFrqEzdY-enhqtSmoBFqOCexF8q-f7J6Jw" target="_blank">官方文件</a>
<p><code><?php <br>
//存文字檔,如果檔案不存在會建立檔案,如果存在會覆蓋檔案<br>
function saveText($filename,$fText){<br>
try{<br>
$fh = fopen($filename, "w");<br>
fwrite($fh, $fText);<br>
fclose($fh);<br>
}catch(Exception $e){<br>
echo 'Error addText: ' .$e->getMessage();<br>
}<br>
}<br>
//增加文字到文字檔最後面,如果檔案不存在會建立檔案<br>
function addText($filename,$fText){<br>
try{<br>
$fh = fopen($filename, "a");<br>
fwrite($fh, $fText);<br>
fclose($fh);<br>
}catch(Exception $e){<br>
echo 'Error addText: ' .$e->getMessage();<br>
}<br>
}<br>
//讀取文字檔內容<br>
function loadText($filename){<br>
$fText=NULL;<br>
try{<br>
if(file_exists($filename)) $fText=file_get_contents($filename); <br>
}catch(Exception $e){<br>
echo 'Error loadText: ' .$e->getMessage();<br>
}<br>
return $fText;<br>
}<br>
//刪除檔案<br>
function deleteFile($filename){<br>
return unlink($filename);<br>
}<br>
//建立資料夾<br>
function createDir($dirname){<br>
return mkdir($dirname);<br>
}<br>
//刪除資料夾<br>
function deleteDir($dirname){<br>
return rmdir($dirname);<br>
}<br>
?><br>
</code></p>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-79486444594683829832009-10-29T20:17:00.000-07:002009-10-29T20:17:00.941-07:00[初學]PHP入門心得<div>
<h4>序言</h4>
雖然寫了許久的程式,但一直沒花時間去練習PHP。<br>
最近花了點時間試試PHP,增長了些見聞,後續幾篇會一一記錄下我開發時注意到的事。 <br>
<h4>開發環境</h4>
<ul>
<li>Windows 2003<br>
</li>
<li><a href="http://www.google.com/url?q=http%3A%2F%2Forz99.com%2Ftwamp%2F&sa=D&sntz=1&usg=AFrqEzd4aOq-KZ7ilc2vuVFP1ylus1SEaA" target="_blank">TWAMPs</a>(Tiny Windows Apache MySQL PHP Portable Web Server)V1.3.3中文版<br>
我開發的時候雖然已經有V1.3.5版,但執行的時候不知道為什麼我的整個作業系統會出現很多衝突的現象,很多程式都受影響,所以就往回推用舊的版本。V1.3.4版無法下載,就改用V1.3.3。以下是這個免安裝的環境提供的版本:<br>
</li>
<ul><li>Apache:2.2.11</li>
<li>PHP:5.2.10</li>
<li>MySQL:5.1.36-community</li>
<li>phpMyAdmin:3.2.0.1</li>
<li>Drupal:6.13</li></ul>
<li><a href="http://www.google.com/url?q=http%3A%2F%2Fnotepad-plus.sourceforge.net%2Ftw%2Fsite.htm&sa=D&sntz=1&usg=AFrqEzcUJQdJn0WKiT5_SygCdsIIIvf27g" target="_blank">Notepad++ 5.4.4</a><br>
我沒有特地找PHP的編輯器,所以編輯起來比較費工,不過Notepad還是有用顏色標亮特定的語法,所以還是有點用的。<br>
</li>
</ul>
<h4>環境設定</h4>
<ul>
<li>啟動前可以看一下根目錄的【README.txt】來找到對應的Port或其他值的更改地點,但有些部分【README.txt】沒有寫的很正確,所以可能還是要靠經驗與人工找找實際的目錄,如:</li>
<ul><li> Apache PORT更改,README.txt說【edit httpd.conf in TWAMP\Apache\conf】,但實際路徑會在【 TWAMPd\app\conf】下的httpd.conf,找到並更改【Listen 80】</li>
<li>php.ini的位置,README.txt說【Edit php.ini in TWAMPd\PHP】,但實際路徑會在【TWAMPd\app\bin】</li>
<li>【TWAMPd\htdocs】目錄下會是所有網頁文件所在的地方。<br>
</li></ul>
</ul>
<h4>Apache 目錄存取限制設定</h4>
【.htaccess】 是一個文字檔,可以自己建立後,放在要限制/保護的目錄下,Apache就會依裡面的設定內容對使用者的存取進行限制或保護。<br>
例如我對目錄要完全不給人進來存取檔案,就在文字檔內寫入以下內容<br>
<p><code>order allow,deny<br>
deny from all</code></p>
基本上這只是最簡單的功能,但很常用。如果需要更多設定,其實這個檔也可以設定的很複雜,網路上還有人專門做出設定工具:<a href="http://www.google.com/url?q=http%3A%2F%2Fwww.htaccesseditor.com%2Ftc.shtml&sa=D&sntz=1&usg=AFrqEzehSxNphIAUfLlLueGSR2pJvvPwVA" target="_blank">htaccessEditor</a>,在此就不詳述了。
<h4>PHP開發兩三事</h4>
<ul><li>
基本語法
<p><code><?php echo "123"; ?><br>
</code></p>
【<?php ... ?>】指的是裡面的code【...】是php,以副檔名為*.php的檔案放在【TWAMPd\htdocs】目錄下,就可以被編譯執行。【echo】會將後面帶的文字顯示在頁面這段程式所在的位置上。→<a href="http://www.google.com/url?q=http%3A%2F%2Fwww.php.net%2Fmanual%2Fen%2Flanguage.basic-syntax.phpmode.php&sa=D&sntz=1&usg=AFrqEzfZbmoR0p3U4Nvc97m2pRg7Y9aRzw" target="_blank">官方文件-基本語法</a>、<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.echo.php&sa=D&sntz=1&usg=AFrqEze3YnyrOFdL01nfXFTMYt6A6pvWhg" target="_blank">官方文件-echo</a></li>
<li>
include
<p><code><?php<br>
include 'myClass/HTMLParser.php';<br>
?><br>
</code></p>
include 的寫法,會將include的PHP程式如同嵌入在宣告的位置一樣,我想使用方法應該就如同C一樣,欲使用前必先宣告。→<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.include.php&sa=D&sntz=1&usg=AFrqEzfB3J7M0yseb99R8eLZ4JPw1nVOsA" target="_blank">官方文件</a>
</li>
<li>
變數、單引號與雙引號
<p><code><?php<br>
$value="123";<br>
echo "1: " . $value . "\r\n<br>";<br>
echo "2: " . "abc\t$valuedef\r\n<br>";<br>
echo "3: " . 'abc$valuedef\r\n<br>';<br>
echo "4: " . "abc\t$value def\r\n<br>";<br>
echo "5: " . 'abc$value def \r\n<br>';<br>
echo "6: " . 'abc' . $value . 'def\r\n<br>';<br>
echo "7: " . '"' . $value . "'\r\n<br>";<br>
?><br>
</code></p>
結果:
<p><code>1: 123<br>
<br>2: abc <br>
<br>3: abc$valuedef\r\n<br>4: abc 123 def<br>
<br>5: abc$value def \r\n<br>6: abc123def\r\n<br>7: "123'<br>
<br></code></p>
上面的程式中可以看到幾個現象:變數的前面用【$】來標示它是個變數,而且不用先行宣告,隨使用就會產生。以下逐行來看<br>
<ol><li>字串的組合是用點【.】來標示兩字串要串聯起來。【雙引號】中的特殊文元【\】標示了後面帶了特殊字元【\r\n】,這都是換行符號,如果用VB來形容就是【vbCrLf】,這個特殊字元可以單獨使用,如【\n】。(PS:按「Enter」鍵實際產生兩個字元換行和回到開頭(ASCII編碼10:\n和13:\r))</li>
<li>【雙引號】中的變數被編譯成顯示,但因為英文字連再一起,所以編譯後是顯示【valuedef】變數的值。因為根本沒有宣告【valuedef】變數的值,所以最後產生的時候是空值,就什麼都沒有。</li>
<li>【單引號】直接輸出文字內容,所以特殊字元或變數都無效。</li>
<li>【雙引號】中的變數被編譯成顯示,此字串內容中,還有用到特殊字元【\t】來出現tab的字元。</li>
<li>【單引號】直接輸出文字內容,所以特殊字元或變數都無效。</li>
<li>【單引號】直接輸出文字內容,所以特殊字元或變數都無效。</li>
<li>雙引號內容中可以出現單引號,反過來說也行,如果雙引號內容中要出現雙引號,需要加上特殊字元\。</li>
</ol>
PHP 會解譯【雙引號】內容中的變數,而【單引號】則視為純字串出,PHP 不會再處理單引號內的內容。所以單引號與雙引號在使用時會有時機上的差異。
</li>
<li>
常數
<p><code><?php<br>
define('myValue','1234');<br>
echo myValue;<br>
?><br>
</code></p>
常數的寫法與變數不同,定義後名稱前面不需要再加上【$】號。→<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.define.php&sa=D&sntz=1&usg=AFrqEzfbeA7BB1AX6Srpj727deKmOPm0dQ" target="_blank">官方文件</a></li>
<li>
脫逸 (Escape)字
<p><code><?php <br>
//去除get_magic_quotes_gpc on 時 針對特殊字做脫逸 (Escape)的影響<br>
if (get_magic_quotes_gpc())<br>
{ <br>
$HTTP_GET_VARS = array_map('stripslashes', $HTTP_GET_VARS);<br>
$HTTP_POST_VARS = array_map('stripslashes', $HTTP_POST_VARS);<br>
$HTTP_COOKIE_VARS = array_map('stripslashes', $HTTP_COOKIE_VARS);<br>
$_GET = array_map('stripslashes', $_GET);<br>
$_POST = array_map('stripslashes', $_POST);<br>
$_COOKIE = array_map('stripslashes', $_COOKIE);<br>
$_REQUEST = array_map('stripslashes', $_REQUEST);<br>
}<br>
?><br>
</code></p>
這個部份是比較與執行環境設定有關的。在PHP.ini中有個設定【get_magic_quotes_gpc on】(<a href="http://www.google.com/url?q=http%3A%2F%2Fphp.net%2Fmanual%2Fen%2Ffunction.get-magic-quotes-gpc.php&sa=D&sntz=1&usg=AFrqEzfDt_z4CsZ0TxgxYKa6tZgaFDwSrw" target="_blank">官方文件</a>),可以讓使用者輸入的字元中一些特殊的字元加上【\】,如單引號【'】、雙引號【"】、斜線【\】,以防程式處理時會造成意想不到的錯誤。但這樣的設定可能反而會讓我們在處理資料時更加棘手,所以這串程式能判斷當這個設定開啟時,讓這些特殊的字元不經過加上【\】的畜哩,直接取得使用者輸入的內容。</li>
</ul>
</div>
相關連結<br>
<ul><li><a target="_blank" href="http://orz99.com/twamp/">TWAMP</a>:免安裝的中英文伺服器執行環境。</li>
<li><a target="_blank" href="http://www.php.net/manual/en/index.php">PHP官方開發手冊</a>:英文開發手冊。<br>
</li>
<li><a target="_blank" href="http://www.w3school.com.cn/php/index.asp">W3School</a>:簡體中文的網站開發程式語言文件,雖然有些不夠完整,不過很適合當工具書或初學參考(除了PHP,其他還有許多網頁語言)。</li></ul>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-30699213879143244732009-05-10T23:34:00.000-07:002009-11-03T00:25:50.201-08:00[程式]VB.Net2.0網頁原始碼取得函式<h4>序言</h4>
<p>我因為學術需求,要取得某些網址的網頁原始碼進行分析,因此寫了以下函式,貼出來與大家分享吧~</p>
<p>*2009/10/29 更新函式,加強切割網頁函式、抓網頁標頭。<br>
</p>
<h4>開發環境</h4>
<ul>
<li>VB.Net 2.0 (VS2005)</li>
</ul>
<h4>專案設定</h4>
<ul>
<li>建立專案後預設的專案屬性下,參考的元件如下圖:<br>
<a href="http://img2.imageshack.us/img2/2200/001txd.jpg" target="_blank"><img src="http://img2.imageshack.us/img2/2200/001txd.jpg" width="80%"></a><br>
</li>
<li>下面的程式中會用到【Web】這個物件,所以我們需要加入【System.Web】這個元件:<br>
<a href="http://img24.imageshack.us/img24/1885/002gam.jpg" target="_blank"><img src="http://img24.imageshack.us/img24/1885/002gam.jpg" width="40%"></a><br>
點選加入,在.Net分頁下找到【System.Web】這個元件<br>
<a href="http://img230.imageshack.us/img230/702/001ady.jpg" target="_blank"><img src="http://img230.imageshack.us/img230/702/001ady.jpg" width="80%"></a></li>
</ul>
<h4>網頁原始碼函式類別</h4>
<pre><code>Imports System.Net
Imports System.io
Imports System.Reflection
Public Class WebPageGenFunc
Private Shared rd As New Random(Now.Second)
Private Shared sec As Integer
Private Shared lastsec As Integer = -1
Public Shared Function sleepTime(Optional ByVal minimatime As Integer = 2600, Optional ByVal rangeSecond As Integer = 5) As Integer
sec = (rd.Next Mod rangeSecond) * 1000 + minimatime
While sec = lastsec
sec = (rd.Next Mod rangeSecond) * 1000 + minimatime
End While
lastsec = sec
System.Threading.Thread.Sleep(sec)
Return sec
End Function
Private Shared Sub SetAllowUnsafeHeaderParsing20()
Dim a As New System.Net.Configuration.SettingsSection
Dim aNetAssembly As System.Reflection.Assembly = Assembly.GetAssembly(a.GetType)
Dim aSettingsType As Type = aNetAssembly.GetType("System.Net.Configuration.SettingsSectionInternal")
Dim args As Object() = Nothing
Dim anInstance As Object = aSettingsType.InvokeMember("Section", BindingFlags.Static Or BindingFlags.GetProperty Or BindingFlags.NonPublic, Nothing, Nothing, args)
Dim aUseUnsafeHeaderParsing As FieldInfo = aSettingsType.GetField("useUnsafeHeaderParsing", BindingFlags.NonPublic Or BindingFlags.Instance)
aUseUnsafeHeaderParsing.SetValue(anInstance, True)
End Sub
''' <summary>
''' 使用Get方法取得網頁內容
''' </summary>
''' <param name="url">網址</param>
''' <param name="noCashe">不使用快取</param>
''' <returns>網頁的HTML</returns>
''' <remarks>使用Get方法取得網頁內容</remarks>
Public Shared Function getHTMLGet(ByVal url As String, Optional ByVal noCashe As Boolean = False) As String
getHTMLGet = Nothing
SetAllowUnsafeHeaderParsing20()
Dim wRs As HttpWebResponse
Dim wRq As HttpWebRequest
' Create the request using the WebRequestFactory.
wRq = CType(WebRequest.Create(url), HttpWebRequest)
With wRq
.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"
.ContentType = "application/x-www-form-urlencoded"
.Headers.Add("Accept-Language", "zh-tw")
.Method = "GET"
.Timeout = 10000
If noCashe Then
Dim policy As New Cache.HttpRequestCachePolicy(Cache.HttpRequestCacheLevel.NoCacheNoStore)
.CachePolicy = policy
.Headers.Add("Cache-Control", "no-cache")
End If
End With
Try
' Return the response stream.
wRs = CType(wRq.GetResponse(), HttpWebResponse)
Dim streamResponse As Stream = wRs.GetResponseStream()
Dim streamRead As New StreamReader(streamResponse)
Dim responseString As String = streamRead.ReadToEnd()
getHTMLGet = responseString
' Close Stream object.
streamResponse.Close()
streamRead.Close()
' Release the HttpWebResponse.
wRs.Close()
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Function
''' <summary>
''' 使用Post方法取得網頁內容
''' </summary>
''' <param name="url">網址</param>
''' <param name="postdata">傳遞參數,如a=123&b=456</param>
''' <param name="noCashe">不使用快取</param>
''' <returns>網頁的HTML</returns>
''' <remarks>使用Post方法取得網頁內容</remarks>
Public Shared Function getHTMLPost(ByVal url As String, Optional ByVal postdata As String = Nothing, Optional ByVal noCashe As Boolean = False) As String
getHTMLPost = Nothing
SetAllowUnsafeHeaderParsing20()
Dim wRs As HttpWebResponse
Dim wRq As HttpWebRequest
' Create the request using the WebRequestFactory.
wRq = CType(WebRequest.Create(url), HttpWebRequest)
With wRq
.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"
.Headers.Add("Accept-Language", "zh-tw")
.Method = "POST"
.Timeout = 10000
.KeepAlive = False
If noCashe Then
Dim policy As New Cache.HttpRequestCachePolicy(Cache.HttpRequestCacheLevel.NoCacheNoStore)
.CachePolicy = policy
.Headers.Add("Cache-Control", "no-cache")
End If
If Not postdata Is Nothing Then
.Timeout = 60000
Dim encoding As New System.Text.ASCIIEncoding()
Dim byte1 As Byte() = encoding.GetBytes(postdata)
.ContentType = "application/x-www-form-urlencoded"
.ContentLength = byte1.Length
.GetRequestStream().Write(byte1, 0, byte1.Length)
End If
End With
wRq.GetRequestStream().Close()
Try
' Return the response stream.
wRs = CType(wRq.GetResponse(), HttpWebResponse)
Dim streamResponse As Stream = wRs.GetResponseStream()
Dim streamRead As New StreamReader(streamResponse)
Dim responseString As String = streamRead.ReadToEnd()
getHTMLPost = responseString
' Close Stream object.
streamResponse.Close()
streamRead.Close()
' Release the HttpWebResponse.
wRs.Close()
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Function
''' <summary>
''' 使用WebClient取得網頁內容
''' </summary>
''' <param name="url">網址</param>
''' <param name="postdata">傳遞的參數</param>
''' <param name="method">使用的方法,預設為POST</param>
''' <param name="noCashe">不使用快取</param>
''' <returns>網頁的HTML</returns>
''' <remarks>使用WebClient取得網頁內容</remarks>
Public Shared Function getHTMLWebClient(ByVal url As String, ByRef postdata As Specialized.NameValueCollection, Optional ByVal method As String = "POST", Optional ByVal noCashe As Boolean = False) As String
getHTMLWebClient = Nothing
Try
SetAllowUnsafeHeaderParsing20()
Dim myWebClient As New WebClient()
If noCashe Then
Dim policy As New Cache.HttpRequestCachePolicy(Cache.HttpRequestCacheLevel.NoCacheNoStore)
myWebClient.CachePolicy = policy
myWebClient.Headers.Add("Cache-Control", "no-cache")
Else
Dim rheaders As WebHeaderCollection = myWebClient.ResponseHeaders
If Not rheaders Is Nothing Then
Dim header As String = rheaders("Set-Cookie")
If Not header Is Nothing Then
myWebClient.Headers.Add("Cookie", header)
End If
End If
End If
myWebClient.Headers.Add("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)")
myWebClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded")
myWebClient.Headers.Add("Accept-Language", "zh-tw")
If postdata Is Nothing Then postdata = New Specialized.NameValueCollection
Dim responseArray As Byte() = myWebClient.UploadValues(url, method, postdata)
Dim encoding As New System.Text.UTF8Encoding
getHTMLWebClient = encoding.GetString(responseArray)
Catch ex As Exception
Console.WriteLine(ex.ToString)
End Try
End Function
''' <summary>
''' 取得網頁的Body區段
''' </summary>
''' <param name="url">網址</param>
''' <param name="postdata">傳遞的參數,若有值會使用getHTMLPost取得</param>
''' <param name="postValue">傳遞的參數,若有值會使用getHTMLWebClient取得</param>
''' <param name="noCashe">不使用快取</param>
''' <returns>網頁的HTML</returns>
''' <remarks>取得網頁的Body區段</remarks>
Public Shared Function getHTMLBody(ByVal url As String, Optional ByVal postdata As String = Nothing, Optional ByVal postValue As Specialized.NameValueCollection = Nothing, Optional ByVal noCashe As Boolean = False, Optional ByVal useWebClient As Boolean = False) As String
getHTMLBody = Nothing
Dim html As String
If Not postValue Is Nothing Then
html = getHTMLWebClient(url, postValue, , noCashe)
ElseIf Not postdata Is Nothing Then
html = getHTMLPost(url, postdata, noCashe)
Else
If useWebClient Then
html = getHTMLWebClient(url, Nothing, "GET", noCashe)
Else
html = getHTMLGet(url, noCashe)
End If
End If
If Not html Is Nothing Then
getHTMLTagContain(html, "body", getHTMLBody)
End If
End Function
''' <summary>
''' 取得HTML中第一個符合的標籤內容的指標,並將取得的標籤內容寫入參數中
''' </summary>
''' <param name="html">HTML</param>
''' <param name="tag">標籤</param>
''' <param name="contain">取得的標籤內容</param>
''' <param name="indexEnd">此標籤結束於HTML的指標</param>
''' <returns>標籤內容的指標</returns>
''' <remarks>取得HTML中第一個符合的標籤內容的指標,並將取得的標籤內容寫入參數中</remarks>
Public Shared Function getHTMLTagContain(ByVal html As String, ByVal tag As String, Optional ByRef contain As String = Nothing, Optional ByRef indexEnd As Integer = -1) As Integer
tag = tag.ToLower
contain = Nothing
indexEnd = -1
Dim indexBegin As Integer = -1
Dim indexbBegin As Integer = -1
If Not html Is Nothing Then
indexBegin = html.ToLower.IndexOf("<" & tag)
If indexBegin > -1 Then
indexbBegin = html.IndexOf(">", indexBegin)
If indexbBegin > -1 Then
indexbBegin += 1
End If
Dim findTag As Boolean = False
indexEnd = indexbBegin
Dim lastStart As Integer = indexbBegin
Dim stopLimit2 As Integer = 9999
Do
indexEnd = html.ToLower.IndexOf("</" & tag, indexEnd)
If indexEnd > -1 Then
If html.Substring(lastStart, indexEnd - lastStart).IndexOf("<" & tag) > -1 Then
lastStart = indexEnd
indexEnd = indexEnd + ("</" & tag).Length
findTag = True
Else
findTag = False
End If
Else
findTag = False
End If
stopLimit2 -= 1
Loop While findTag And stopLimit2 > 0
If indexEnd > -1 Then
contain = html.Substring(indexbBegin, indexEnd - indexbBegin)
indexEnd = html.IndexOf(">", indexEnd)
If indexEnd > -1 Then
indexEnd += 1
End If
End If
End If
End If
Return indexbBegin
End Function
''' <summary>
''' 取得HTML中第一個符合的標籤屬性的指標,並將取得的標籤內容與該屬性內容寫入參數中
''' </summary>
''' <param name="html">HTML</param>
''' <param name="tag">標籤</param>
''' <param name="attName">屬性名稱</param>
''' <param name="att">取得的屬性內容</param>
''' <param name="contain">取得的標籤內容</param>
''' <param name="indexEnd">此標籤結束於HTML的指標</param>
''' <returns></returns>
''' <remarks>取得HTML中第一個符合的標籤屬性的指標,並將取得的標籤內容與該屬性內容寫入參數中</remarks>
Public Shared Function getHTMLTagAtt(ByVal html As String, ByVal tag As String, ByVal attName As String, Optional ByRef att As String = Nothing, Optional ByRef contain As String = Nothing, Optional ByRef indexEnd As Integer = -1) As Integer
att = Nothing
contain = Nothing
tag = tag.ToLower
attName = attName.ToLower
indexEnd = -1
Dim indexBegin As Integer = -1
Dim indexaBegin As Integer = -1
Dim indexbEnd As Integer = -1
Dim findTag As Boolean = False
Dim sign As String
If Not html Is Nothing Then
indexBegin = 0
Dim stopLimit1 As Integer = 9999
Do
indexbEnd = -1
indexBegin = html.ToLower.IndexOf("<" & tag, indexBegin)
If indexBegin > -1 Then
indexbEnd = html.IndexOf(">", indexBegin)
If indexbEnd > -1 Then
indexaBegin = html.Substring(0, indexbEnd).Replace("""", "'").ToLower.IndexOf(attName & "='", indexBegin)
If indexaBegin > -1 Then
sign = html.Substring(indexaBegin + (attName & "=").Length, 1)
indexaBegin += (attName & "='").Length
Dim indexaEnd As Integer = html.Substring(0, indexbEnd).IndexOf(sign, indexaBegin)
If indexaEnd > -1 Then
att = html.Substring(indexaBegin, indexaEnd - indexaBegin)
End If
Else
indexBegin = indexbEnd + 1
Continue Do
End If
indexbEnd += 1
End If
findTag = False
indexEnd = indexbEnd
Dim lastStart As Integer = indexbEnd
Dim stopLimit2 As Integer = 9999
Do
indexEnd = html.ToLower.IndexOf("</" & tag, indexEnd)
If indexEnd > -1 Then
If html.Substring(lastStart, indexEnd - lastStart).IndexOf("<" & tag) > -1 Then
lastStart = indexEnd
indexEnd = indexEnd + ("</" & tag).Length
findTag = True
Else
findTag = False
End If
Else
findTag = False
End If
stopLimit2 -= 1
Loop While findTag And stopLimit2 > 0
If indexEnd > -1 Then
contain = html.Substring(indexbEnd, indexEnd - indexbEnd)
indexEnd = html.IndexOf(">", indexEnd)
If indexEnd > -1 Then
indexEnd += 1
End If
End If
Else
Exit Do
End If
stopLimit1 -= 1
Loop While att Is Nothing And stopLimit1 > 0
End If
Return indexbEnd
End Function
''' <summary>
''' Url參數值編碼
''' </summary>
''' <param name="value">參數值</param>
''' <returns>編碼結果</returns>
''' <remarks>Url參數值編碼</remarks>
Public Shared Function getEncodeStr(ByVal value As String)
Return Web.HttpUtility.UrlEncode(value)
End Function
''' <summary>
''' Url參數值解碼
''' </summary>
''' <param name="value">參數值</param>
''' <returns>解碼結果</returns>
''' <remarks>Url參數值解碼</remarks>
Public Shared Function getDecodeStr(ByVal value As String)
Return Web.HttpUtility.UrlDecode(value)
End Function
End Class
</code></pre>
<div></div>
<h4>使用範例程式</h4>
<p><code> Dim indexEnd As Integer<br>
Dim valueAttribute As String<br>
Dim valueContain As String<br>
Dim url As String = "http://allen080.blogspot.com/2009/05/vbnet20.html"<br>
'使用WebRequest的Get方法取得整個網頁的HTML<br>
'Dim htmlAll As String = WebPageGenFunc.getHTMLGet(url)<br>
'取得網頁Body的部份<br>
Dim htmlBody As String = WebPageGenFunc.getHTMLBody(url)<br>
If Not htmlBody Is Nothing Then<br>
indexEnd = htmlBody.IndexOf("<span class='item-control blog-admin'>")<br>
valueAttribute = Nothing<br>
valueContain = Nothing<br>
If indexEnd > 0 Then<br>
htmlBody = htmlBody.Substring(indexEnd)<br>
'取得a標籤1的內容<br>
WebPageGenFunc.getHTMLTagContain(htmlBody, "span", valueContain, indexEnd)<br>
Console.WriteLine("span標籤的內容: " & valueContain)<br>
'htmlBody = htmlBody.Substring(indexEnd)<br>
'取得a標籤2的內容與href的屬性<br>
WebPageGenFunc.getHTMLTagAtt(htmlBody, "a", "onclick", valueAttribute, valueContain, indexEnd)<br>
Console.WriteLine("a標籤的內容與onclick的屬性: " & valueAttribute & vbTab & ",內容:" & valueContain)<br>
End If<br>
End If<br>
<br>
<br>
'使用WebClient的Post方法取得資料<br>
url = "http://al080.summerhost.info/invoiceMe/index.php"<br>
Dim searchStr As String = "123"<br>
Dim postdata As New Specialized.NameValueCollection<br>
postdata.Add("ddlYear", "2009")<br>
postdata.Add("ddlMonth", "7-8")<br>
postdata.Add("txtInvNO", searchStr)<br>
postdata.Add("btnMatchInv", "對獎")<br>
htmlBody = WebPageGenFunc.getHTMLBody(url, , postdata)<br>
If Not htmlBody Is Nothing Then<br>
indexEnd = htmlBody.IndexOf("<div class=""DivRight"">")<br>
If indexEnd > 0 Then<br>
htmlBody = htmlBody.Substring(indexEnd)<br>
'取得div標籤的內容<br>
WebPageGenFunc.getHTMLTagContain(htmlBody, "div", valueContain, indexEnd)<br>
Console.WriteLine("使用WebClient的Post方法取得資料: " & valueContain)<br>
End If<br>
End If<br>
<br>
'使用WebRequest的Post方法取得資料<br>
searchStr = String.Empty<br>
'在組合參數時要同時編碼<br>
For i As Integer = 0 To postdata.Count - 1<br>
searchStr &= "&" & postdata.GetKey(i) & "=" & WebPageGenFunc.getEncodeStr(postdata(i))<br>
Next<br>
searchStr = searchStr.Substring(1)<br>
htmlBody = WebPageGenFunc.getHTMLBody(url, searchStr)<br>
If Not htmlBody Is Nothing Then<br>
indexEnd = htmlBody.IndexOf("<div class=""DivRight"">")<br>
If indexEnd > 0 Then<br>
htmlBody = htmlBody.Substring(indexEnd)<br>
'取得div標籤的內容<br>
WebPageGenFunc.getHTMLTagContain(htmlBody, "div", valueContain, indexEnd)<br>
Console.WriteLine("使用WebRequest的Post方法取得資料: " & valueContain)<br>
End If<br>
End If</code></p>
<h4>執行結果</h4>
<p><code>span標籤的內容: <br>
<a class='quickedit' href='http://www.blogger.com/rearrange?blogID=2698062899592178296&widgetType=HTML&widgetId=HTML1&action=editWidget' onclick='return _WidgetManager._PopupConfig(document.getElementById("HTML1"));' target='configHTML1' title='編輯'><br>
<img alt='' height='18' src='http://img1.blogblog.com/img/icon18_wrench_allbkg.png' width='18'/><br>
</a><br>
<br>
a標籤的內容與onclick的屬性: return _WidgetManager._PopupConfig(document.getElementById("HTML1")); ,內容:<br>
<img alt='' height='18' src='http://img1.blogblog.com/img/icon18_wrench_allbkg.png' width='18'/><br>
<br>
使用WebClient的Post方法取得資料: <span style="font-weight:bold;">對獎結果:</span><br><br>
<div class="DivResult"><br>
無中獎發票...<br><br>
</div><br>
<br>
使用WebRequest的Post方法取得資料: <span style="font-weight:bold;">對獎結果:</span><br><br>
<div class="DivResult"><br>
無中獎發票...<br><br>
</div></code></p>
<h4>相關連結</h4>
<ul>
<li><a href="http://code.google.com/p/zuse/source/browse/trunk/Zuse/Core/ZuneCatcher.cs?spec=svn33&r=33">如果想設定更多Request時的標頭可參考 zuse</a><br>
</li>
</ul>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0tag:blogger.com,1999:blog-2698062899592178296.post-62584161014513730712009-04-20T22:25:00.000-07:002009-10-28T22:13:59.134-07:00[程式]VB.Net2.0資料庫通用存取函式<h4>序言</h4>
<p>在VS2005建立VB專案(或Web網站)後,若要進行資料庫存取,我個人比較習慣將連線字串寫在設定檔app.config(或web.config)下。</p>
<p>不過VB專案預設是不會產生這個檔,而且在程式中若要取得連線字串的設定也要對專案的參考進行設定。</p>
<p>以下記錄下我做的設定,並把資料庫存取程式簡化為函式。 <br>
</p>
<h4>開發環境</h4>
<ul>
<li>VB.Net 2.0 (VS2005)</li>
<li>MSSQL2005 Express<br>
</li>
</ul>
<h4>專案設定</h4>
<ul>
<li>建立專案後預設的專案屬性下,參考的元件如下圖:<br>
<a href="http://img2.imageshack.us/img2/2200/001txd.jpg" target="_blank"><img src="http://img2.imageshack.us/img2/2200/001txd.jpg" width="80%"></a><br>
</li>
<li>下面的程式中會用到【ConfigurationManager】這個物件來取得設定檔的連線字串,所以我們需要加入【System.Configuration】這個元件:<br>
<a href="http://img24.imageshack.us/img24/1885/002gam.jpg" target="_blank"><img src="http://img24.imageshack.us/img24/1885/002gam.jpg" width="40%"></a><br>
點選加入,在.Net分頁下找到【System.Configuration】這個元件<br>
<a href="http://img23.imageshack.us/img23/4898/003rdv.jpg" target="_blank"><img src="http://img23.imageshack.us/img23/4898/003rdv.jpg" width="80%"></a></li>
<li>再來要在專案加入新項目【應用程式組態】,名稱用預設的【app.config】就可以了:<br>
<a href="http://img22.imageshack.us/img22/8335/004ybn.jpg" target="_blank"><img src="http://img22.imageshack.us/img22/8335/004ybn.jpg" width="80%"></a><br>
</li>
<li>
<p>編輯app.config,在【configuration】標籤內加入連線字串的設定如:<br>
<a href="http://img18.imageshack.us/img18/3728/005ozh.jpg" target="_blank"><img src="http://img18.imageshack.us/img18/3728/005ozh.jpg" width="80%"></a></p>
<p><code><?xml version="1.0" encoding="utf-8" ?><br>
<configuration><br>
...<br>
<connectionStrings><br>
<add name="MSSQLDB1"<br>
connectionString="Data Source=localhost;Initial Catalog=MyTestDB;Integrated Security=True"<br>
providerName="System.Data.SqlClient" /><br>
<add name="MSSQLDB2"<br>
connectionString="Data Source=127.0.0.1;Initial Catalog=MyTestDB;User ID=sa;Password=1234"<br>
providerName="System.Data.SqlClient" /><br>
</connectionStrings>
<br>
... </code></p>
</li>
</ul>
<h4>通用存取函式類別</h4>
<p><code><br>
Imports System.Data.SqlClient<br>
Imports System.Configuration<br>
Public Class DBAccessFunc<br>
''' <summary><br>
''' 從ConfigurationManager中的ConnectionStrings找出Initial Catalog<br>
''' </summary><br>
''' <param name="ConnName">ConnectionStrings名稱(String)</param><br>
''' <returns>回傳資料庫名稱</returns><br>
''' <remarks>從ConfigurationManager中的ConnectionStrings找出Initial Catalog</remarks><br>
Public Shared Function getDBName(ByVal ConnName As String) As String<br>
Dim val As String = ""<br>
Dim ConnString As String = ConfigurationManager.ConnectionStrings(ConnName).ConnectionString<br>
Dim i As Integer = ConnString.IndexOf("Initial Catalog=")<br>
If i > -1 Then<br>
val = ConnString.Substring(i + "Initial Catalog=".Length)<br>
i = val.IndexOf(";")<br>
If i > -1 Then<br>
val = val.Substring(0, i)<br>
End If<br>
End If<br>
Return val<br>
End Function<br>
<br>
Public Shared Function getConnString(ByVal ConnName As String) As String<br>
Return ConfigurationManager.ConnectionStrings(ConnName).ConnectionString<br>
End Function<br>
<br>
<br>
Public Shared Function getConn(ByVal ConnName As String) As SqlConnection<br>
Return New SqlConnection(getConnString(ConnName))<br>
End Function<br>
''' <summary><br>
''' 查詢資料庫<br>
''' </summary><br>
''' <param name="cn">連線</param><br>
''' <param name="sql">查詢內容</param><br>
''' <returns>回傳查詢結果的DataTable</returns><br>
''' <remarks>查詢資料庫並回傳查詢結果的DataTable</remarks><br>
Public Shared Function getTable(ByRef cn As SqlConnection, ByRef sql As String, Optional ByVal isColseConn As Boolean = True) As Data.DataTable<br>
Dim da As New SqlDataAdapter(sql, cn)<br>
Dim dt As New Data.DataTable("dt_xml")<br>
Try<br>
If cn.State = ConnectionState.Closed Then cn.Open()<br>
da.SelectCommand.CommandTimeout = 36000000<br>
da.Fill(dt)<br>
Catch ex As Exception<br>
If isColseConn And cn.State = ConnectionState.Open Then cn.Close()<br>
Throw ex<br>
End Try<br>
If isColseConn And cn.State = ConnectionState.Open Then cn.Close()<br>
Return dt<br>
End Function<br>
<br>
''' <summary><br>
''' 執行命令<br>
''' </summary><br>
''' <param name="cn">連線</param><br>
''' <param name="sql">查詢內容</param><br>
''' <returns>回傳受影響的資料筆數</returns><br>
''' <remarks>執行命令並回傳受影響的資料筆數</remarks><br>
Public Shared Function doCmd(ByRef cn As SqlConnection, ByRef sql As String, Optional ByRef param() As SqlParameter = Nothing, Optional ByVal isColseConn As Boolean = True) As Integer<br>
Dim result As Integer = 0<br>
Dim cmd As New SqlCommand<br>
Try<br>
cmd.Connection = cn<br>
cmd.CommandText = sql<br>
If Not param Is Nothing Then<br>
cmd.Parameters.AddRange(param)<br>
End If<br>
cmd.CommandTimeout = 36000000<br>
If cn.State = ConnectionState.Closed Then cn.Open()<br>
result = cmd.ExecuteNonQuery()<br>
Catch ex As Exception<br>
cmd.Parameters.Clear()<br>
If isColseConn And cn.State = ConnectionState.Open Then cn.Close()<br>
Throw ex<br>
Finally<br>
cmd.Parameters.Clear()<br>
If isColseConn And cn.State = ConnectionState.Open Then cn.Close()<br>
End Try<br>
Return result<br>
End Function<br>
<br>
<br>
''' <summary><br>
''' 取得單一資料<br>
''' </summary><br>
''' <param name="cn">連線</param><br>
''' <param name="sql">查詢內容</param><br>
''' <returns>回傳受影響的資料筆數</returns><br>
''' <remarks>執行命令並回傳受影響的資料筆數</remarks><br>
Public Shared Function doScalar(ByRef cn As SqlConnection, ByRef sql As String, Optional ByRef param() As SqlParameter = Nothing, Optional ByVal isColseConn As Boolean = True) As Object<br>
Dim result As Object = Nothing<br>
Dim cmd As New SqlCommand<br>
Try<br>
cmd.Connection = cn<br>
cmd.CommandText = sql<br>
If Not param Is Nothing Then<br>
cmd.Parameters.AddRange(param)<br>
End If<br>
cmd.CommandTimeout = 36000000<br>
If cn.State = ConnectionState.Closed Then cn.Open()<br>
result = cmd.ExecuteScalar()<br>
Catch ex As Exception<br>
cmd.Parameters.Clear()<br>
If isColseConn And cn.State = ConnectionState.Open Then cn.Close()<br>
Throw ex<br>
Finally<br>
cmd.Parameters.Clear()<br>
If isColseConn And cn.State = ConnectionState.Open Then cn.Close()<br>
End Try<br>
Return result<br>
End Function<br>
<br>
Public Function executeStoredProcedure(ByRef cn As SqlConnection, ByVal procedure As String, Optional ByRef param As SqlParameter() = Nothing, Optional ByRef output As SqlParameter() = Nothing, Optional ByVal isColseConn As Boolean = True) As Integer<br>
Dim result As Integer = 0<br>
Dim cmd As New SqlCommand(procedure, cn)<br>
Try<br>
<br>
cmd.CommandText = procedure<br>
cmd.CommandTimeout = 36000000<br>
cmd.CommandType = CommandType.StoredProcedure<br>
If Not param Is Nothing Then cmd.Parameters.AddRange(param)<br>
If Not output Is Nothing Then<br>
For Each o As SqlParameter In output<br>
o.Direction = ParameterDirection.Output<br>
Next<br>
cmd.Parameters.AddRange(output)<br>
End If<br>
<br>
'開啟資料庫連線<br>
If cn.State = ConnectionState.Closed Then cn.Open()<br>
'設定變數儲存受影響資料列<br>
result = cmd.ExecuteNonQuery()<br>
Catch ex As Exception<br>
cmd.Parameters.Clear()<br>
If isColseConn And cn.State = ConnectionState.Open Then cn.Close()<br>
Throw ex<br>
Finally<br>
cmd.Parameters.Clear()<br>
If isColseConn And cn.State = ConnectionState.Open Then cn.Close()<br>
End Try<br>
Return result<br>
End Function<br>
End Class<br>
<br>
<br>
</code></p>
<h4>使用範例程式</h4>
<p><code> Dim connStr1 As String = DBGenFunc.getConnStr("MSSQLDB1")<br>
Dim sourceTable As String() = {"[" & DBGenFunc.getDBName("MSSQLDB1") & "].[dbo].[" & "MyTestTab" & "]", _<br>
"[" & DBGenFunc.getDBName("MSSQLDB1") & "].[dbo].[" & "MyContentTab" & "]"}<br>
Dim param() As SqlClient.SqlParameter = {New SqlClient.SqlParameter("P0", SqlDbType.VarChar)}<br>
Dim sql As String<br>
<br>
Dim title As String<br>
<br>
Console.WriteLine("doCmdScalar Start:")<br>
sql = "SELECT Title" & vbCrLf & _<br>
" FROM " & sourceTable(0) & "" & vbCrLf & _<br>
" WHERE SN=@P0"<br>
param(0).Value = 1<br>
title = DBGenFunc.doCmdScalar(connStr1, sql, param)<br>
Console.WriteLine("doCmdScalar" & vbTab & title)<br>
<br>
Console.WriteLine("getTable Start:")<br>
sql = "SELECT Title" & vbCrLf & _<br>
" FROM " & sourceTable(0) & "" & vbCrLf<br>
Dim dt As DataTable = DBGenFunc.getTable(connStr1, sql)<br>
For Each r As DataRow In dt.Rows<br>
title = r.Item(0)<br>
Console.WriteLine("getTable" & vbTab & title)<br>
Next<br>
<br>
Console.WriteLine("getTableToArray Start:")<br>
Dim data As String() = DBGenFunc.dataTableToArray(Of String)(dt, 0)<br>
For Each r As String In data<br>
title = r<br>
Console.WriteLine("getTable" & vbTab & title)<br>
Next<br>
<br>
Console.WriteLine("doCmd Start:")<br>
sql = "INSERT INTO " & sourceTable(0) & "" & vbCrLf & _<br>
"VALUES(@P0,@P1)"<br>
param = New SqlClient.SqlParameter() {New SqlClient.SqlParameter("P0", SqlDbType.VarChar), _<br>
New SqlClient.SqlParameter("P1", SqlDbType.VarChar)}<br>
param(0).Value = "TNew"<br>
param(1).Value = "SNew"<br>
title = DBGenFunc.doCmd(connStr1, sql, param)<br>
Console.WriteLine("doCmd" & vbTab & title)<br>
<br>
Console.WriteLine("getReader Start:")<br>
sql = "SELECT Title, Subject" & vbCrLf & _<br>
" FROM " & sourceTable(0) & "" & vbCrLf<br>
Dim dr As SqlClient.SqlDataReader = DBGenFunc.getReader(connStr1, sql)<br>
While dr.Read()<br>
title = dr.Item(0)<br>
Console.WriteLine("getReader" & vbTab & title & vbTab & dr.Item(1))<br>
End While<br>
DBGenFunc.closeReader()</code></p>
<h4>執行結果</h4>
<p><code>doCmdScalar Start:<br>
doCmdScalar T1<br>
getTable Start:<br>
getTable T1<br>
getTable T2<br>
getTable T3<br>
getTable TNew<br>
getTableToArray Start:<br>
getTable T1<br>
getTable T2<br>
getTable T3<br>
getTable TNew<br>
doCmd Start:<br>
doCmd 1<br>
getReader Start:<br>
getReader T1 S1<br>
getReader T2 S2<br>
getReader T3 S3<br>
getReader TNew SNew<br>
getReader TNew SNew</code></p>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com2tag:blogger.com,1999:blog-2698062899592178296.post-33049539948811968852009-03-12T20:23:00.000-07:002011-04-17T19:28:05.258-07:00[筆記]我的FireFox愛用套件<h4>序言 <br></h4>
<p>此篇記下我常用的套件相關連結,方便安裝使用。 <br></p>
<h4>清單<br></h4>
<ol>
<li>FireFox主程式(我都用Portable版不用安裝):<br><a class="snap_append_preview" target="_Blank" href="http://portableapps.com/apps/internet/firefox_portable/localization">FireFox Portable by portableapps.com</a></li>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-TW/firefox/addon/2410">Foxmarks</a>:<a class="snap_append_preview" target="_Blank" href="http://www.foxmarks.com/">官網</a>。書籤同步,可至官網直接登入瀏覽你的書籤。</li>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-tw/firefox/addon/firegestures">FireGestures</a>:滑鼠手式(控制上一頁下一頁等)。</li>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-tw/firefox/addon/quickdrag/">QuickDrag</a>:用拖曳手勢更容易地在新分頁裡打開連結、搜尋文字和儲存圖片。</li>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-TW/firefox/addon/6113">新同文堂</a>:<a class="snap_append_preview" target="_Blank" href="http://of.openfoundry.org/projects/333">官網</a>。中文繁簡體互轉工具。</li>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-TW/firefox/addon/1122">Tab Mix Plus</a>:<a class="snap_append_preview" target="_Blank" href="http://tmp.garyr.net/">官網</a>。分頁加強版。</li>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-tw/firefox/addon/mozilla-archive-format/">Mozilla Archive Format</a>:MHT (MHTML) 檔案開啟外掛。</li>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-TW/firefox/addon/605">Copy Links</a>:方便複製連結。</li>
<li><a class="snap_append_preview" target="_Blank" href="http://facepad.en.softonic.com/download#pathbar">FacePad</a>:Facebook相簿下載(安裝後於相簿連結點右鍵可以看到功能)。</li>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-TW/firefox/addon/748">Greasemonkey</a>:<a aiotitle="官網" href="http://www.greasespot.net/">官網</a>。客製化網頁Script功能。搭配以下Script。</li>
<ul>
<li><a class="snap_append_preview" target="_Blank" href="http://userscripts.org/scripts/show/75918">Plurk Smile</a>:plurk表情外掛。</li>
<li><a class="snap_append_preview" target="_Blank" href="http://userscripts.org/scripts/show/39186">RePlurk</a>:plurk轉發。</li>
<li><a class="snap_append_preview" target="_Blank" href="http://userscripts.org/scripts/show/9116">RS_Bundle</a>:方便下載Rapidshare。</li>
<li><a class="snap_append_preview" target="_Blank" href="http://userscripts.org/scripts/show/44105">MU Bundle</a>:方便下載Megaupload。</li>
<li><a class="snap_append_preview" target="_Blank" href="http://userscripts.org/scripts/show/21774">Download ANY Video from YouTube</a>:方便下載YouTube。</li>
<li><a class="snap_append_preview" target="_Blank" href="http://userscripts.org/scripts?sort=installs">其他熱門Script</a></li>
</ul>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-TW/firefox/addon/220">FlashGot</a>:<a class="snap_append_preview" target="_Blank" href="http://flashgot.net/">官網</a>。搭配其他下載工具用。</li>
<li><a class="snap_append_preview" target="_Blank" href="http://pcmanfx.openfoundry.org/">PCmanfx</a>:<a class="snap_append_preview" target="_Blank" href="http://pcmanfx.openfoundry.org/">官網</a>。上BBS。</li>
<li><a class="snap_append_preview" target="_Blank" href="https://addons.mozilla.org/zh-TW/firefox/addon/9452">Profile Manager and Synchronizer </a>:多帳號登入。</li>
</ol>倫倫3號http://www.blogger.com/profile/07296292522311254178noreply@blogger.com0