徹底解決java WEB項目的文件路徑問題(war包)

在j2EE項目中,我們一般會把項目打包發佈,一般是war包,作爲獨立單元,可以遠程上傳,加載,發佈,還可以實現版本控制,但這與我們開發過程中使用MyEclipse自動部署有所不同,以下做詳細說明.

使用war包部署,在tomcat和WebLogic下部署有很大的區別,tomcat會把war自動加壓到當前目錄下,然後再用解壓的目錄來發布,這與一般不會出現太大的意外,但如果是用WebLogic發佈,就不會被解壓,如果開發過程中不注意,war包發佈後就有可能出現找不到文件的現象。例如:使用以下方法獲取路徑:

this.getClass().getClassLoader().getResource("/").getPath(); 

這與得到的是絕對Uri路徑,例如::/D:/jboss-4.2.2.GA/server/default/deploy/hp.war/WEB-INF/classes/,帶盤符的路徑,顯然在war中無法根據盤符來找到文件

第二種方式:

this.getClass().getResource("/").getPath(); 

那麼這樣獲取行不行呢?經試驗,這與獲取的是當前類的Uri目錄,例如:/D:/jboss-4.2.2.GA/server/default/deploy/hp.war/WEB-INF/classes/com/jebel/helper/ 也是絕對路徑,顯然無法適用於war包。

其實以上兩種方式都走入了岔路,因爲讀取文件未必要讀取路徑,文件操作一般都要轉換爲流的方式,既然要讀取文件,不如直接讀成輸入流,也少了一步封裝。請看以下方式:

InputStream is= this.getClass().getResourceAsStream("/config/bctcms/" + templateFileName);
意思是讀取classes目錄中,目錄config/bctcms/下,文件名爲templateFileName的文件輸入流。經試驗在war中可以正常讀取到。

該方法存在一個弊端,只能讀取classes目錄下的文件,對於其他目錄下的文件無能爲力,顯然並不適用於所有場景。

如果文件在WEB-INF目錄下,如何進行讀取呢?

答案是使用ServletContext.getResourceAsStream(String)方法。也就是先得到上下文信息,然後通過以工程目錄爲root的絕對路徑,找到文件,舉例說明:

InputStream is= context.getResourceAsStream(templatePath + "/" + templateFileName);
templatePath="/WEB-INF/classes/config/bctcms/"
templateFileName="source.xls"
可以看到templatePath是相對於context root 的路徑,而不是相對於classes,這樣即使文件在WEB-INF其他目錄下,也可以順利找到,經測試,對war的情況支持良好。請來看看ServletContext.getResourceAsStreamAPI文檔,
Returns a URL to the resource that is mapped to a specified path. The path must begin with a "/" and is interpreted as relative to the current context root. 
This method allows the servlet container to make a resource available to servlets from any source. Resources can be located on a local or remote file system, in a database, or in a .war file.

相信大家都看得懂,就不用贅述了。只是有個問題,context是個什麼東西?答案:ServletContext,上下文信息,在j2EE類中使用request獲得,如:

ServletContext context = request.getSession().getServletContext();
那麼在普通類中如何獲取呢?暫時特別好的辦法,使用application是一種方式,另外一種方式就是想辦法先後去request對象,如:

RequestAttributes ra = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) ra).getRequest();
this.context = request.getSession().getServletContext();
這樣也是可以獲得Context的

但如果是JSP中,可以直接這麼獲取輸入流:

application.getResourceAsStream("xxx”);

路徑問題不要糾結太久,根據以上辦法解決,最好都用ServletContext方法來獲取,只需要知道一種情況就可以了。達到目的纔是最重要的,對吧?

有不對之處,歡迎大家進行補充糾錯!

update:當使用spring定時器時:request和servletContext就獲取不到了,那麼要使用這樣的辦法直接獲取ServletContext:

ContextLoader.getCurrentWebApplicationContext().getServletContext()

update20151228:

寫文件的時候可能需要獲得路徑,比如上傳文件的時候就需要輸出流,而通過ServletContext不能夠直接獲得輸出流的,但可以直接獲取實際路徑,如:

servletContext.getRealPath("/")

這樣獲得的路徑是${context}/路徑,再根據子路徑和文件名獲取輸出流。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章