javaweb項目中有很多場景的路徑
客戶端的POST/GET請求,服務器的請求轉發,資源獲取需要設置路徑等
這些路徑表達的含義都有不同,所以想要更好的書寫規范有用的路徑代碼 需要對路徑有一個清晰地認知
路徑基本上分三類
- 客戶端路徑
- 服務端路徑
- 其他
路徑相關的操作類型
- 超鏈接
- 表單
- 重定向
- 轉發
- 包含
- <url-pattern>
- ServletContext獲取資源
- Class獲取資源
- ClassLoader獲取資源
客戶端路徑
超鏈接/表單/重定向 都是客戶端路徑
客戶端路徑形式上可以分為三種方式:
- 絕對路徑;
- 以“/”開頭的相對路徑;
- 不以“/”開頭的相對路徑;
超鏈接/表單
比如:
http://127.0.0.1:8080/servlet/NewFile.jsp
絕對路徑: <a href="http://127.0.0.1:8080/servlet/ServletA">鏈接1</a> 以“/”開頭的相對路徑: <a href="/servlet/ServletB">鏈接2</a> 相對路徑: <a href="ServletB">鏈接3</a> <hr /> 絕對路徑: <form action="http://127.0.0.1:8080/servlet/ServletA"> <input type="submit" value="表單1" /> </form> 以“/”開頭的相對路徑: <form action="/servlet/ServletB"> <input type="submit" value="表單2" /> </form> 相對路徑: <form action="ServletB"> <input type="submit" value="表單3" /> </form>
鏈接1和表單1:沒什么可說的,它使用絕對路徑;
鏈接2和表單2:以“/”開頭,相對主機,與當前jsp頁面的主機相同
即最終訪問的頁面為http://localhost:8080/servlet/ServletB;
鏈接3和表單3:不以“/”開頭,相對當前頁面的路徑,即頁面jsp所有的路徑
即最終訪問的路徑為:http://localhost:8080/servlet/ServletB;
重定向
兩種形式
帶/開頭的 相對路徑
不帶/開頭的 相對路徑
ServletA中
response.sendRedirect("/servlet/ServletB");
http://127.0.0.1:8080/servlet/ServletA
因為路徑以“/”開頭,所以相對當前主機
http://127.0.0.1:8080/servlet/ServletB
ServletA中
response.sendRedirect("ServletB");
相對於當前ServletA的路徑
當前ServletA的路徑為http://127.0.0.1:8080/servlet/
所以請求的是:
http://127.0.0.1:8080/servlet/ServletB
上面的例子如果寫成
response.sendRedirect("/ServletB");
將是相對於主機http://127.0.0.1:8080/ServletB 就找不到了
強烈建議使用“/”開頭的路徑,這說明在頁面中的超鏈接和表單都要以“/”開頭
后面是當前應用的名稱,再是訪問路徑
/servlet/ServletB
在Servlet中的重定向也建議使用“/”開頭,同理,也要給出應用的名稱
應用名稱可以使用request.getContextPath()獲取
response.sendRedirect(request.getContextPath() + "/BServlet");
服務端路徑
請求轉發 請求
服務器端路徑必須是相對路徑,不能是絕對路徑。但相對路徑有兩種形式
以“/”開頭;
不以“/”開頭;
其中請求轉發、請求包含都是服務器端路徑 request.getRequestDispatcher()的參數 |
服務器端路徑與客戶端路徑的區別是:
- 客戶端路徑以“/”開頭:相對當前主機;
- 服務器端路徑以“/”開頭:相對當前應用;
例如
ServletA中
request.getRequestDispatcher("/BServlet").forward(request, response);
相對於ServletA http://127.0.0.1:8080/servlet/ServletA 的當前應用 http://127.0.0.1:8080/servlet
也就是http://127.0.0.1:8080/servlet/BServlet
如果是
request.getRequestDispatcher("BServlet").forward(request, response);
那么則是相對於當前路徑
相對於ServletA http://127.0.0.1:8080/servlet/ServletA 的當前路徑 http://127.0.0.1:8080/servlet/
也就是http://127.0.0.1:8080/servlet/BServlet
例子不是很明顯,因為只有一層路徑,應用名下面就是ServletB了 可以再多加一層路徑嘗試
比如:
假設訪問AServlet的路徑為:http://localhost:8080/hello/servlet/AServlet
因為路徑不以“/”開頭,所以相對當前應用,即http://localhost:8080/hello/servlet/BServlet。
其他
url-pattern
<url-pattern>必須使用“/”開頭,並且相對的是當前應用。
ServletContext獲取資源
必須是相對路徑,可以“/”開頭,也可以不使用“/”開頭,但無論是否使用“/”開頭都是相對當前應用路徑
String path1 = this.getServletContext().getRealPath("a.txt"); String path2 = this.getServletContext().getRealPath("/a.txt");
path1和path2是相同的結果
Class獲取資源
import java.io.InputStream; public class Demo { public void fun1() { InputStream in = Demo.class.getResourceAsStream("/a.txt"); } public void fun2() { InputStream in = Demo.class.getResourceAsStream("a.txt"); } }
其中fun1()方法獲取資源時以“/”開頭,那么相對的是當前類路徑,即 /應用名/WEB-INF/classes/a.txt文件;
其中fun2()方法獲取資源時沒有以“/”開頭,那么相對當前Demo.class所在路徑,
因為Demo類在com.test 包下,所以資源路徑為:/應用名/WEB-INF/classes/com/test/a.txt
Class獲取資源也必須是相對路徑,可以“/”開頭,也可以不使用“/”開頭。
以“/”開頭,那么相對的是當前類路徑,即 /應用名/WEB-INF/classes/
沒有以“/”開頭,那么相對當前.class所在路徑,因為類一般都在包下面比如com.demo
所以/應用名/WEB-INF/classes/...包路徑.../
ClassLoader獲取資源
ClassLoader獲取資源也必須是相對路徑,可以“/”開頭,也可以不使用“/”開頭。
但無論是否以“/”開頭,資源都是相對當前類路徑。
public class Demo { public void fun1() { InputStream in = Demo.class.getClassLoader().getResourceAsStream("/a.txt"); } public void fun2() { InputStream in = Demo.class.getClassLoader().getResourceAsStream("a.txt"); } }
fun1()和fun2()方法的資源都是相對類路徑,即classes目錄,即/應用名/WEB-INF/classes/a.txt