Spring静态资源处理的两种解决方案
一、采用<mvc:default-servlet-handler />
若是基于XML的方式,我们会配置一个:
<mvc:default-servlet-handler />
来专门处理静态资源文件。它其实就是向MVC的容器内注入了一个DefaultServletHttpRequestHandler实例,它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web应用服务器默认的Servlet处理,如果不是静态资源的请求,才由DispatcherServlet继续处理。
一般Web应用服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。如果你所有的Web应用服务器的默认Servlet名称不是"default",则需要通过default-servlet-name属性显示指定:<mvc:default-servlet-handler default-servlet-name="xxx" />
如果你是基于注解驱动的呢?这么做即可:
@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
// 注册 一个默认的servlet处理器 让它处理静态资源
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
DefaultServletHandlerConfigurer handlerConfigurer = new DefaultServletHandlerConfigurer(servletContext);
// 这个Configurer只有一个enable方法,内部会 new DefaultServletHttpRequestHandler();
handlerConfigurer.enable("default"); //默认值的servlet名字就是default
super.configureDefaultServletHandling(configurer);
}
}
<mvc:default-servlet-handler />将静态资源的处理经由Spring MVC框架交回Web应用服务器处理。
二、采用<mvc:resources /> (重点了解)
<mvc:resources />相比前一种方式更进一步,由Spring MVC框架自己处理静态资源,并添加一些有用的附加值功能。
首先,<mvc:resources />允许静态资源放在任何地方,如WEB-INF目录下、类路径下等,你甚至可以将JavaScript等静态文件打到JAR包中(为后续的webjar做好了充分的支持~)。通过location属性指定静态资源的位置,由于location属性是Resources类型,因此可以使用诸如"classpath:"等的资源前缀指定资源位置。
传统Web容器的静态资源只能放在Web容器的根路径下,<mvc:resources />完全打破了这个限制。
其次,<mvc:resources />
依据当前著名的Page Speed
、YSlow
等浏览器优化原则对静态资源提供优化。你可以通过cacheSeconds
属性指定静态资源在浏览器端的缓存时间,一般可将该时间设置为一年,以充分利用浏览器端的缓存。在输出静态资源时,会根据配置设置好响应报文头的Expires
和 Cache-Control
值。
这样在接收到静态资源的获取请求时,会检查请求头的Last-Modified
值,如果静态资源没有发生变化,则直接返回303/304响应状态码
,提示客户端使用浏览器缓存的数据,而非将静态资源的内容输出到客户端,以充分节省带宽,提高程序性能。
基于XML的使用示例:
<!-- 一次性可以写多个路径,里面都可议放置静态资源文件~ location表示资源文件的位置 mapping:表示请求URL-->
<mvc:resources location="/,classpath:/META-INF/publicResources/" mapping="/resources/**"/>
// 当然我们也可以写成多个,类似这样子
<mvc:resources location="/img/" mapping="/img/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<mvc:resources location="/css/" mapping="/css/**"/>
以上配置将Web根路径"/"及类路径下 /META-INF/publicResources/ 的目录映射为/resources路径。
它的核心处理类为:ResourceHttpRequestHandler,也是个HttpRequestHandler。ResourcesBeanDefinitionParser是用于解析XML里的这个标签的~~~~
如果你是基于注解驱动的呢?这么做即可:
@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resource/**").addResourceLocations("/WEB-INF/static/"); // 支持Ant风格的路径匹配
}
}
三、Spring MVC中对静态资源的访问
1、当静态资源放在webapp下面的时候,可直接通过浏览器访问,不需要配置映射,安全性略低,对应的访问效率就略高。
但是静态资源若很多,访问频率很高的话,强烈建议放在静态服务器或者CDN上,不要放在tomcat里,这不是它擅长的。
2、WEB-INF是Java的WEB应用的安全目录。所谓安全就是客户端无法直接访问,只有服务端可以访问的目录(所以理论上必须经过controller)
对于第一点这里需要强调一下:其实这么说是有问题的。因为我们一般会把DispatcherServlet映射为 /从而拦截所有的请求(包括静态资源的请求),所以如果直接访问就找不到Handler还是会报404的。
那么现在问题就来了,Spring MVC下怎么让访问WEB-INF下面的静态资源呢?
比如现在我有如下静态资源:
通过浏览器直接访问肯定是会404的,但是因为它是html文件,我们也不能通过controller直接转发,那肿么办呢?
如果我们之前的Spring MVC项目是基于xml的,相信很多人都看到过如下的配置项:
<mvc:default-servlet-handler/>
...
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>
<mvc:resources mapping="/html/**" location="/html/"/>
// 备注两种只需要配其一,其中<mvc:resources />是被推荐的方式
如果是Java代码方式:
这里只说<mvc:resources />对应的ResourceHandler方式:ResourceHttpRequestHandler
@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resource/**").addResourceLocations("/WEB-INF/static/");
// 备注这里addResourceLocations(“file:D:/”)这样都是支持的~~~~~
}
}
这样只要我们访问路径中是匹配/resource/**的,那就能够访问了。比如上面截图中的1.html我们这样访问:http://localhost:8080/demo_war_war/resource/1.html就能正常访问到了。(相当于路径中给加个/resource/)
那它的基本原理是什么呢?
就是向容器注册了一个ResourceHttpRequestHandler
,它是一个HttpRequestHandler
。
DefaultServletHttpRequestHandler它也是一个HttpRequestHandler
四、/ 和 /*有什么区别?
/会拦截除了jsp以外的所有url,/ 会拦截所有url,包括jsp。*
例如:在webroot下面有一个test.jsp,当DispatcherServlet 配置映射/ 时,浏览器输入:http://localhost:8080/test.jsp 这个jsp是可以直接访问的,并且不经过DispatcherServlet ;而当DispatcherServlet 配置映射/* 时,这个请求就会被DispatcherServlet 拦截。
整理自:https://blog.csdn.net/f641385712/article/details/89845181