注:本文部分引用了網絡上的文章,以及動力節點老師的講解內容,感謝老師,嘻嘻。
為了舉例方便,我新建了pathTest項目:
關於tomcat的配置,eclipse訪問項目的路徑一般是localhost:8080/projectName, 在idea,訪問路徑默認情況下就變成了localhost:8080,路徑沒有了后面的項目名。localhost:8080/projectName或者是localhost:8080就是我們平常所說的應用上下文,項目中的路徑名都是相對於這個應用上下文來說的。在idea下開發的時候,有時候我們可能需要讓訪問路徑帶上項目名,但是idea默認是為每個項目單獨配置tomcat的,eclipse是把項目統一放到某個配置好的tomcat中,所以默認配置的不同會導致訪問路徑的差別(這個要重點理解)。
out包含了項目中所有的文件,資源。
這也是為什么我們在寫路徑時,為什么不用寫web這個路徑的原因(一開始我以為會自動補上,其實項目發布后以out文件夾中的projectName_war_exploded為根目錄,根本就沒web文件夾的事)。
測試環境弄好了,我們就可以開始理解各種路徑的問題了!我在這幾天看了不少資料,發現:路徑問題具有相對性,要根據服務器的配置討論,具體問題具體分析!如上面所示我是把idea的默認配置修改了,把application context由空修改為/pathTest,這是大前提哦!這樣配置的話,有一層含義是一個服務器中是存在多個web項目的。
雖然說路徑具有相對性,但是還是有一些“不變的真理”的:
1. / 與 \ 的區別:作為目錄分隔符:Windows目前用 \ 和 / 都可以,Unix只能用 / 。因為web最開始在Unix上跑,所以URL也用 / 做目錄分割符。
2. / 表示文件根目錄
./ 表示文件目前所在的目錄(寫與不寫等效)
../ 表示文件的上一層目錄
3. 絕對路徑 = 參考路徑 + 相對路徑
+----------------------------------------------------------------------------------------------------------------------------------------------------------------+
在開始實驗前,先總觀路徑問題:絕對路徑沒啥說的,主要是相對路徑。
- 以斜杠開頭的相對路徑
- 前台路徑:由瀏覽器解析執行的代碼中所包含的路徑(html,css,js及jsp中靜態部分的路徑,ajax)。前台路徑的參照路徑是web服務器的根路徑即http://127.0.0.1:8080(http://localhost/)。將前台路徑轉化為絕對路徑,是由瀏覽器自動完成的,作用是為用戶提交對某種資源的請求,是要查找並定位服務器中某種資源,即查找。
- 后台路徑:由服務器所執行的代碼及文件中所包含的路徑(java、jsp動態部分,xml等配置文件)。后台路徑的參考路徑是web應用的根路徑,如http://127.0.0.1:8080/webAppName(項目工程名字)。將后台路徑轉化為絕對路徑的工作由服務器完成。其作用是標識該資源在服務器中的路徑,以便客戶端能夠按照這個設定路徑來查找相應的資源,即標識。
- 特例:response.sendRedirect()。若其參數路徑為以斜杠開頭相對路徑,那么這個后台路徑是個特例。這是由sendRedirect()的本質決定的:該方法可以跳轉到其它項目的資源,所以這個后台路徑的參照路徑為當前web服務器的根目錄。(可以使用request.getContextPath()獲取路徑。)只有這種重定向的以斜杠開頭的相對路徑是特例,其它重定向遵循路徑轉化定理。
- 以名稱開頭的相對路徑(其實是省略了 ./)
- 無論是出現在前台還是后台,其參照路徑都是當前訪問路徑的資源路徑(倒數第一個斜杠/前面的路徑)。即使是response.sendRedirect()方法的參數路徑,若不以斜杠開頭,其也屬於以路徑名稱開頭的相對路徑,參照路徑為當前訪問路徑的資源路徑。web.xml中Servlet的配置<url-pattern></ url-pattern >中的路徑只能是以斜杠開頭的相對路徑,因為它根本不是請求,只是起標識作用,故沒有資源路徑。
建議使用以斜杠開頭的相對路徑,這樣的話參考路徑固定了,會避免很多不必要的錯誤。上面說的不懂,沒關系,下面結合例子來說:
首先,我把pages目錄下的index.html設置為歡迎頁面,項目結構忘記了的看上面哦!
我在index.html中插入如下標簽:

啟動服務器,發現第一張圖片路徑是無效的,剩下兩張圖片路徑有效。點擊超鏈接進入第二頁。
成功跳轉,來到第二頁后,點擊返回首頁。
回到首頁后,你會發現,第一張圖片原本路徑無效的,現在反而有效了;第三張圖片原本路徑有效的,現在反而無效了。之后反復切換,三張圖片的狀態保持不變。
這其實就是歡迎頁面在作怪!項目啟動時,瀏覽器訪問webApplication context(http://localhost/pathTest/),此時會進行請求轉發,就近訪問在web.xml中配置的歡迎頁面。由於是請求轉發(服務器端跳轉),url地址欄看上去沒變化,實際上你訪問的是pages目錄下的index.html(我們設置的歡迎頁面)。但是,瀏覽器是根據目前地址欄(你所看到的)來定位資源的。
下面使用瀏覽器的調試工具查看各圖片的路徑訪問情況(按F12)
圖片1引用路徑: ../images/test.jpg
圖片2引用路徑: /pathTest/images/test.jpg
圖片3引用路徑: images/test.jpg
因為我們設置應用上下文為:/pathTest,所以項目啟動時訪問http://localhost/pathTest/,tomcat默認你的在web根目錄下有一個index.html或者jsp等等歡迎頁面,所以我們啟動項目第一次訪問首頁時,其實,
url地址欄是http://localhost/pathTest/index.html或者http://localhost/pathTest/index.jsp(即使它不存在,執着的tomcat......)
此時進行請求轉發,訪問http://localhost/pathTest/pages/index.html,但是你看到的地址欄仍然是http://localhost/pathTest/。
分析圖片1:參考路徑:http://localhost + 相對路徑:/images/test.jpg = http://localhost /images/test.jpg,路徑錯誤了(缺少項目名稱),故自然無法訪問。
分析圖片2:參考路徑:http://localhost + 相對路徑:/pathTest/images/test.jpg = http://localhost /pathTest/images/test.jpg,路徑正確,可以訪問。
分析圖片3:參考路徑(資源路徑):http://localhost/pathTest + 相對路徑:/images/test.jpg = http://localhost /pathTest/images/test.jpg,路徑正確,可以訪問。
當我們進入第二頁再返回首頁時,瀏覽器的地址欄是 http://localhost/pathTest/pages/index.html
分析圖片1:參考路徑:http://localhost + 相對路徑:/pathTest/images/test.jpg = http://localhost/pathTest/images/test.jpg,路徑正確,可以訪問。
分析圖片2:參考路徑:http://localhost + 相對路徑:/pathTest/images/test.jpg = http://localhost /pathTest/images/test.jpg,路徑正確,可以訪問。
分析圖片3:參考路徑(資源路徑):http://localhost/pathTest/pages/ + 相對路徑:/images/test.jpg = http://localhost/pathTest/pages/images/test.jpg,路徑錯誤,無法訪問。
圖片1這里有個地方有點玄,解析一下:在第一次訪問首頁時,我們可以認為瀏覽器地址欄是:http://localhost/pathTest/index.html(tomcat假設存在index.html),這個假想的index.html所在的目錄是pathTest,它的上一層目錄為服務器根目錄了,這時在服務器根目錄下訪問images/test.jpg便會出錯。
我們可以做個小實驗檢驗一下:把tomcat的應用上下文(application context)設置為空(默認配置,一個tomcat只裝一個web項目,服務器根目錄也就是web應用根目錄,直接訪問http://localhost即可訪問web項目pathTest),重啟服務器。
此時圖片1可以正常訪問,圖片的訪問路徑是:http://localhost/images/test.jpg
此時我們可以認為地址欄為:http://localhost/index.html,此時無論這個假想的index.html怎么返回上一級目錄,它還是只能呆在http://localhost(也是web應用根目錄),而我們的web項目下是存在images/test.jpg的,所以圖片可以正常訪問。
這樣我們就知道為什么歡迎頁會導致圖片訪問出錯了,怎么樣,是不是有種一本正經的胡說八道的趕腳?其實,相對路徑是沒有沒有萬能的寫法的,主要是服務器配置好了以后,才有一種相對穩定的寫法(以斜杠開頭,以根目錄為參考路徑,這也是為什么推薦這種寫法的原因),才有繼續討論的意義。