當 DispatcherServlet 映射為 / 時,會攔截所有請求導致靜態資源(JS、CSS、圖片)返回 404。本文總結三種標準解決方案,並分析其原理、優缺點與執行順序。
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern> <!-- 攔截所有請求 -->
</servlet-mapping>
靜態資源請求進入 Spring MVC,找不到對應 @Controller,拋出 No mapping found。
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
DefaultServlet 先處理靜態資源,不進入 Spring。default, WebLogic: FileServlet, WebSphere: SimpleFileServlet)。DispatcherServlet 映射之前。
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:resources mapping="/static/**" location="classpath:/static/" cache-period="31536000" />
ResourceHttpRequestHandler 到 SimpleUrlHandlerMapping,order=2147483646。cache-period 設定 Cache-Control 標頭。<mvc:annotation-driven />,否則會報 No mapping found。SimpleUrlHandlerMapping 設定 defaultHandler,否則靜態資源無法處理。
<mvc:default-servlet-handler />
DefaultServletHttpRequestHandler 到 SimpleUrlHandlerMapping,order=2147483647(最低優先級),匹配 /**。| HandlerMapping | Order | 匹配模式 |
|---|---|---|
| DefaultAnnotationHandlerMapping | 0 | @RequestMapping |
| ResourceHttpRequestHandler (mvc:resources) | 2147483646 | /resources/** |
| DefaultServletHttpRequestHandler (default-servlet-handler) | 2147483647 | /** |
請求流程:@Controller 先匹配 → 失敗 → mvc:resources → 失敗 → default-servlet-handler(容器 DefaultServlet)。
<mvc:resources> 映射 /static/**、/assets/**,資源放 src/main/resources/static 或 src/main/webapp/static。DispatcherServlet 映射為 *.do、*.action 等後綴,雖能解決靜態資源問題,但不符合 REST 風格。三種方案各有適用場景:容器級方案效能最好但配置繁瑣;mvc:resources 功能最豐富支援 Classpath/Jar;mvc:default-servlet-handler 最省事。現代 Spring Boot 專案預設已配置 ResourceHttpRequestHandler,資源置於 static/public/resources/META-INF/resources 即可自動生效。