有一個需求:讓一個Servlet能夠同時處理形如/XXX/YYY
和/XXX/YYY/
的URI,即URI尾部的斜槓有沒有都要能處理到。
很容易想到,做兩個URL Pattern/XXX/YYY
和/XXX/YYY/
對映到該Servlet,問題就解決了。
但如果URI是動態的呢?比如XXX
和YYY
都是不確定的,成分數量也是不確定的,但處理邏輯又是相同的,那麼就需要將任意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);
}
}