实验结论
这篇文章记录的是springMVC中关于静态资源放行、自定义视图解析器以及WEB-INF下的资源请求问题,虽然学的时候这些概念都明白,但是在开发中却经常混淆,特地花两小时来做测试后才写下此篇文章
接下来说一下我得出的结论:
1. jsp文件不会经过单元方法匹配问题(但html、css、js、image等都会经过单元方法匹配)
2. 静态资源放行的优先级低于单元方法的匹配,静态资源放行的url不要和单元方法冲突,若冲突则静态资源放行不生效
3. WEB-INF下的资源虽然不能通过浏览器直接访问,但是我们可以通过请求转发和静态资源放行的机制访问
4. 访问jsp时不会经过静态资源放行(但html会)
踩坑记录
情景一:
先配置视图解析器,将请求转发至WEB-INF/page下,再配置restful格式的单元方法,该方法仅仅返回请求地址,作用是配合视图解析器使得浏览器可以访问WEB-INF下的资源。那我们来看看jsp请求能被单元方法匹配到并正确转发吗?
代码
静态资源放行、自定义视图解析器
<!-- 3.配置静态资源放行 -->
<mvc:resources mapping="/js/**" location="/WEB-INF/js/"></mvc:resources>
<mvc:resources mapping="/css/**" location="WEB-INF/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="WEB-INF/images/"></mvc:resources>
<!-- 4.配置自定义视图解析器 -->
<bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/"></property>
<property name="suffix" value=" "></property>
</bean>
通过这段代码配置了静态资源放行以及自定义视图,我们可以看到当url匹配js/xxx、css/xxx、images/xxx的时候,我们可以通过静态资源放行跳转到WEB-INF/js(css、images)下的资源。我不配置后缀名的想法是我想通过该视图解析器访问WEB-INF/page下的任何资源,如果设置了后缀名就将资源类型限定死了。
restful代码
@RequestMapping("{page}/{url}")
public String getPage(@PathVariable String url){
System.out.println("restful:"+url);
return url;
}
该段代码的作用是配合自定义视图解析器使得浏览器可以访问WEB-INF下的资源
文件层级
我们可以看到WEB-INF下有一个page文件夹,接下来我们尝试通过匹配getPage方法,来访问此WEB-INF/page/index.jsp.
结果
我们可以看到结果是访问page/index.jsp时出现404,这是怎么回事呢?结论的第一条有说过,jsp文件不经过DispatcherServlet,根本就不会跟单元方法进行匹配。
可是我把restful改一改。
@RequestMapping("{url}/{xxx}")
public String getPage(@PathVariable String url){
System.out.println("restful:"+url);
return url;
}
不少小伙伴问,不是说jsp文件的请求不会和单元方法匹配嘛,这不还是匹配到了restful格式的方法,是的,的确匹配到了,但是它压根不是jsp请求。大家仔细看看
http://localhost:8080/springMVC_02_war_exploded/index.jsp/xxx这个格式是jsp请求嘛,jsp只是路径的一段而已,此时服务器将index.jsp解析为一个层级而已而不是jsp文件。
情景二
刚刚我们已经测试了jsp文件的请求不会经过单元方法,那它会经过静态资源放行吗?
代码
<!-- 3.配置静态资源放行 -->
<mvc:resources mapping="/js/**" location="/WEB-INF/js/"></mvc:resources>
<mvc:resources mapping="/page/**" location="/WEB-INF/page/"></mvc:resources>
<mvc:resources mapping="/css/**" location="WEB-INF/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="WEB-INF/images/"></mvc:resources>
<!-- 4.配置自定义视图解析器 -->
<bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/"></property>
<property name="suffix" value=""></property>
</bean>
单元方法
@RequestMapping("{url}")
public String getPage(@PathVariable String url){
System.out.println("restful:"+url);
return url;
}
文件层级
结果
我们可以看到,我们发起的是page/index.jsp的请求,根据资源放行机制应该跳转到WEB-INF/page/index.jsp资源,可是却报错/page/index.jsp未找到,说明jsp请求也没有经过静态资源放行。
根本原因:jsp请求没有经过DispatcherServlet,而不管是静态资源放行或者单元方法匹配都是基于DispatcherServlet的,所以静态资源放行也无法转发jsp请求
我们再看看访问html是否成功来验证结果。
不出意外,访问成功。
情景三
此时我想比较静态资源放行的转发和单元方法匹配谁优先级更高。
代码
<!-- 3.配置静态资源放行 -->
<mvc:resources mapping="/js/**" location="/WEB-INF/js/"></mvc:resources>
<mvc:resources mapping="/page/**" location="/page/"></mvc:resources>
<mvc:resources mapping="/css/**" location="WEB-INF/css/"></mvc:resources>
<mvc:resources mapping="/images/**" location="WEB-INF/images/"></mvc:resources>
<!-- 4.配置自定义视图解析器 -->
<bean id="resourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/page/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
@RequestMapping("{url}")
public String getPage(@PathVariable String url){
System.out.println("restful:"+url);
return url;
}
我们注意,此时我给自定义视图加上了后缀,我可以通过访问/index来跳转到/WEB-INF/page/index.jsp文件。
文件层级
按照该文件层级,当我访问/page/index时的时候,若是静态资源优先则会报错,若是单元方法优先则成功访问
结果
成功访问,我们再改文件层级再次验证若单元方法失败后,静态资源放行还能否执行?
我们将WEB-INF/page下的index.html移到了page下,并且去掉自定义视图解析器的后缀名添加,因为html可以被过静态资源放行和单元方法两者匹配到。此时请求page/html,单元方法匹配肯定失效,若是静态资源放行仍能执行则应该正确访问,若是单元方法失败后静态资源放行不再执行则报404
显然,单元方法和静态资源放行不能的url设置不应该冲突,若发生冲突的话静态资源放行则不再执行。