2011年5月31日 星期二

TortoiseSVN的圖示

TortoiseSVN是一套結合在Windows作業系統
右鍵選單中的SVN Client軟體
它對於SVN版本控制的各種狀態有相對應的圖示(icons)

下圖是從說明手冊中截取的各圖示意義











這裡則是TortoiseSVN的說明手冊頁
共有18種語言版本可以選擇

版本控制

工作之前
程式的檔案就是放在一個資料夾
自己修修改改
有時發現這樣的思考架構不對
想要回到前前前一次的版本
只能靠文字編輯器的還原功能來達成

工作之後
一分程式每個人都可能會改到
所以你會想把程式移到大家都可以存取的地方
可能是一台與網路連接且獨立機器
然後大家連到那台機器上存取程式碼

接著你想到要回復程式版本
還要慢慢還原
真是太蠢的方法
如果那台獨立的機器
可以提供記錄版本的功能
以供我們隨時存取各版本
那就是太美妙了

所以版本控制的概念就由此而生
我自己以為他出生的原因
是因為以下兩個需求
1.程式放在大家都可以存取的地方
2.能夠記錄程式的版本, 以備還原或查閱需要

之前公司用Rational ClearCase
現在用Subversion(前身為CVS)
這兩套在操作上與指令意義上略有不同
例如
ClearCase:
執行"Update"下載檔案到本機,  以後要更新本機檔案也是執行"Update". 下載後, 檔案是上鎖住狀態, 且本機的檔案在下載後都是唯讀, 必須再執行"Check-Out"才能將該程式解鎖, 並且將本機檔案變成可讀寫狀態, 進行編寫. 編寫完檔案後, 再將檔案做"Check-In"將檔案上傳到版本控制的Server, 並且上鎖, 從而將本機檔案又恢復成唯讀. 版本控制的Server裡的檔案, 一開始時先上鎖, 且本機的複本檔案是唯讀. 使用者要編寫時, 再執行Check-Out, 可以同時做解鎖與恢復讀寫. 編寫完成後, 再執行Check-In. 同時做上鎖與恢復唯讀.
Subversion:
執行"Check-Out"下載檔案到本機, 以後要更新本機檔案變成執行"Update". 下載後, 檔案是未鎖住狀態, 且本機的檔案在下載後都是可讀寫狀態. 使用者可以直接編寫檔案. 編寫完檔案後, 再將檔案做"Update"將檔案上傳到版本控制的Server. 版本控制的Server裡的檔案從未上鎖, 而本機的複本檔案也從未變成唯讀.

個人認為ClearCase的運作模式較佳
因為一開始強制上鎖
待有修改需要才由個人去解鎖以"借出"做修改
可以確保同一時間, 只有將程式借走的人可以修改該程式
而Subversion沒有強制上鎖
可能會發生你改我也改同一版本的程式
造成後來上程式的人, 會把前一個人修改地方蓋掉的風險.

阿~沒想到題外話說了這麼多
其實我是想要說
最近電腦換成64位元,
很多本來在32位元作業系統上, 安裝與操作都很順利的應用程式,
卻變成坎坷難行....要一直去找他64位元的版本.

阿然後我在eclipse裡用的svn client是Subclipse(有另一個相似的叫Subversive)
在64位元電腦上一直使用失敗
出現"unable to load default svn client"的訊息
Google了一下
應該是出在Subclipse所使用的svn client有問題
推估也是不支援x64吧
這個解決方法是
1.安裝64位元的JavaHL
2.安裝SVNKit

我採用2.去解決
結果沒反應
改採1.去解決
去下載安裝Silk SVN
(我猜他底層也是用JavaHL, 且提供的是64位元版本)
然後把eclipse關掉重開
結果就成功不會有錯誤訊息啦~哈哈

我逛了一下Silk SVN網站
發現他是一家提供SVN Repository的廠商
免費的使用者可以有100MB的空間來放你的程式
如果想要1000MB, 就要付出一個月4.95歐元(約台幣205元)的代價
最大的是10000MB, 一個月足足要19.95歐元(約台幣825元)呢!!

2011年5月30日 星期一

EL裡面是否可以再使用JSP expression?

今天有個JSP如下:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "
http://www.w3.org/TR/html4/loose.dtd">
<html>

<body>
<%
String a = "Apple";
%>
<c:out value="${'Apple'}"/>
<br/>
<c:out value="<%=a%>" />
<br/>
</body>
</html>


它的結果會是:
Apple
Apple

因此知道要在JSTL中表達literal
可以用
1.EL表示: ${'Apple'}
2.JSP expression元素: <%=a%>

那可不可以用EL+JSP expression咧?
像是這樣:
<c:out value="${<%=a%>}"/>
答案是:.
.
..
...
不行, 你會得到這樣的一個例外:
org.apache.jasper.JasperException: /A.jsp(13,0) "${<%=a%>}" contains invalid expression(s): javax.el.ELException: Error Parsing: ${<%=a%>}--
結論:
1.JSTL裡面的literal可以用JSP expression或EL來表示
2.EL中不要再使用JSP expression, 否則會出現錯誤.

2011年5月29日 星期日

Tomcat 7中設立目錄列表和錯誤處理頁面

如果你在瀏覽器輸入一個網址
例如http://localhost:8081/Apple/
你並沒有再指定任何特定的資源名稱
例如一個servelt url pattern
或真實檔名的jsp, html, jpg等
那這時web container會如何反應?

答案是會先找有無welcome-file-list
再找有無開放directory listings
如果以上兩者都沒有
瀏覽器會顯示HTTP Status 404

這兩個設定值
都可以在下列檔案進行設定:
Tomcat 7的安裝目錄/conf/web.xml
該檔定義了該Tomcat安裝版本底下
所有web應用程式共用的初始參數

1.welcome-file-list
在該檔中, 尋找下列標籤
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
這是預設的歡迎頁面
只要在各應用程式的根目錄中
有這些檔案
則在沒有特別指定資源名稱的情況下
就會導到這些指定的歡迎頁面

如果, 你又在應用程式自己的WEB-INF/web.xml中
再次設定了welcome-file-list
則就會置換掉Tomcat 7的安裝目錄/conf/web.xml
裡面指定的welcome-file-list版本

2.directory listing
在該檔中
尋找下列標籤
    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
這是一隻"預設"(名稱是default ^_^)的servlet
可以讓web container列出目錄下的所有檔案
如下圖所示















不過, 不建議這樣做
原因如下:
1.會浪費server資源去產生這份list
2.應用程式中可能有些機敏資料, 你不想被看光光, 並被直接存取.

--
如果瀏覽器指定了url卻沒有指定資源名稱
並且沒有設定welcome-file-list
也沒有開放directory listing
那就只能義無反顧地顯示HTTP Status 404了

上圖為Tomcat的預設404畫面
其實我們可以加以客製化
透露出更多的訊息

只要在應用程式的WEB-INF/web.xml中
加入以下標籤
<error-page>
<error-code>404</error-code>
<location>/NotFound.html</location>
</error-page>
就可以指定發生HTTP 404時
web container要回傳的頁面
可以是html也可以是jsp
上例中/NotFound.html是說
請在該應用程式的根目錄底下
尋找NotFound.html這檔案
根據網路上的資料
斜線 / 不可缺少

網路上搜尋到這個網站
裡面就有一些有趣的客製化HTTP 404網頁
還教你如何製作出一個好的HTTP 404頁面
並且還引當你遇到404頁面時
應該如何做, 才能找到你想要的東西
很值得一看哦!!







2011年5月27日 星期五

在win7 x64上使用VPN

自從公司電腦從win7 x86換成了win7 x64後
本來在使用的 cisco vpn client 就無法安裝
雖然聽說64位元的作業系統, 依然可以安裝32位元的應用程式
例如win7 x64版本裡, 在系統碟除了原本的Program Files資料夾外
還多了一個Program Files (x86)資料夾

所以看來應該是只有部分的32位元應用程式
可以在x64的機器上跑

對了, 這裡說的 x86 = 32位元
而 x64 = 64位元
x86或x64應該都是指Intel的CPU型號
(其中x64亦可稱為x86-64)

於是我直接去CISCO的網站上下載
發現真的有for win7 x64的版本ㄝ
超高興
可是他下面有說, 必須是付費的使用者
才可以下載
冏!!

後來找到這篇文章
對岸有人找到檔案下載的連結
我下載測試後
真的可以在win7 x64上運作無誤
文章中也提到cisco網站不提供給我們這些草民下載
唉~有錢的是老大咩~

或者你因此看不起cisco的財大勢大
也可以用其他的vpn client端軟體
來嘗試連接到原本使用cisco vpn client連線的網路
我沒有試過
據說也可以連線成功
不過好像要從本來的cisco vpn client去匯入一些檔之類的
像是這篇文章中提到的Shrew Soft 的 VPN Client ,  NCP Secure Entry Client
還有其他人提到的OpenVPN

2011年5月25日 星期三

用java.net.URL建立連線注意事項

java.net.URL是java內建的類別
能幫助程式去取得網路上的資源
以http封包發送request封包給站台
再從站台收到response

今天在測試時
發現你使用此類別建立連線
URL的openConnection()會回傳一個URLConnection物件
該物件一直都不會送出request封包
直到你呼叫他的getHeaderField()或getInputStream()等getter方法
才會送出request封包

我嚐試如果都不用getter方法
用connect()方法也是不行
可能是因為該方法是抽象的abstract
然後URL的openConnection()方法所回傳的URLConnection實作物件
(呼叫該物件的.getClass().getName方法, 得知是個HttpURLConnection類別的物件)
又沒有覆寫該方法所致

所以我剛去看了一下JAVA API
發現URLConnection本身是個abstract class
abstract class的意思是有些方法可以沒有身體
(interface的話就全部都不能有身體)
而繼承他的HttpURLConnection也是個abstract class
並且真的沒有加以定義connect()

所以要是你想要用java.net.URL
讓你的程式和網路上的資源取得連線
呼叫connect()方法是沒用的, 他目前還是個空殼
(或許以後版本的java會為他填一些內容)
記得要呼叫URLConnection類別的getter方法
這樣才會真的把request封包送出去!!

2011年5月23日 星期一

以HTTP下載WORD文件會卡住

近來碰到一個怪狀況
有個WORD文件放在HTTP伺服器上
我連結到那邊去
比如說 HTTP://站台1號/A.DOC
就會下載A.DOC

瀏覽器提示訊息
問我要存在哪裡
選好地方後按確定
可是大概1MB大小的WORD文件
下載進度是卡住狀態
如果是IE
你看它下載進度列
一直都是0
大概要五分鐘後
才瞬間下載完成

有趣的是,
如果我把該檔案
放到HTTP://站台2號/A.DOC
站台1和2號是不同台的機器
則A.DOC馬上就可以下載完成

不論是站台1號或2號
下載的檔案都是同一份
也可以順利正常地開啟編輯
差別在1號站台會先卡住一段時間才能下載

上網搜索有無案例
可惜無所獲
解決之道:
我將此WORD文件內容全選並複製
新增一個空白的WORD文件
把複製的內容貼上
再存檔, 檔名也一樣
然後位置存在其它本機的目錄下

發現存檔完成後的檔案大小
竟然比原始檔案要小上49KB
但是兩者內容完全一樣
我還印出來比對 沒有缺少什麼文字或圖檔

但是它就是小了一些,
看來是有一些肉眼無法看建的物件在搗亂呀~
將此新檔再上傳到站台1號
原先下載會卡住的狀況
就從此消失了

結論:
會發生下載檔案時
卡住很久才可始的狀況
跟檔案的建立的方式有關
可能當初建立時, 產生了些異常物件
這些物件並不影響WORD文件內容
卻會與某些站台的軟硬體架構相沖
造成下載時卡住
或者產生: HTTP Error 502 Bad gateway

解決方式
就是全選->複製
將文件內容轉貼到一個新的檔案
以消除此一不明物件

2011年5月19日 星期四

從資料庫一次取太多筆會造成AP SERVER記憶體空間不夠

記得以前在金融公司資訊部上班時
金融業都很講求效率
比如在資料庫下SQL, 不能執行太久,
否則DB的效能都被你吃完, 別人就吃得少或吃不到了
所以每個星期會公布SQL COST前五名的SQL
以茲獎....哦不, 是以茲改進
改進的方式是改變SQL的本身
通常都是條件下得不夠漂亮
或者真的資料量爆大
必須要增加INDEX
或者是根本沒有條件
造成他一次取回資料表的全部資料
這也是今天的主題

如果一次取回的資料太多筆
則不但DB會效能低落
連AP SERVER也是
那時如果一次取十萬筆資料回來
AP SERVER會發出OUT OF MEMORY的錯誤訊息
因為你取資料回來時
是以RESULTSET的型式放在AP SERVER上
取回的東西多, RESULTSET就越大到記憶體空間不足

在DB層面也是
操作DBMS時, 比如TOAD
對一個有龐大資料的資料表
如果直接下SQL不加任何條件
那它顯示查詢結果畫面的時間
就會處理得很久
你可以想像從一家滿滿的麵包店拿十個麵包
跟掃光全店的所有麵包
哪個時間會花得比較久?

所以我們知道不能"一次"取"太多筆"資料回來
否則會造成AP SERVER和DB這兩層TIER
處理速度變慢且記憶體不夠用

但是有時真的有這個需求, 怎辦
我就是有取大量資料的需求
這時可以透過JDBC裡定義的executeBatch()
它先將所有要執行的語句用addBatch()加入容器中
最後executeBatch()時就一次送出全部的句子

之前上課聽老師說
有人執行大量的資料庫異動
用傳統的execute()花了一個星期還沒好
使用了executeBatch(), 十個小時就好了

但是這個executeBatch()可以拿來做批次異動
卻好像不適用於select語法??
之前公司有個套件
你可以設定每次要取回的資料筆數
它會自動當你分成一批一批地取回
也避免了一次取大量資料的問題
只是不知道JDBC有無對應的現成方法?

2011年5月18日 星期三

web Application的session中斷

因為http協定是stateless
stateless的意思指它不記得狀態
因使你在逛下一頁時
它沒有辦法知道你上一頁在幹嘛

因此
我們需要session機制來輔助
它的作用原理是client(一般情況下, 指的是瀏覽器)
向server(指web container, 如tomcat)
發送請求封包後
web container端便會檢查該封包是否有cookie資訊
再檢查裡面是否帶有JSESSIONID這樣的參數
如果有
則取回原session
沒有的話
web container會給null或新的session
這要視你程式寫法而定
servlet可以選擇要null或新的session
但是jsp一定是新的session

建立了session之後
使用者資訊都被存在裡面
直到session中斷

session中斷有兩個方式:
1.使用者關掉瀏覽器, 使得client端"忘了"它的JSESSIONID.
2.server端web container的session timeout. 以tomcat為例, 預設是30分鐘.
但是各專案可以自己設定, 在web.xml中加入以下標籤
<session-config>
<session-timeout>10</session-timeout>
</session-config>
就會將時間設為10"分鐘"
亦可以每個專案底下的session都設定不同timeout時間
setMaxInactiveInterval(int interval)
(注意這裡interval的時間單位是"秒", 和web.xml裡設定的"分鐘"不一樣!)

還記得小時後去超市
都要在櫃台寄放包包
它會給你一個號碼牌
購物完出來再憑此號碼排拿包

可以用這個拿包來比喻session中斷情況:

:包包(session)依然在櫃台(指server), 但client端沒有了號碼牌, 所以無法提取, 等於沒有包包.
分析: 這樣的狀況會在server端留下無用的seesion資料, 因為再也沒辦法被存取到.
(除非有心人士去改了他本機cookie裡面的JSESSIONID資訊.)
因為沒辦法被存取到, 等於留了很多垃圾, 很佔記憶體空間. 有時你會在櫃台看到上次你來就有的包擺在那, 佔了一個儲存格空間.
:client端依然有號碼牌, 但是購物逛太久, 超過預設保管時間30分鐘沒來拿, 所以櫃台自動把包包銷毀.......
分析:server端不會留垃圾下來, 還可以接受.

:client端沒有號碼牌, 櫃台也已銷毀包包
分析:很好大家都沒遺憾了~

一般認為只要瀏覽器關掉
session就結束
其實只是JSESSIONID不見了
但是session資料仍然留在server端佔空間

為了替server著想
建議大家下次逛網站時
如果該網站有登入機制
記得好心一點按登出
這樣可以幫網站減少一點負擔哦!

Toad for Oracle的Import Utility Wizard, 有個畫面寫錯啦~

以前公司的資料庫是用IBM DB2
那時我們裝的DBMS就是Toad
然後現在使用是Oracle
再去逛Toad發現原來Toad有為各DB推出對應的DBMS
Toad在網路上搜尋一下
名聲還滿高的
所以這次就使用了Toad for Oracle

我們知道SQL語法各家DB廠商都略有不同
所以如果你用ORM框架
例如知名的Hibernate, 它會自動幫你將操作物件的動作
轉成各DB適用的SQL
所以這大概也是這類ORM框架受歡迎的原因之一
不過這是題外話

這次工作上有需要將遠端A資料庫下甲使用者所有TABLE的資料
備份到本機B資料庫
所以研究了一下Oracle的匯出匯入指令
在電腦有安裝Oracle DB的情況下
像我是安裝Oracle Database 10g Express Edition Release 10.2.0.1.0
就可以在命令列輸入exp或imp
然後它自動會引導你完成後續動作
滿方便的
像是命令列精靈一樣

接著再研究到Toad for Oracle
嗯嗯~它也有匯出匯入功能
而且是視覺化精靈
一步一步引導你完成步驟
比命令列好用許多

我執行備份的步驟
1.在Toad for Oracle
先選擇A資料庫的連線
工具列->Database->Export->Export Utility Wizard,
然後選擇匯出TABLE
照著精靈指示操作後
最後會得到*.DMP檔案
(我猜DMP的全名是 DATA DUMP)
2.再選擇B資料庫的連線
工具列->Database->Import->Import Utility Wizard,
一樣選擇匯入TABLE
(其實它的選項還有匯入User, 匯入Tablespace等.
不過既然當初匯出Table, 這裡當然就是選匯入Table啦!)
然後選擇要匯入的檔案, 接著就開始執行
--由於我的B資料庫原本空無一物
所以匯入時, 會順便建立 TABLE
以及TABLE的資料
(如果欲匯入的TABLE已存在於B資料庫了,
會發生什麼事?
答:還沒研究到那....
20110610更新:資料會附加在既有資料後面
如果有一模一樣的, 則該筆資料會匯入失敗
例如以下錯誤訊息:
. 正在將 TESTLA 的物件匯入 TESTLA 中
. . 正在匯入表格                       "TESTLA1"
IMP-00019: 資料列遭拒由於發生 ORACLE 錯誤 1
IMP-00003: ORACLE 錯誤 1 發生
ORA-00001: 違反必須為唯一的限制條件 (TESTLA.TESTLA1_PK)
資料欄 1 Steven
資料欄 2 Jay      

匯入了                                                             0 列
已順利終止匯入作業, 但含有警告.

後來google到有人說這種匯入方式是用sql的insert句子執行的
所以效率慢且無法選擇你要replace還是append等匯入模式

但oracle 10g後多了另外一種匯入匯出的功能: Data Pump
可以提升匯入匯出的速度
並且可以自行選擇要匯入的選項, 有
skip: 如已存在就跳過處理下一筆
append: 附加在現有資料後面
replace: 如已存在取代現有資料
truncate : 如已存在則砍掉現有資料再新增
參考來源: 這裡那裡

所以做個總結吧!
Import/Export Utility Wizard ->用傳統的insert語句達成, 速度較慢, 無法選擇匯入方式, 參數較少較簡單
Data Pump Import/Export Wizard ->用某種神秘的技術加速匯入匯出速度, 可以選擇四種匯入方式, 參數較多較複雜, 執行的使用者最好需具備DBA的權限, 因為過程中會建立資料夾之類的
)

今天的標題是:
Import Utility Wizard, 有個畫面寫錯啦~

就是在選擇匯入檔案時
它老兄給我出現下列這個圖















紅框處它竟然寫Export file name
害我覺得很疑惑
阿現在是說, 他會自動從A資料庫匯出一個檔
然後再自動將此檔匯入到B資料庫
所以現在是要我選擇匯出的檔案名稱嗎?
(功能這麼強大?)

可是當我看到另一個紅框處標示的"Open",
我就釋懷了
這的的確確是要我選擇Import file name.
所以畫面上的Export file name完全是筆誤

2011年5月15日 星期日

web.xml中的load-on-startup標籤

在寫WEB應用程式時
web.xml這個檔很重要
他記載了該應用程式所需要被使用到的資源

例如: Servelet, Filterk 和 Listener等
你光有程式還不行
必須還要再web.xml中加以登記
Web Container, 例如Apache Tomcat, IBM WebSphere, 在啟動時
才會找到該類別

這裡我只有講"找到", 但是並沒有講"載入"
是因為載入的時機有兩個
一個是Web Container啟動時
另一個就是該Servlet第一次被使用時
Web Container會自己選擇該怎樣載入
但無論如何
該Servlet的instance一定會在被使用前就準備好
(準備好後並不是會一直在那
例如空間不夠用時
Web Container可能會把一些已建立好的instance砍掉
但Web Container保證一定會在下一次該Servlet被使用前
先把它的instance準備好
)

於是如果今天想要強迫Web Container啟動時
1.就要載入特定的Servlet
2.並且指定載入的順序
那麼就需要<load-on-startup>標籤了

他的使用方式
是夾在<servlet>之間
例如:

<servlet>

<servlet-name>abc<servlet-name>

<servlet-class>my.abc</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>
 
至於<load-on-startup>的內容, 是一個整數. 可以正, 可以負, 也可以是0,
在網路上人家說J2EE Specilization 裡面有這一段
介紹這個標籤的用法
:(但是我找不到原文出處)
 
The load-on-startup element indicates that this servlet should be loaded (instantiated and have its init() called) on the startup of the web application. The optional contents of these element must be an integer indicating the order in which the servlet should be loaded. If the value is a negative integer, or the element is not present, the container is free to load the servlet whenever it chooses. If the value is a positive integer or 0, the container must load and initialize the servlet as the application is deployed. The container must guarantee that servlets marked with lower integers are loaded before servlets marked with higher integers. The container may choose the order of loading of servlets with the same load-on-start-up value.


上面這段內容說
1.如果<load-on-startup>的內容是0或正的整數, Web Container會依由小到大的順序, 來載入並初始話該Servlet. 於是載入順序就是: 0->1->2->3
2.如果<load-on-startup>的內容是負的整數, 或是沒有內容. 那Web Container就會自行選擇載入時機.

但是如果有兩個Servlet都是標示為2,
那順序是誰先誰後呢?

經過我的測試
是每次都不一樣.
因為我有兩個Servlet, 姑且稱為A和B
A是proxool連接池, 用來載入連接池設定檔的Servlet
然後B會利用 DriverManager.getConnection("proxool.example")來獲取資料庫連線
想當然爾
A必須要先載入->初始
然後B才能利用proxool.example這樣的別名
去取得連線,
否則會出現找不到對應的Driver訊息.

我試了幾次
有幾次B連線成功
有幾次連線失敗

後來把B的<load-on-startup>改為3
則無論試了N次都能連線成功

所以結論就是:
如果兩個Servlet的載入有相依關係
務必讓它們的<load-on-startup>值改為一前一後