2007年6月28日 星期四

聰明的男人、女人與傻男女

聰明的女人選擇會願意愛自己一輩子的男人;
聰明的男人選擇會願意照顧、呵護一輩子的女人;
傻男女則是除了會做出聰明男女相反的選擇外還會犯一個相同的錯誤!
「愛不對人!!!」

Read More......

2007年6月27日 星期三

求婚大作戰-最終回:打開奇跡之門


這是 健 與 禮 小時候的一段話。
健:「我會負責的,會一輩子照顧禮的」
禮:「拜託你了!」

妖精對著健說:「
你要繼續尋找奇跡之門啊!
無論如何都想改變命運,
唯有這樣持續祈禱方能開啟奇跡之門,
打開那道門的鑰匙就在你心中,
只是你沒注意到罷了。


回顧過往 健 與 禮 的對話。
健:「人生裡有沒有想要重新來過的時候,有沒有後悔的事情」
禮:「我啊,高中的時候一直在想,我們為什麼是青梅竹馬呢?如果不是青梅竹馬的話,可能會更加坦率一些吧!可能就不用這麼痛苦地一直暗戀了。想了很多,但我明白了是不應該否定這一點。想著雖然那個時候覺得很痛苦,很失敗,但如果沒有這一點的話,就沒有今天的我在這裡笑著。這麼想就覺得沒有什麼值得後悔的事情。我覺得能和健認識真的太好了!是不是覺得現在我很少見的坦率一回了呢!雖然知道以後還有各種各樣的事,只有健的存在是永遠不變的。雖然到現在在健的面前一直不能坦率,但是我覺得因為有健,才會有現在的我。謝謝你!真的很感謝你!」
健心想:「禮沒有後悔過去,而是活在當下,接受了過去的一切,毫不動搖地活在當下。對於想要重新來過的我來說,禮的純潔,十分耀眼,刺痛了心裡。為什麼小時候,那麼容易就能辦到的事情,越長大就變得越困難呢?跟失敗比起來,根本沒有做的後悔會痛苦好幾倍。現在目的地不知道是否有奇跡的大門,但覺得應該試著想相信我自己。」

回到現實 妖精為健 準備了最佳的舞台。
妖精:「
重要的,不是感嘆過去的現在,而是改變現在,面向未來的意志。
我為你準備了,總算能表達自己回到過去,經歷拼命磨練的痛苦洗練的答案合適的地方。
祈願吧!你祈願我就替你實現。
尋求吧!你尋求我就替你發掘。
叩門吧!你叩門我就替你打開。
好了,挺起胸膛,走下去!



婚禮上健的致辭。
健三:「
我和禮從小學開始就是同學,
昨天在小學畢業紀念冊上看到,禮在上面寫到將來夢想成為一個可愛的新娘,
現在看來對他可不可愛還有很多疑問,這暫且不論,總之她能實現自己從小的夢想
…………………………
雖然對不起多田先生,我想過如果禮放棄結婚就好了。
我也想過搶走禮,14年中,歡樂的時候也好、痛苦的時候也好、
難過的時候也好,都一起度過的禮。
真心覺得能讓他幸福的只有我,一點兒不順心就馬上鬧彆扭的禮、
因為我逃避掃除和工作而常常生氣的禮,倔強,一點兒也不坦率的禮。
最了解她的是我,看起來堅強,其實很細膩的禮。
自己的事總是放在第二位,比誰都重視朋友的禮。
一直在身邊的禮,最需要他的是我。
但是,最終只是在心裡想著,在禮面前從來沒有坦白過。
一直在身邊,想著隨時都可以說的話。
最終一次都沒有說出口。
只有那麼一句話,但是一次都沒有說出口。
我…我喜歡過禮。
說真的,現在也喜歡著禮!
但是,禮在今天和多田先生結婚了。
雖然很不甘心,但是他甘要結婚了。
禮的存在,在我的心裡十分重要。
這些話,為了說出口花了好長的時間。
禮,恭禧你結婚,請你過得幸福。
沒有幸福的話,不幸福的話,我可真的不原諒你哦!


禮內心的掙扎。
禮:「
我的身旁,總是有岩瀨健。
我的回憶,也總有著健的身影。
健的溫柔,總像無意間在哪兒繞了點路。
要稍稍慢一拍才會傳達給我…
如今的我才能察覺到那份笨拙的溫柔。
當時的自己,總是無法那麼坦率。
明明很開心卻說不出口。
好鄙視這樣的自己。
害怕被傷害,而沒能鼓起勇氣到最後的人…是我
沒能一直相信健的溫柔就中途放棄的人…是我
決定了不再回頭,就單方面閉上眼的人…也是我
健他總是一直在認真的投球,沒能好好接住的人…是我。
我們的人生,總是不斷錯過。
害怕再這樣繼續錯過
不要再搖擺,不要再猶豫
那時明明就決定了
要是…要是那時候
能對自己誠實一點的話
是不是就能把一直沒能說出口的話
"我喜歡你"這樣一句話…說出口了呢?


妖精給予禮的最後協助,打開奇跡之門。
妖精:「
J.S韋斯曾經說過
男人無法放棄初戀
女人則無法放棄最後的愛
曾有個男人展開一段重寫過去悔恨的旅程
他拼命努力想改變過去
無奈奇跡之門終究沒有打開
在旅程的最後他發現了
再怎麼改變過去,自己還是不會改變
於是他想到了,比起感嘆過去的現在
改變現在,面向未來的意志才是最重要的。
你不覺得,現在開始還來得及嗎?








Read More......

Liferay Portal單一使用者登入

在啟動Liferay後,如果同一個使用者連續開啟Browser進行登入後結果會是如何,真正實作後會發現,我們同樣使用test@liferay.com這個帳號進行二次登入後,在Session中會有二個Session的記錄,並且這二個同樣帳號的使用者可進行完全符合該帳號權限的操作,那我們要如何限制使用者帳號只能進行單一的登入呢?

圖:預設狀況下,同一使用者進行二次登入的結果。

如果手邊有LiferaySource Code的話,可以找一下,在原始碼[portal-ejbclassesportal.properties]中的設定。

portal.properties

#

# Set the following to true if users are allowed to have simultaneous logins

# from different sessions.

#

auth.simultaneous.logins=true

這個設定主要用途在於設定是否允許相同帳號的使用者同時間進行登入,換句話說就是允許同一使用者進行多次的登入,因為預設為true,所以才會有上述的狀況出現。

若不希望同一時使用者進行多次登入的話可將該設定改為false即可,但在原始碼中修改並不明智,畢竟你修改了預設的設定,比較聰明的方法為,在已經佈署的Liferay Portal上進行調整,你可以開啟[%LiferayPortal%webappsROOTWEB-INFclassesportal-ext.properties]這個延伸設定檔,在當中進行設定將會覆蓋掉預設的設定。將其修改為auth.simultaneous.logins=false後重新啟動liferay,再次進行二次相同帳號使用者登入。

實作後會覺得有些吊詭的情況,還是允許二次相同帳號的登入如下圖:

圖:還是一樣的狀況

但當我們將第一次登入帳號的Browser進行任何操作時將會發現出現結果如下:

圖:警告有相同的帳號用不同的Session登入。

這個意思就代表了第一次登入的使用者因為在之後已有其他相同的使用者進行了登入,因此被踢出了Portal系統。這時我們再檢查一次第二次登入的BrowserSession資訊:

圖:得到滿意的結果,因先前登入的User已被踢出,所以只有一個使用者登入。

好,最後我們來個結論,這個設定只會限制在Liferay Portal中無論使用PCIP為何,使用者只能進行單一的登入,這麼看來似乎很像達成了SSO( Single Sign On )單一使用者簽入的任務,但其實不然,SSO是基於多個系統的單一簽入,因此多個系統一定會共用一個驗證中心,有興趣的話可以找一下Liferay PortalCAS進行SSO的資料。在本例中,因為Liferay Portal只是單一一個系統,因此談不上SSO

Read More......

2007年6月25日 星期一

專家、高手與好顧問

專家只是訓練有素的狗、高手只是有好習慣的工程師…

而好顧問則是什麼事都沒做,卻用了影響力讓公司朝正確方向前進。

Read More......

(2006.04月號-147期)_實踐專案管理,使用Maven

在小型專案與一般於企業中建置的J2EE專案中,經常因導入的AP Server平台的不同而統一使用特定的IDE開發環境,例如:IBMWebSphere使用WSADOracleOC4J使用JDeveloperWebLogic使用Workshop等。

當進行大型專案開發,並分割出多數的系統模組都委外進行開發時,每一間委外廠商可能都使用不同的開發工具與IDE進行開發,因此如何管理、建置、佈署專案就是一門學問了。



而以往J2EE專案依IDE開發環境不同有不同的建置與佈署邏輯,而這些建置與佈署方式彼此並不相容,例如在WSAD建置的設定,無法移植至JDeveloperWorkshop使用,反之亦然,這對日後的維護上也將更形困難,我們沒辦法保證,當時開發時的IDE與目前維護時使用的IDE開發工具是相同的。


若欲將各模組委外進行開發,管理跨J2EE平台建置的大型專案,Ant是個很好的選擇,Ant可以撰寫腳本進行所有動作,要求委外廠商進行模組開發使用Ant也不是問題,因為目前業界大多數也是如此進行開發的。


但問題在於其Ant建構人員必須非常熟悉專案建置邏輯,並且善用一些開放原始碼元件協同進行開發、測試與佈署,若只是單純使用Ant基本腳本功能的話,則頂多也只是將原先手動進行複製、刪除、編譯、封裝JARWAREAR的動作轉為自動化而已,實質上並沒有太大的意義,還不如撰寫批次檔進行自動化來得簡單方便。


遺憾的是,於Ant中協同其他元件進行Ant功能的擴充並沒有想像中的簡單,參考設定 1中可以發現,於Ant中欲使用Cactus進行容器測試,必須進行以下步驟。


步驟1:首先必須於init中設定cactus的擴充標籤runservertests

步驟2testwar中進行原始碼的編譯與封裝。

步驟3prepare.test.tomcat.40中複製出tomcat環境並進行佈署。

步驟4test.tomcat.40中使用runservertests擴充標籤執行start.tomcat.40啟動tomcat、執行test進行容器測試、最後執行stop.tomcat.40關閉tomcat


基本上,建構人員並不想建置這麼複雜的設定、不想引入這些與專案原始碼無關並且只供測試用的jar檔、不想了解tomcat伺服容器的結構,更不用說怎麼去啟動與關閉tomcat了。但若專案欲於Ant上使用Cactus,這一切似乎是無可避免的,一旦加入的擴充元件愈多,Ant腳本將愈來愈複雜,目前Ant中只加入了tomcat的設定,試想當專案需要於WebLogicResinJBoss進行測試時,撰寫的Ant的腳本檔將會有多複雜與難以維護。


另外,在設定 1中我們也發現,多個專案中運行Cactus時的設定都是大同小異的,因此可以將其抽出作為template,並以ENTITY方式進行引入,於多個專案中使用。這是個很好的解決方案,解決了設定上的複雜性,卻還是免不了必須在專案中放置相依的jar檔,當建構範圍愈來愈大相依jar檔的管理也更加麻煩。更何況Ant中只包含建置邏輯的腳本,雖然目前在各IDE開發環境中幾乎都已支援Ant,但Ant並無法反向建置出各IDE開發環境的設定。


當使用版本控制程式進行管理時,相依jar檔愈多將使納入版本管理的程式愈顯龐大,但實際上該納入控管的只有原始碼而已,所有jar檔應該抽出並且共用才對。而若將IDE開發環境的設定納入控管則會造成災難,開發人員都會希望自己的開發環境是方便且友善的,為了如此的目的多多少少都會修改其相關設定,當每一位開發人員都有權利對IDE設定進行commit時,我們將發現開發環境的設定將會是一團亂,甚至於造成專案無法正常開啟。


總結上面所述,跨J2EE平台的專案管理工具最好能符合以下條件。


  • 由建置設定檔反向產生個別IDE開發環境設定,並且由建置人員將IDE設定檔排除在版本控制之外。

  • 將所有相依的jar檔統一放置於貯藏庫(repository)中,於建置專案的同時進行連結與Classpath的引用。

  • 將所有經常使用的建置邏輯抽出成為template,並強迫使用統一的建置邏輯,才不會因為不同的建置人員而寫出不同的建置腳本檔,而使日後維護更加艱難。

  • 將所有第三方協同專案開發的套件進行封裝,成為一個外掛模組。例如將Cactus封裝成為Plug-in,而之後只需簡易的呼叫Plug-in進行協同作業而無須理會原先該套件使用上有多複雜。


筆者於139期的RunPC中直接使用Maven進行了簡易專案開發的示範,從本期開始將與讀者一同分享,如何使用Maven完成上述的要求,並且更進一步的超越使其成為專案管理與建置工具的最佳實踐。

設定 1 Ant中使用Cactus設定

<target name="init">

<taskdef name="runservertests" classname="...">

[...設定cactus擴充標籤...]

</taskdef>

</target>

<target name="test.tomcat.40"

depends="prepare.test.tomcat.40">

<runservertests

testURL="[cactus測試網址]"

startTarget="start.tomcat.40"

stopTarget="stop.tomcat.40"

testTarget="test"/>

</target>

<target name="prepare.test.tomcat.40"

depends="check.test.tomcat.40,testwar">

[...設定Tomcat環境並將測試War檔進行佈署...]

<copy file="[...]/test.war"

tofile="[...]/webapps/test.war"/>

</target>

<target name="testwar" depends="compile">

<war warfile="..." webxml="...">

[...進行封裝War...]

</war>

</target>

<target name="start.tomcat.40">

<java classname="..." fork="yes">

[...設定Classpath並啟動tomcat...]

</java>

</target>

<target name="stop.tomcat.40">

<java classname="..." fork="yes">

[...設定Classpath並關閉tomcat...]

</java>

</target>

<target name="test">

<junit fork="yes">

<classpath>

[...設定cactus所需要的Classpath...]

</classpath>

<formatter type="plain" usefile="false"/>

<test name="[cactus測試單元]"/>

</junit>

</target>


Maven的起源

Ant曾經是筆者認為絕佳的建置工具,畢竟AntAnother Neat Tool(另一個很棒的工具)的縮寫。經過多次專案的歷練後發現,要建置與維護多個Ant腳本的專案將非常的不易。而Maven的起源最初是由於進行Jakarta Turbine專案,原先專案中每一個check inCVS的不同的JAR檔都擁有他們自己的build files,在進行維護上相當的困難,因此能夠進行很簡單的建置,並且定義出一個建置多個project的標準、一個對project構成清晰的描述、一個簡單的方式發佈project的資訊與一個能夠通過幾個不同的project去分享不同的JAR檔的方式就成為Maven這個專案的目標。


現在的Maven將可以協助開發人員更容易的進行日常工作的建立與更輕易的理解所有Java-based開發的專案。

因此可以在最短時間內使開發人員導入目前專案的開發。並且提供以下幾個特點。


  • 使專案建置的過程更加容易

  • 提供一個通用的專案建置系統

  • 提供建立高品質的專案開發資訊

  • 提供最佳化實踐的專案開發指南

  • 允許以通透的方式進行新功能的整合


理念上Maven是一個管理與整合專案開發的建置工具,在使用上基於XML概念的Project Object Model (POM-專案元件模型)的設計,並且實際上Maven的架構與核心是非常微小的,幾乎所有的功能都是由Plugins所提供,因此,在Maven中對於Plug-in的應用非常重要。


Maven1.x環境設定

Maven相容於大多數的OS平台,讀者可參考設定 2與設定 3進行Maven環境的指定並執行maven確認是否正確執行。


首次執行時,Maven預設將[MAVEN_HOME]/plugins下所有jar檔進行解壓縮放置於${user.home}/.maven/cache路徑下,在Windows中是置於C:Documents and Settings[登入帳號] .mavencache,於Linux則是置於/home/[登入帳號] /.maven/cache下,這些所謂的plugins大多是基於Jelly語言所定義的建置腳本,也將是日後我們最常使用的套件。


Maven對於相依jar檔的管理則提供了Remote & Local Repository進行集中的管理,預設Remote Repository指向http://www.ibiblio.org/maven網站而Local Repository置於${user.home}/.maven/ repository下,Maven運行過程中相依的檔案會經由Remote Repository下載至Local Repository存放。


pluginslocal repository置於${user.home}/.maven/cache${user.home}/.maven/ repository,原意在跨平台環境下都能指向開發人員登入後User Home的資料放置路徑,但通常在實際開發中我們會希望將其路徑指向特定位置。


設定 2 MavenWindows平台設定

set MAVEN_HOME=[maven放置路徑]maven
set PATH=%MAVEN_HOME%bin;%PATH%


設定 3 MavenLinux平台設定

export MAVEN_HOME= [maven放置路徑] /maven
export PATH=${PATH}:${MAVEN_HOME}/bin


Maven參數設定與優先權

在此我們可以參考圖 1進行參數的修改,該圖說明了Maven中參數優先權的順序,在Ant中當使用property標籤進行設定之後,將無法再次修改其參數值,而MavenAnt的差異在於Maven依照設定檔放置的位置不同擁有其不同的優先權。


讀者可自行解壓縮[MAVEN_HOME]/lib/maven.jar,當中可以發現名為defaults.properties,該檔為所有預設參數放置的位置。另外在我們建置的專案中皆可包含二個設定檔,分別為project.propertiesbuild.properties,並且build.properties優先權高於project.properties,也就是說當這二個檔案中使用相同參數時build.properties所設定的值會替代project.properties的值。但這二個檔案的用意究竟為何?一般初次接觸Maven的人都會搞混,觀念上來說project.properties所存的參數多為專案所需使用的參數,build.properties所設定的參數則為建置專案時所需的參數。


以另外一個觀點來說,假設於目前專案開發階段,我們將程式碼納入版本控管,並在一部測試伺服主機上進行自動化的每日構建與測試,則我們可以將這部測試機或正式機上所需的建置參數指定給project.properties並將該檔納入版本控管當中。因此在進行Daily Build時可以從project.properties取得參數。


而開發人員於自己的開發環境中進行check out原始碼後,一樣可以從版本控制系統中取得project.properties,但該檔的設定並不一定與目前開發人員的環境相同,因此建置上可能會發生問題,為此開發人員可自行建立build.properties並將設定上的不同處進行覆寫,來完成專案建置與測試。而build.properties我們通常不納入版本控管當中。另外Maven中協同多專案進行開發是非常容易的,所以目前進行開發的專案,有可能是父專案中的子專案,也因此繼承了父專案的相關屬性,在父專案下亦可包含project.propertiesbuild.properties二個設定檔。


User home的路徑下,也就是C:Documents and Settings[登入帳號],是屬於優先權次高的設定檔,通常在此進行對預設參數的覆寫,以取代原始的預設值,參考設定 4在這裏重新指定了maven.home.localmaven.repo.remote,透過maven.home.local參數的覆寫,相對的也指定了.maven/cache.maven/ repository的路徑,這一點可以從maven.jar中的defaults.properties的設定maven.repo.local=${maven.home.local}/repositorymaven.plugin.unpacked.dir = ${maven.home.local}/cache找到解答。


若為了加速下載速度或是企業內部網路受限的環境下而必須設定代理伺服器可使用設定 4maven.proxy相關參數進行設定,該設定中亦支援NTLM授權。但在網路管制較嚴格的企業中,代理伺服器的設定可能還是無法使Maven順利進行檔案下載作業,則這時必須求助於網管人員調整其網路權限。


使用Command line方式進行設定的參數將覆蓋之前所有的設定,參考設定 6中我們運行了plugin:download並覆寫參數maven.repo.remote以及其他參數。使用方式同java參數設定-Dproperty=value,擁有最高的優先權。


設定 4 User home下的build.properties

#設定cacherepository放置路徑

maven.home.local=${maven.home}/.maven


#設定remote repository網址

maven.repo.remote=file:E:/maven/maven.remote.repository,

http://www.ibiblio.org/maven,

http://maven-plugins.sourceforge.net

#Maven使用代理伺服器

maven.proxy.host=[代理伺服器網址]

maven.proxy.port=[代理伺服器Port]

maven.proxy.username=[帳號]

maven.proxy.password=[密碼]

maven.proxy.ntlm.username=[帳號]

maven.proxy.ntlm.password=[密碼]


1 參數優先權設定順序


資料結構、groupIdartifactId

Maven提供了許多的Plug-in,讓專案建構變得非常簡單。但Maven對於建置專案也有限制,其限制就是每個專案﹙在Maven中一個專案是指帶有project.xml的一個資料夾﹚只能生成一個成品(artifact)。但這個限制對於複雜的專案架構上並沒有問題,因為Maven支援多專案的建置。一個Maven專案可以由子專案,每個子專案可以建置產生自己的成品,最頂層的專案可以將子專案的成品打包進行封裝生成JARWAREAR。並且Maven在專案之間還提供了繼承(inheritance)。


Maven使用了groupIdartifactId的觀念,參考資料結構 1,當進行小型專案的建置時,我們只需要類似artifact-id-implementartifact-id-war簡易的建出JARWAR即可,這時groupIdartifactId通常是相同的。但若進行大型專案的建置,將可能將企業邏輯進行抽像化,產生介面、實作與其共用元件,而多個介面、實作、共用元件配合WAREAR的建置就可對大型專案進行封裝與佈署,如此的分層架構規劃下,許多Maven建置的artifact都將可以輕易的在各專案的建置下重覆使用,而這時的groupIdartifactId就必須有不同的名稱。例如Spring這個Framework,其groupIdorg.springframework,而分別依功能區分了spring-aopspring-beansspring-contextspring-dao…等的artifactId


註:關於project.xmlgroupIdartifactId的設定請參考139期的Run PC


資料結構 1 Maven資料夾結構

group-id

|-- artifact-id-interface

| |-- src/

| | |-- main/

| | | |-- java/

| | | | `-- ...

| | | `-- resources/

| | | `-- ...

| | `-- test/

| | |-- java/

| | | `-- ...

| | `-- resources/

| | `-- ...

| |-- project.xml

| |-- maven.xml

| |-- project.properties

| `-- build.properties

|

|-- artifact-id-implement

| `-- ...結構同上...

|

|-- artifact-id-war

| |-- src/

| | |-- java/

| | |-- resources/

| | `-- webapp/

| |-- test/

| | |-- java/

| | `-- resources/

| |-- project.xml

| |-- maven.xml

| |-- project.properties

| `-- build.properties

|

|-- project.xml

|-- maven.xml

|-- project.properties

`-- build.properties


建置Maven的組件與其核心架構

Maven的基本概念就是Project,每一個目錄包含有project.xml的目錄都是一個Project,而另一個概念就是Repository。當運行maven命令時,將會從Remote repository中複製於project.xmldependency標籤所相依的jar檔到Local repository,然後建構專案,封裝成品。參考設定 5與圖 2MavengroupId建立一個子目錄,在groupId資料夾中依所需的artifactId進行下載指定type的檔案,這裏所指的typejarejbplugin…等設定,若未指定則預設為jar。在設定 5的範例中將會建立groupIdorg.springframework的資料夾並於預設typejar的條件下建立jars資料夾並下載指定規則為<artifactid>-<version>.<type>spring-aop-1.2.6.jarspring-beans-1.2.6.jarspring-context-1.2.6.jar三個檔案於該資料夾內。


Repository的角色是相當明顯的,每個專案不再需要各自包含自己所依賴的第三方套件,Repository將會協助開發人員在多個專案間共用所有套件。而另一方面每個專案也可以自己建置成品,依Maven的觀念可使用install將套件安裝到Local repository,使用deploy將套件佈署到Remote repository。使用這種方式可以幫助開發者用一種標準的方式在專案間共用自製的套件。並且相互依賴的進行專案間持續整合(continuous integration)。若透過Cruise Control工具。專案可以持續的建置,最新釋出的成品可以重覆佈署到Repository中。在建置主機上運行持續性整合,將會定時的持續建構、發佈成品到應用伺服器中、進行自動測試並檢驗建置狀態。參考圖 3顯示了在Maven建置過程中project.xmlRepositorygoalplug-in各自的角色。


設定 5 project.xml設定dependency

<dependencies>

...

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-aop</artifactId>

<version>1.2.6</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-beans</artifactId>

<version>1.2.6</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>1.2.6</version>

</dependency>

...

</dependencies>



2 Repository資料夾結構


3 建置Maven相關組件


Maven Plug-in

Maven中幾乎所有功能都是由Plug-in所提供的,在Plug-in中包含了多個goal,而針對每個goal可以因應多個property的設定呈現不同的實作結果。例如Maven Jar Plug-in中原先在執行maven jar:jar這個goal之後,將進行原始碼編譯、測試並依artifactid-version.jar規則封裝成jar檔,而當我們在進行參數設定並加入maven.jar.final.name=xxxx.jar後重新執行,則最後封裝結果的檔案將會是xxxx.jar


究竟目前在本機上有多少的Plug-in可用,在此我們可以執行maven -g列出所有的Plug-in,亦可以使用maven -g > goal.txt重導至檔案中慢慢查看,若已經知道欲使用的Plug-in卻不知該Plug-in提供多少goal,可使用maven -P [plugin name]則可列出指定的Plug-in中所有的goalmaven -g maven -P 列出格式參考資料結構 2



Maven -g-P參數可以清楚的知道有多少的goal可使用,但Plug-in中有多少property就沒有參數可以協助列出以供查看了,關於這個部分可以連至Maven官方網站http://maven.apache.org/maven-1.x/reference/plugins參考詳細的Plug-in說明文件。



Maven在預先安裝中就已經包含了大多數的Plug-in了,但若欲使用的Plug-inbug或欲使用的功能於本機上的Plug-in尚未提供,則可至Maven官方網站中任選以下方式進行下載並安裝,。


  • 方式1:手動下載指定版本Plug-injar,置於[MAVEN_HOME]/plugins下即可。

  • 方式2:參考設定 6執行plugin:download並指定所需的Plug-in進行手動下載與安裝。

  • 方式3:參考設定 7執行maven任一goal的同時進行Plug-in進行自動下載與安裝。


註:Maven中的goalAnt腳本中的target是意義相同的,所指的都是預先定義好的任務,而Mavengoal是由Jelly(基於XML的標記語言)編寫的一系列命令腳本,而使用goal的語法為maven [plugin name]:[goal name]


資料結構 2 maven -g maven -P 輸出格式

__ __

| / |__ _Apache__ ___

| |/| / _` V / -_) ' ~ intelligent projects ~

|_| |___,_|_/___|_||_| v. 1.0.2


Available [Plugins] / Goals

===========================

[plugin name1] 針對plugin name1的描述

goal name1 ..... goal name1使用描述

goal name2 ..... goal name2使用描述

goal name3 ..... goal name3使用描述

...

[plugin name2] 針對plugin name2的描述

...


設定 6 Maven手動下載Plug-in

maven plugin:download

-Dmaven.repo.remote=http://www.ibiblio.org/maven, http://cvs.apache.org/repository/

-DgroupId=maven

-DartifactId=maven-jar-plugin

-Dversion=1.7


設定 7 MavenPOM中設定自動下載Plug-in

<dependencies>

...

<dependency>

<groupId> maven</groupId>

<artifactId> maven-jar-plugin </artifactId>

<version>1.7</version>

<type>plugin</type>

</dependency>

...

</dependencies>


Maven Goal

除了之前提過的project.xmlRepositoryPlug-in之外,在圖 3中我們可以看到maven.xml檔的設置,這個檔案主要用途在於延伸、擴展與客製化Goal,並且在這個檔案中我們會使用到preGoalgoalpostGoal三個標籤進行Goal的定義。


參考設定 8project標籤的default屬性設定為buildWeb,在Maven中的goalAnt中的target是相同的概念,而且Maven中的default屬性的設定亦是相同於Ant。這個設定意味著在目前專案的目錄下,直接執行maven指令,這時將會執行的defaultgoalbuildWeb,在這個設定中buildWeb直接使用attainGoal標籤去執行另外一個goalwar Plug-in中的war這個goal


從這個例子中我們可知,我們可以在goal標籤中撰寫所需的執行的Jelly腳本,當然這個腳本目前也相容於Ant的寫法,並且在goal中還可以使用attainGoal去執行其他Plug-ingoal。例如war:war這個goal依順序也會去執行java:compiletest:testwar:webapp…這幾個goal


preGoal標籤則代表了在指定的goal執行之前所要執行的建構規則,如之前所提war:war運行過程中會去執行java:compile,而本例中在編譯之前將先行呼叫xdoclet:webdoclet這個goal協助在建置過程中產生web相關的設定檔。因此使用preGoal進行功能的擴展就無須直接修改java:compile這個goal


同樣的postGoal的意義在於將在goal執行之後所運行的建構規則,在本例中當war:war完成後將產生一個war檔,透過postGoal功能的延伸的撰寫我們就可以進行簡易的tomcat的佈署動作了。


Maven中無論是goalpreGoalpostGoal都可以嵌入任何Anttask,。雖然給了Maven極大的靈活性,但是也很容易造成誤用,反而將之前使用Ant進行的設定、建置、佈署動作方式原封不動的搬到Maven來了,也就是說,只是在Maven的結構下依然故我的撰寫Ant的腳本,而造成在Maven下卻完全用不到Plug-in的好處。


建議在一般情況下,當找不到任何適當的的Plug-in時再自行撰寫,畢竟Maven最大的好處在於有無數的Plug-in可以使用,並且每一個Plug-in都是開放原始碼的心血結晶。


設定 8 maven.xml

<?xml version="1.0" encoding="Big5"?>

<project xmlns:j="jelly:core" xmlns:ant="jelly:ant" default="buildWeb">

<preGoal name="java:compile">

<attainGoal name="xdoclet:webdoclet" />

...在指定的goal之前執行建構規則...

</preGoal>

<goal name="buildWeb">

<attainGoal name="war:war" />

...建立一個新的或覆寫一個goal...

</goal>

<postGoal name="war:war">

<copy file="${maven.build.dir}/${pom.artifactId}.war"

todir="${tomcat.home.webapps}"/>

...在指定的goal之後執行建構規則...

</postGoal>

</project>


Maven1.xMaven2.x的差異

目前上過Maven官方網站的讀者應該已經注意到,Maven2已經Release了,雖然Maven2Maven1在概念上是非常相近的,但Maven2在架構上是對於Maven1完全的重寫,也因此將完全不相容。Maven1 Plug-in的部分也無法直接在Maven2上使用,而且因為效能考量下原先在Maven1建立Plug-in受到重用的Jelly語言,將不會在Maven2中出現,取而代之的將是回歸使用Java進行Plug-in的開發。


讀者看到這裏是否覺得,即然如此這時專案的開發應該全數移轉到Maven2上才是,也該放棄Maven1了。這也是當筆者看到Maven2的感想,但是實際上運作幾個Project後發現,雖然Maven2提供了不少相對於Maven1增加的新功能與特色,而且目前版本也尚稱穩定,但它最大的問題在於可用的Plug-in還不多,而少數的Plug-in目前還有Bug


這是理所當然的,想當初Maven1也是經過二、三年的時間才延伸出這些為數可觀又好用的Plug-in,若要Maven2Plug-in能夠成長到一個地步則還需要一段時間,但讀者無需擔心,目前Maven1建置的資料夾結構移到Maven2還是可以共用的,若日後需移轉到Maven2時,只需加上pom.xml並依Maven2規範設定就可以完成相容於Maven1Maven2的專案了。


相關資源

1. http://maven.apache.org/ Maven官方網站

2. http://www.theserverside.com/articles/article.tss?l=MavenMagic

Srikanth Shenoy TheServerSide.com發表的MavenMagic文章

3. Maven: A Developer's Notebook

By Vincent Massol, Timothy M. O'Brien


Read More......