目錄1. Servlet 規范解讀 1.1. Use of URL Paths 1.2. Specification of Mappings2. Tomcat 源碼分析 2.1. 幾個概念 2.2. <url-pattern> 校驗規則 2.3. <url-pattern> 如何分類 2.4. <url-pattern> 分類過程 2.5. <url-pattern> 匹配過程3. 綜合示例
1. Servlet 規范解讀
1.1. Use of URL Paths
Upon receipt of a client request, the Web container determines the Web application to which to forward it. The Web application selected must have the longest context path that matches the start of the request URL.The matched part of the URL is the context path when mapping to servlets.
The Web container next must locate the servlet to process the request using the path mapping procedure described below.
The path used for mapping to a servlet is the request URL from the request object minus the context path and the path parameters. The URL path mapping rules below are used in order. The first successful match is used with no further matches attempted:
The container must use case-sensitive string comparisons for matching.
1.2. Specification of Mappings
In the Web application deployment descriptor, the following syntax is used to define mappings:
If the effective web.xml (after merging information from fragments and annotations) contains any url-patterns that are mapped to multiple servlets then the deployment must fail.
2. Tomcat 源碼分析
2.1. 幾個概念
在分析之前簡單看下tomcat源碼中的幾個概念,Context、Wrapper、Servlet:
2.2. <url-pattern> 校驗規則
org.apache.catalina.core.StandardContext.java:
/** * Adjust the URL pattern to begin with a leading slash, if appropriate * (i.e. we are running a servlet 2.2 application). Otherwise, return * the specified URL pattern unchanged. * * @param urlPattern The URL pattern to be adjusted (if needed) * and returned * @return the URL pattern with a leading slash if needed */protected String adjustURLPattern(String urlPattern) { if (urlPattern == null) return urlPattern; if (urlPattern.startsWith("/") || urlPattern.startsWith("*.")) return urlPattern; if (!isServlet22()) return urlPattern; if(log.isDebugEnabled()) log.debug(sm.getString("standardContext.urlPattern.patternWarning", urlPattern)); return "/" + urlPattern;}/** * Validate the syntax of a proposed <code><url-pattern></code> * for conformance with specification requirements. * * @param urlPattern URL pattern to be validated * @return <code>true</code> if the URL pattern is conformant */private boolean validateURLPattern(String urlPattern) { if (urlPattern == null) return false; if (urlPattern.indexOf('n') >= 0 || urlPattern.indexOf('r') >= 0) { return false; } if (urlPattern.equals("")) { return true; } if (urlPattern.startsWith("*.")) { if (urlPattern.indexOf('/') < 0) { checkUnusualURLPattern(urlPattern); return true; } else return false; } if ( (urlPattern.startsWith("/")) && (urlPattern.indexOf("*.") < 0)) { checkUnusualURLPattern(urlPattern); return true; } else return false;}/** * Check for unusual but valid <code><url-pattern></code>s. * See Bugzilla 34805, 43079 & 43080 */private void checkUnusualURLPattern(String urlPattern) { if (log.isInfoEnabled()) { // First group checks for '*' or '/foo*' style patterns // Second group checks for *.foo.bar style patterns if((urlPattern.endsWith("*") && (urlPattern.length() < 2 || urlPattern.charAt(urlPattern.length()-2) != '/')) || urlPattern.startsWith("*.") && urlPattern.length() > 2 && urlPattern.lastIndexOf('.') > 1) { log.info("Suspicious url pattern: "" + urlPattern + """ + " in context [" + getName() + "] - see" + " sections 12.1 and 12.2 of the Servlet specification"); } }}
2.3. <url-pattern> 如何分類
org.apache.catalina.mapper.Mapper.java#ContextVersion
protected static final class ContextVersion extends MapElement<Context> { public final String path; public final int slashCount; public final WebResourceRoot resources; public String[] welcomeResources; public MappedWrapper defaultWrapper = null; public MappedWrapper[] exactWrappers = new MappedWrapper[0]; public MappedWrapper[] wildcardWrappers = new MappedWrapper[0]; public MappedWrapper[] extensionWrappers = new MappedWrapper[0]; ...}
2.4. <url-pattern> 分類過程
org.apache.catalina.mapper.Mapper.java
/** * Adds a wrapper to the given context. * * @param context The context to which to add the wrapper * @param path Wrapper mapping * @param wrapper The Wrapper object * @param jspWildCard true if the wrapper corresponds to the JspServlet * and the mapping path contains a wildcard; false otherwise * @param resourceOnly true if this wrapper always expects a physical * resource to be present (such as a JSP) */protected void addWrapper(ContextVersion context, String path, Wrapper wrapper, boolean jspWildCard, boolean resourceOnly) { synchronized (context) { if (path.endsWith("/*")) { // Wildcard wrapper String name = path.substring(0, path.length() - 2); MappedWrapper newWrapper = new MappedWrapper(name, wrapper, jspWildCard, resourceOnly); MappedWrapper[] oldWrappers = context.wildcardWrappers; MappedWrapper[] newWrappers = new MappedWrapper[oldWrappers.length + 1]; if (insertMap(oldWrappers, newWrappers, newWrapper)) { context.wildcardWrappers = newWrappers; int slashCount = slashCount(newWrapper.name); if (slashCount > context.nesting) { context.nesting = slashCount; } } } else if (path.startsWith("*.")) { // Extension wrapper String name = path.substring(2); MappedWrapper newWrapper = new MappedWrapper(name, wrapper, jspWildCard, resourceOnly); MappedWrapper[] oldWrappers = context.extensionWrappers; MappedWrapper[] newWrappers = new MappedWrapper[oldWrappers.length + 1]; if (insertMap(oldWrappers, newWrappers, newWrapper)) { context.extensionWrappers = newWrappers; } } else if (path.equals("/")) { // Default wrapper MappedWrapper newWrapper = new MappedWrapper("", wrapper, jspWildCard, resourceOnly); context.defaultWrapper = newWrapper; } else { // Exact wrapper final String name; if (path.length() == 0) { // Special case for the Context Root mapping which is // treated as an exact match name = "/"; } else { name = path; } MappedWrapper newWrapper = new MappedWrapper(name, wrapper, jspWildCard, resourceOnly); MappedWrapper[] oldWrappers = context.exactWrappers; MappedWrapper[] newWrappers = new MappedWrapper[oldWrappers.length + 1]; if (insertMap(oldWrappers, newWrappers, newWrapper)) { context.exactWrappers = newWrappers; } } }}
2.5. <url-pattern> 匹配過程
org.apache.catalina.mapper.Mapper.java
/** * Wrapper mapping. * @throws IOException if the buffers are too small to hold the results of * the mapping. */private final void internalMapWrapper(ContextVersion contextVersion, CharChunk path, MappingData mappingData) throws IOException { // ... // Rule 1 -- Exact Match MappedWrapper[] exactWrappers = contextVersion.exactWrappers; internalMapExactWrapper(exactWrappers, path, mappingData); // Rule 2 -- Prefix Match boolean checkJspWelcomeFiles = false; MappedWrapper[] wildcardWrappers = contextVersion.wildcardWrappers; if (mappingData.wrapper == null) { internalMapWildcardWrapper(wildcardWrappers, contextVersion.nesting, path, mappingData); // ... } // ... // Rule 3 -- Extension Match MappedWrapper[] extensionWrappers = contextVersion.extensionWrappers; if (mappingData.wrapper == null && !checkJspWelcomeFiles) { internalMapExtensionWrapper(extensionWrappers, path, mappingData, true); } // Rule 4 -- Welcome resources processing for servlets if (mappingData.wrapper == null) { boolean checkWelcomeFiles = checkJspWelcomeFiles; // ... } // ... // Rule 7 -- Default servlet if (mappingData.wrapper == null && !checkJspWelcomeFiles) { if (contextVersion.defaultWrapper != null) { mappingData.wrapper = contextVersion.defaultWrapper.object; mappingData.requestPath.setChars (path.getBuffer(), path.getStart(), path.getLength()); mappingData.wrapperPath.setChars (path.getBuffer(), path.getStart(), path.getLength()); mappingData.matchType = MappingMatch.DEFAULT; } // ... } // ...}
3. 綜合示例
web.xml:
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <display-name>urlpattern</display-name> <servlet> <servlet-name>Servlet1</servlet-name> <servlet-class>com.Servlet1</servlet-class> </servlet> <servlet> <description></description> <servlet-name>Servlet2</servlet-name> <servlet-class>com.Servlet2</servlet-class> </servlet> <servlet> <servlet-name>Servlet3</servlet-name> <servlet-class>com.Servlet3</servlet-class> </servlet> <servlet> <servlet-name>Servlet4</servlet-name> <servlet-class>com.Servlet4</servlet-class> </servlet> <servlet> <servlet-name>Servlet5</servlet-name> <servlet-class>com.Servlet5</servlet-class> </servlet> <servlet> <servlet-name>Servlet6</servlet-name> <servlet-class>com.Servlet6</servlet-class> </servlet> <servlet-mapping> <servlet-name>Servlet1</servlet-name> <url-pattern>/Servlet1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Servlet2</servlet-name> <url-pattern>/Servlet2/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Servlet6</servlet-name> <url-pattern>/Servlet6/</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Servlet4</servlet-name> <url-pattern>*.foo</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Servlet3</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Servlet5</servlet-name> <url-pattern></url-pattern> </servlet-mapping></web-app>
測試url:
http://localhost:8080/urlpattern/Servlet2http://localhost:8080/urlpattern/Servlet2/a/b/c/dhttp://localhost:8080/urlpattern/Servlet1http://localhost:8080/urlpattern/Servlet6/http://localhost:8080/urlpattern/ServletX/l/m/n/x.foohttp://localhost:8080/urlpattern/http://localhost:8080/urlpatternhttp://localhost:8080/urlpattern/Servlet6http://localhost:8080/urlpattern/Servlet1/http://localhost:8080/urlpattern/ServletY/NOT/EXIST/
測試結果:
參考:
JSR-000340 JavaTM Servlet 3.1 Final Release for Evaluation:https://download.oracle.com/otndocs/jcp/servlet-3_1-fr-eval-spec/index.html
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
炫舞怎么得消費券?通常它 這是GM的活動。和節假日一樣,周末會有14 : 00-16 : 00在線,贈送優惠券和購物券。。。但是購物券只能和第一期q幣一起使用。在炫舞游戲里怎樣快速刷點券?:我們有三種可以拿到點卷。1.騰訊將游戲中的積分滾動獎勵設置在節假日或周末。15: 00、16: 02快速升級平刷做任務,刷明星挑戰模式,轉音樂。3.每天領工資。每天完成十場兩人以上的比賽,可以獲得日薪卷。炫舞手...
怎么登錄青驕第二課堂?首先點擊鏈接https://www.2-class.com/competition進入清教第二課堂官方網站后,電腦用戶點擊網站第一個登錄頁面進入賬號登錄界面,手機用戶點擊我的課程進入賬號登錄界面。2-class平臺怎么注冊?點擊flash場景右上角的【注冊】按鈕,進入注冊頁面,根據頁面要求填寫注冊信息,注冊成功。注意:不支持個人注冊帳戶。所有參與者的帳號和密碼均由學校管理員提...
成都哪家工作室拍藝術照拍的更好呢?1.木沙英花婚紗攝影工作室地址:嬌子北二路61號馮丹國際地鐵1號線金融城A出口顧客評價:能在沐沙英花拍婚紗照真的超級開心。剛到店的時候,感覺超級驚喜。給我的感覺是,只要是女生,我都會喜歡。2.八點半去照相館地址:較場壩街東方廣場B座停車場入口2單元1207室客戶評價:體驗很棒。提前兩天預約。到達當天,店家會提前打電話確認時間。到了就不用等了,馬上就可以開始化妝。3...