標籤:
如果你的DispatcherServlet攔截 *.do這樣的URL,就不存在訪問不到靜態資源的問題。如果你的DispatcherServlet攔截“/”,攔截了所有的請求,同時對*.js,*.jpg的訪問也就被攔截了。
目的:可以正常訪問靜態檔案,不要找不到靜態檔案報404。
方案一:啟用Tomcat的defaultServlet來處理靜態檔案
Xml代碼
<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>
要寫在DispatcherServlet的前面, 讓 defaultServlet先攔截,這個就不會進入Spring了。
方案二: 在spring3.0.4以後版本提供了mvc:resources 的使用方法:
Xml代碼
<!-- 對靜態資源檔案的訪問 --> <mvc:resources mapping="/images/**" location="/images/" />
/images/**映射到ResourceHttpRequestHandler進行處理,location指定靜態資源的位置.可以是web application根目錄下、jar包裡面,這樣可以把靜態資源壓縮到jar包中。cache-period 可以使得靜態資源進行web cache 如果出現下面的錯誤,可能是沒有配置<mvc:annotation-driven />的原因。 報錯WARNING: No mapping found for HTTP request with URI [/mvc/user/findUser/lisi/770] in DispatcherServlet with name ‘springMVC‘
使用<mvc:resources/>元素,把mapping的URI註冊到SimpleUrlHandlerMapping的urlMap中,key為mapping的URI pattern值,而value為ResourceHttpRequestHandler,這樣就巧妙的把對靜態資源的訪問由HandlerMapping轉到ResourceHttpRequestHandler處理並返回,所以就支援classpath目錄,jar包內靜態資源的訪問.另外需要注意的一點是,不要對SimpleUrlHandlerMapping設定defaultHandler。因為對static uri的defaultHandler就是ResourceHttpRequestHandler,否則無法處理static resources request。
方案三 ,使用<mvc:default-servlet-handler/>
Xml代碼
<mvc:default-servlet-handler/>
會把"/**" url,註冊到SimpleUrlHandlerMapping的urlMap中,把對靜態資源的訪問由HandlerMapping轉到org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler處理並返回DefaultServletHttpRequestHandler使用,就是各個Servlet容器自己的預設Servlet。
補充說明:多個HandlerMapping的執行順序問題:
DefaultAnnotationHandlerMapping的order屬性值是:0
<mvc:resources/ >自動註冊的SimpleUrlHandlerMapping的order屬性值是:2147483646<mvc:default-servlet-handler/>自動註冊的SimpleUrlHandlerMapping的order屬性值是:2147483647
spring會先執行order值比較小的。當訪問一個a.jpg圖片檔案時,先通過DefaultAnnotationHandlerMapping來找處理器,一定是找不到的,我們沒有叫a.jpg的Action。再按order值升序找,由於最後一個SimpleUrlHandlerMapping是匹配"/**"的,所以一定會匹配上,再響應圖片。
註:如果DispatcherServlet攔截 *.do這樣的URL,就不存上述問題了。
方案四、認真閱讀spring的源碼,好好理解一下。
17.16.7 Serving of Resources
This option allows static resource requests following a particular URL pattern to be served by a ResourceHttpRequestHandler from any of a list of Resource locations. This provides a convenient way to serve static resources from locations other than the web application root, including locations on the classpath. The cache-period property may be used to set far future expiration headers (1 year is the recommendation of optimization tools such as Page Speed and YSlow) so that they will be more efficiently utilized by the client. The handler also properly evaluates the Last-Modified header (if present) so that a 304 status code will be returned as appropriate, avoiding unnecessary overhead for resources that are already cached by the client. For example, to serve resource requests with a URL pattern of /resources/** from a public-resources directory within the web application root you would use:
@Configuration@EnableWebMvcpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/"); }}
And the same in XML:
<mvc:resources mapping="/resources/**" location="/public-resources/"/>
To serve these resources with a 1-year future expiration to ensure maximum use of the browser cache and a reduction in HTTP requests made by the browser:
@Configuration@EnableWebMvcpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926); }}
And in XML:
<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>
The mapping attribute must be an Ant pattern that can be used by SimpleUrlHandlerMapping, and the location attribute must specify one or more valid resource directory locations. Multiple resource locations may be specified using a comma-separated list of values. The locations specified will be checked in the specified order for the presence of the resource for any given request. For example, to enable the serving of resources from both the web application root and from a known path of /META-INF/public-web-resources/ in any jar on the classpath use:
@EnableWebMvc@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/", "classpath:/META-INF/public-web-resources/"); }}
And in XML:
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>
When serving resources that may change when a new version of the application is deployed it is recommended that you incorporate a version string into the mapping pattern used to request the resources so that you may force clients to request the newly deployed version of your application’s resources. Support for versioned URLs is built into the framework and can be enabled by configuring a resource chain on the resource handler. The chain consists of one more ResourceResolver instances followed by one or more ResourceTransformer instances. Together they can provide arbitrary resolution and transformation of resources.
The built-in VersionResourceResolver can be configured with different strategies. For example a FixedVersionStrategy can use a property, a date, or other as the version. A ContentVersionStrategy uses an MD5 hash computed from the content of the resource (known as "fingerprinting" URLs).
ContentVersionStrategy is a good default choice to use except in cases where it cannot be used (e.g. with JavaScript module loaders). You can configure different version strategies against different patterns as shown below. Keep in mind also that computing content-based versions is expensive and therefore resource chain caching should be enabled in production.
Java config example;
@Configuration@EnableWebMvcpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/resources/**") .addResourceLocations("/public-resources/") .resourceChain(true).addResolver( new VersionResourceResolver().addContentVersionStrategy("/**")); }}
XML example:
<mvc:resources mapping="/resources/**" location="/public-resources/"><mvc:resource-chain><mvc:resource-cache /><mvc:resolvers><mvc:version-resolver><mvc:content-version-strategy patterns="/**"/></mvc:version-resolver></mvc:resolvers></mvc:resource-chain></mvc:resources>
In order for the above to work the application must also render URLs with versions. The easiest way to do that is to configure the ResourceUrlEncodingFilter which wraps the response and overrides its encodeURL method. This will work in JSPs, FreeMarker, Velocity, and any other view technology that calls the response encodeURL method. Alternatively, an application can also inject and use directly the ResourceUrlProvider bean, which is automatically declared with the MVC Java config and the MVC namespace.
17.16.8 Falling Back On the "Default" Servlet To Serve Resources
This allows for mapping the DispatcherServlet to "/" (thus overriding the mapping of the container’s default Servlet), while still allowing static resource requests to be handled by the container’s default Servlet. It configures a DefaultServletHttpRequestHandler with a URL mapping of "/**" and the lowest priority relative to other URL mappings.
This handler will forward all requests to the default Servlet. Therefore it is important that it remains last in the order of all other URL HandlerMappings. That will be the case if you use <mvc:annotation-driven> or alternatively if you are setting up your own customized HandlerMapping instance be sure to set its order property to a value lower than that of the DefaultServletHttpRequestHandler, which is Integer.MAX_VALUE.
To enable the feature using the default setup use:
@Configuration@EnableWebMvcpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); }}
Or in XML:
<mvc:default-servlet-handler/>
The caveat to overriding the "/" Servlet mapping is that the RequestDispatcher for the default Servlet must be retrieved by name rather than by path. The DefaultServletHttpRequestHandler will attempt to auto-detect the default Servlet for the container at startup time, using a list of known names for most of the major Servlet containers (including Tomcat, Jetty, GlassFish, JBoss, Resin, WebLogic, and WebSphere). If the default Servlet has been custom configured with a different name, or if a different Servlet container is being used where the default Servlet name is unknown, then the default Servlet’s name must be explicitly provided as in the following example:
@Configuration@EnableWebMvcpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable("myCustomDefaultServlet"); }}
Or in XML:
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>
Spring MVC如何訪問到靜態檔案,如jpg,js,css?