有一個需求:讓一個Servlet能夠同時處理形如/XXX/YYY/XXX/YYY/的URI,即URI尾部的斜槓有沒有都要能處理到。

很容易想到,做兩個URL Pattern/XXX/YYY/XXX/YYY/對映到該Servlet,問題就解決了。

但如果URI是動態的呢?比如XXXYYY都是不確定的,成分數量也是不確定的,但處理邏輯又是相同的,那麼就需要將任意URI都對映到該Servlet上。為了使靜態資源能正常響應而不匹配進來,URL Pattern不要寫/*,而是寫/(fallback匹配),同時在web.xml中做靜態資原始檔的URL Pattern(如*.css)對映到default(因為優先順序*.xxx > / > 靜態資源預設)。

此時,靜態資源的URI和形如/XXX/YYY(尾部無斜槓)的URI就都能正常響應了,但是/XXX/YYY/(尾部有斜槓)卻404,原因是Servlet容器將尾部帶斜槓的URI看做是靜態資源了,在沒有精確匹配的情況下,會作為目錄去匹配預設主頁檔案(實際請求/XXX/YYY/index.html)。也就是說,請求根本就沒有走到預期的Servlet中。

那怎麼辦呢?難道用/*Servlet抓到所有的請求,然後自己做分發?很麻煩,而且對於靜態資源是重複造輪子。

解決思路其實很簡單,用Filter把尾部斜槓去掉,然後內部轉發一下就可以了。Filter用URL Pattern/*抓到所有請求,如果發現URI尾部帶斜槓,就移除尾部斜槓然後轉發,否則正常放行。

@WebFilter("/*")
public class TheFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
String uri = httpRequest.getRequestURI();
if (uri.endsWith("/")) {
uri = uri.substring(0, uri.length() - 1);
httpRequest.getRequestDispatcher(uri).forward(servletRequest, servletResponse);
return;
} filterChain.doFilter(servletRequest, servletResponse);
}
}