傳統 Spring MVC 依賴固定後綴。本文實現一個基於 Filter 的通用 Dispatcher,支援任意自定義擴展名或完全無擴展名的 REST 風格 URL 路由。
javax.servlet.Filter,攔截所有請求。extension:.do、.action、空串(無擴展名)。servletPath,命中則路由到 Action 處理鏈,否則 chain.doFilter 放行靜態資源。public class Dispatcher implements Filter {
private static final Logger log = Logger.getLogger(Dispatcher.class);
private static String ext = SimpleConfig.getConfig("extension"); // 可為空
private static String regex;
static {
if (ext == null || ext.length() <= 1) {
ext = "";
regex = ".*?/[^\\.]*?$"; // 無擴展名:最後一段不含點
} else {
if (ext.charAt(0) != '.') ext = "." + ext;
regex = ".*?\\." + ext.substring(1) + "$";
}
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
String servletPath = request.getServletPath();
if (servletPath.matches(regex)) {
long start = System.currentTimeMillis();
String actionName = servletPath.substring(1, servletPath.length() - ext.length())
.replace("/", ".");
ActionContext ctx = SimpleConfig.getActionContext(actionName);
if (ctx != null) {
new ActionContainer(ctx, request, (HttpServletResponse) res).process();
}
log.info("Dispatcher: " + servletPath + ": " + (System.currentTimeMillis() - start) + "ms");
} else {
chain.doFilter(req, res);
}
}
// init/destroy 省略
}
| extension 配置 | regex | 匹配示例 | 不匹配示例 |
|---|---|---|---|
| .do | .*?\.do$ | /user/login.do | /user/login.jsp、/static/style.css | (空) | .*?/[^\\.]*?$ | /user/login、/api/v1/users | /user/login.do、/api/v1/users.json |
web.xml 首位註冊,url-pattern>/*。SimpleConfig 實現 Action 名稱到處理器映射(可掃描註解/配置文件)。/static/、*.css、*.js),或由默認 Servlet 處理。Filter 級 Dispatcher 輕量、無侵入、靈活適配各類 URL 風格,是輕量級 MVC 框架或遷移舊系統的理想選擇。生產環境建議增加:路由緩存、異常統一處理、執行耗時監控、安全過濾器鏈整合。