一個請求 URI 實際上是由三個部份所組成,你可以使用 HttpServletRequest
的 getRequestURI()
來取得:
requestURI = contextPath + servletPath + pathInfo
其中 contextPath 是環境路徑(Context path),是容器用來決定該挑選哪個 Web 應用程式的依據(一個容器上可能部署多個Web應用程式),在 Servlet 4.0 之前,環境路徑的設定並沒有標準規範,而是依伺服器實作而有所不同。例如在 Tomcat 9 中,可以設定 context.xml 的 <Context path="xxxx">
來決定,在 Servlet 4.0 中,可以於 web.xml 中使用 <default-context-path>
來設定預設路徑,然而,容器實作廠商可以覆蓋這個設定。
你可使用 HttpServletRequest
的 getContextPath()
來取得。如果應用程式環境路徑與 Web 伺服器環境根路徑相同,則應用程式環境路徑為空字串,如果不是,則應用程式環境路徑以 /
開頭,不包括 /
結尾。
一旦決定是哪個 Web 應用程式來處理請求,接下來就進行 Servlet 的挑選,Servlet 必須設定 URL 模式(URL pattern),可以設定的格式是:
/
開頭但/*
結尾的 URL 模式被用於路徑對應(Path mapping)。例如若設定 URL 模式為/guest/*
,則請求 URI 扣去環境路徑的部份若為 /guest/test.view、/guest/home.view 等以 /guest/ 作為開頭的,都會交由該Servlet處理。- 以
*.
開頭的 URL 模式被用於延伸對應(extension mapping)。例如若 URL 模式設定為*.view
,則所有以 .view 結尾的請求,都會交由該 Servlet 處理。 - 空字串是個特殊的URL模式,對應至環境根目錄(Context root),也就是
/
的請求,但不用於設置<url-pattern>
或urlPattern
屬性。例如若環境根目錄為App,則http://host:port/App/
的請求,路徑資訊是 /,而 Servlet 路徑與環境路徑都是空字串。 - 僅包括
/
的 URL 模式,表示預設 Servlet,當找不到適合的 URL 模式對應時,就會使用預設 Servlet。 - 其他的字串設定,都是用在於嚴格匹配(Exact match)。
如果 URL 模式在設定比對的規則在某些 URL 請求時有所重疊,例如若有 /admin/login.do
、/admin/*
與 *.do
三個URL模式設定,則請求時比對的原則是從最嚴格的 URL 模式開始符合。如果你請求 /admin/login.do,則一定是由 URL 模式設定為 /admin/login.do
的 Servlet 來處理,而不會是 /admin/*
或 *.do
。如果你請求 /admin/setup.do,則是由 /admin/*
的 Servlet 來處理,而不會是 *.do
。
在最上面的 requestURI 中,servletPath 的部份是指 Servlet 路徑(Servlet path),不包括路徑資訊(Path info)與請求參數(Request parameter)。Servlet 路徑直接對應至URL模式資訊,可使用 HttpServletRequest
的 getServletPath()
來取得,Servlet 路徑基本上是以 /
開頭,但 /*
與空字串的URL模式比對而來的請求除外,在 /*
與空字串的情況下,Servlet 路徑是 ""
。
例如若某個請求是根據 /hello.do
對應至 Servlet,則 Servlet 路徑就是 "/hello.do"
,如果是透過 /servlet/*
對應至 Servlet,則 Servlet 路徑就是 "/servlet"
,但如果是透過 /*
或空字串,則 Servlet 路徑就是 ""
。
在最上面的 requestURI 中,pathInfo 的部份是指路徑資訊(Path info),路徑資訊不包括請求參數,指的是不包括 Context Path 與 Servlet Path 部份的額外路徑資訊。可使用 HttpServletRequest
的 getPathInfo()
來取得。如果沒有額外路徑資訊,則為 null
(延伸對應、預設 Servlet、嚴格匹配的情況下),如果有額外路徑資訊,則是個以 "/"
為開頭的字串。
例如若對以下的 Servlet 請求之 URL 為 http://localhost:8080/ServletDemo/servlet/path:
package cc.openhome;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/servlet/*")
public class Path extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println(" <head>");
out.println(" <title>Path Servlet</title>");
out.println(" </head>");
out.println(" <body>");
out.println(request.getRequestURI() + "<br>");
out.println(request.getContextPath() + "<br>");
out.println(request.getServletPath() + "<br>");
out.println(request.getPathInfo());
out.println(" </body>");
out.println("</html>");
}
}
則會顯示以下的內容:
<!DOCTYPE html>
<html>
<head>
<title>Path Servlet</title>
</head>
<body>
/ServletDemo/servlet/path<br>
/ServletDemo<br>
/servlet<br>
/path
</body>
</html>
在 Servlet 4.0 中,HttpServletRequest
新增了 getHttpServletMapping()
方法,可以取得 javax.servlet.http.HttpServletMapping
實作物件,透過該物件,可以在執行時期,偵測執行中的 Servlet,是透過哪個 URL 對應而來,以及被比對到的值為何等,例如:
package cc.openhome;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/servlet/*")
public class Path extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpServletMapping mapping = request.getHttpServletMapping();
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println(" <head>");
out.println(" <title>Path Servlet</title>");
out.println(" </head>");
out.println(" <body>");
out.println(mapping.getMappingMatch() + "<br>");
out.println(mapping.getMatchValue() + "<br>");
out.println(mapping.getPattern());
out.println(" </body>");
out.println("</html>");
}
}
HttpServletMapping
的 getMappingMatch()
會傳回 javax.servlet.http.MappingMatch
列舉值,成員有 CONTEXT_ROOT
、DEFAULT
、EXACT
、EXTENSION
與 PATH
,個別的 URL 模式意義在前面有談過了。
getMatchValue()
會傳回實際上符合的比對值,getPattern()
傳回使用之 URL 模式,例如,若請求 http://localhost:8080/ServletDemo/servlet/path,那麼會路徑比對成功,而比對值是 path,結果會顯示如下:
<!DOCTYPE html>
<html>
<head>
<title>Path Servlet</title>
</head>
<body>
PATH<br>
path<br>
/servlet/*
</body>
</html>