題外話:感謝開源精神,如果不是她,我今天可能就不會如此順利的找到解決問題的方法。
Velocity主要是一個在MVC框架中解決View層問題的框架,其模版功能十分之強大,可以用來做很多事情,據傳曾有人用這個來生成程序,還有生成JSP文件等,不過后來也發現這樣做的維護開銷極大,而且畢竟沒有人那多智能。但是在View層做一些改進還是很好的,雖然我并沒有拿她來做這樣的事,但是從我用她來實現其它的功能便可感受到。
我見過的使用Velocity較好的項目有DLOG4J(中文官方網站為:http://www.javayou.com/main.jspe?cat_id=7),天乙BBS(http://www.laoer.com/)等,大家有興趣的話可以去看看。
我用Velocity主要是在項目中做為生成各類系統MAIL的template,所以在使用的時候雖然是在WEB應用中,但是并不是做為View層的模版,也不用在web.xml文件中加一堆配置,但是問題隨之也產生了。
Velocity讀取模版文件的方式采用的是File類,每次都會自動將我們給出的模版的相對路徑解析成一個絕對路徑,然后再用File類讀入,這如果對于一個本地運行的Application來說不會有太大的問題(存在的問題就是模版文件不能一起打包在.JAR文件中,只能放在JAR包的外面,具體位置為與JAR包同一目錄下)。這樣的方式,對于WEB應用中的相當于資源文件的方式來說簡直就是一種災難,無論是將這些文件放在classes目錄下,還是放在lib目錄下,都會找不到資源文件。
無奈之下,我只好跟進Velocity的源碼,一看究竟。經過一翻追蹤,發現模版文件的加載主要由FileResourceLoader這個類來搞定,而且加載模版文件的實現十分繁雜(主要是方法間的調用讓人看得極為眼花),最終使用的方法如下:
?1?private?InputStream?findTemplate(String?path,?String?template)
?2?????{
?3?????????try
?4?????????{
?5?????????????File?file?=?new?File(?path,?template?);
?6?????????????if?(?file.canRead()?)
?7?????????????{
?8?????????????????return?new?BufferedInputStream(
?9?????????????????????new?FileInputStream(file.getAbsolutePath()));
10?????????????}
11?????????????else
12?????????????{
13????????????????return?null;
14???????????}
15?????????}
16?????????catch(?FileNotFoundException?fnfe?)
17?????????{
18?????????????/*
19??????????????*??log?and?convert?to?a?general?Velocity?ResourceNotFoundException
20??????????????*/
21?????????????return?null;
22?????????}
23?????}
在這段code中,關鍵所在即為?File?file?=?new?File(?path,?template?),所以如果在web應用中運行的話,非把文件放到運行時系統所處的相對路徑下才能成功,這對于WEB的部署帶來的也是災難性的后果。?2?????{
?3?????????try
?4?????????{
?5?????????????File?file?=?new?File(?path,?template?);
?6?????????????if?(?file.canRead()?)
?7?????????????{
?8?????????????????return?new?BufferedInputStream(
?9?????????????????????new?FileInputStream(file.getAbsolutePath()));
10?????????????}
11?????????????else
12?????????????{
13????????????????return?null;
14???????????}
15?????????}
16?????????catch(?FileNotFoundException?fnfe?)
17?????????{
18?????????????/*
19??????????????*??log?and?convert?to?a?general?Velocity?ResourceNotFoundException
20??????????????*/
21?????????????return?null;
22?????????}
23?????}
我曾試著在上面這段code的第5行下面用file.getAbsolutePath()得到其絕對路徑,作為Application運行的時候,得到的是項目所在的工作目錄,而我在Web應用環境下得到的結果卻讓我大吃一驚,結果居然是:c:\windows\system32(我采用的平臺是WinXP+Tomcat5.0.28)。各位看官,到此是不是令你咋舌了?你一定也會覺得這有些不可思議,這樣的結果弄得跟系統都變得相關了。
經過一番分析發現有一個極其簡單的解決辦法(或許我總是喜歡用簡單的辦法解決問題,這可能也是受XP的影響),將上面的代碼改為如下:
?1?????private?InputStream?findTemplate(String?path,?String?template)
?2?????{
?3?????????try
?4?????????{
?5?????????????File?file?=?new?File(?path,?template?);
?6?
?7?//????????????System.out.println(file.getAbsolutePath());//for?test
?8?//????????????System.out.println(template);
?9?????????????if?(?file.canRead()?)
10?????????????{
11?????????????????return?new?BufferedInputStream(
12?????????????????????new?FileInputStream(file.getAbsolutePath()));
13?????????????}
14?????????????else
15?????????????{
16????????????????//?return?null;//before?modified.
17?
18????????????????????return?this.getClass().getClassLoader().getResourceAsStream(template);
19?????????????}
20?????????}
21?????????catch(?FileNotFoundException?fnfe?)
22?????????{
23?????????????/*
24??????????????*??log?and?convert?to?a?general?Velocity?ResourceNotFoundException
25??????????????*/
26?????????????return?null;
27?????????}
28?????}
?2?????{
?3?????????try
?4?????????{
?5?????????????File?file?=?new?File(?path,?template?);
?6?
?7?//????????????System.out.println(file.getAbsolutePath());//for?test
?8?//????????????System.out.println(template);
?9?????????????if?(?file.canRead()?)
10?????????????{
11?????????????????return?new?BufferedInputStream(
12?????????????????????new?FileInputStream(file.getAbsolutePath()));
13?????????????}
14?????????????else
15?????????????{
16????????????????//?return?null;//before?modified.
17?
18????????????????????return?this.getClass().getClassLoader().getResourceAsStream(template);
19?????????????}
20?????????}
21?????????catch(?FileNotFoundException?fnfe?)
22?????????{
23?????????????/*
24??????????????*??log?and?convert?to?a?general?Velocity?ResourceNotFoundException
25??????????????*/
26?????????????return?null;
27?????????}
28?????}
看看,是不是超級簡單。
Compile,打包,搞定!
經過測試,現在無論是將模版文件一起打包到JAR包中還是放到Classes目錄下均可。
PS:將模版文件用作View層的Web應用沒有測試過,有興趣的朋友可以幫我測一把。謝謝! 如有錯誤,歡迎指正。