在做项目的时候,我希望静态资源由WEB服务器默认的Servlet来处理,所以我在配置文件中添加了如下的语句:
<mvc:default-servlet-handler/>
但是我再次运行项目,并访问资源的时候,发现访问@RequestMapping("/path1/path2")都不能访问了,之前没有添加的时候是能够访问的。
解决方案是,在配置文件中再添加一句代码:
<mvc:annotation-driven/>
这样做的原因是:
另解:
要说明这个问题,首先要知道一个请求是如何处理的。
1.所有的请求一定都是被Servlet处理的,springmvc也是DispatcherServlet处理的,至于Servlet怎么处理则是它自己内部的事情;
2.一个请求最多只会被一个Servlet处理,至于由哪个Servlet处理,完全由Servlet配置的url-pattern决定,匹配程度最高的Servlet将处理,其他Servlet不再有机会。匹配程度从高到低依次为:
<1> 精准匹配,优先级最高;
<2> “/∗"匹配,所有不是精准匹配的请求,都会被该Servlet处理。所以应用的web.xml中如果配置了这种类型的Servlet,tomcat是没有机会处理请求的;(如果访问a.jsp、a.action都会被这个Servlet处理而不是下面模糊匹配的Servlet处理)
<3> 模糊匹配,如∗.do、∗.jsp、∗.action等,如果没有上述两种Servlet,请求将会被这个Servlet处理;
<4>”/"匹配,优先级最低,如果没有<1>、<2>类型的Servlet,并且3类型的Servlet没有匹配到,所有的请求都会由这个Servlet处理;
能够处理请求的Servlet有哪些?
- 应用中web.xml中注册的Servlet;
- tomcat配置目录下web.xml中的两个Servlet:DefaultServlet、JspServlet
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
请求处理的过程
1. 从应用的web.xml、tomcat的web.xml中找出所有能够处理该请求的Servlet;
2. 用请求名和这些Servlet的url-pattern逐个匹配,匹配程度最高的Servlet处理该请求;
3. Servlet处理完返回结果。
有了以上的理论基础,就可以分析请求在springmvc中是如何处理请求的了。
DispatcherServlet的url-pattern为什么是"/“而不是”/*"?
如果配置为"/*",应用中能够处理请求的Servlet排序如下:
/*-----------------------DispatcherServlet
*.jsp--------------------org.apache.jasper.servlet.JspServlet
/------------------------org.apache.catalina.servlets.DefaultServlet
所有请求都会被DispatcherServlet处理,包括静态的xx.html、xx.js和xx.jsp。
而我们是不会配置@RequestMapping("/xx.jsp")、 @RequestMapping("/xxhtml")这种映射的,
除了@RequestMapping映射的请求,其他如静态请求xx.html、xx.js、xx.jsp请求就不能成功响应。
如果配置为"/",应用中能够处理请求的Servlet排序如下:
*.jsp--------------------org.apache.jasper.servlet.JspServlet(如果是jsp优先处理)
/------------------------DispatcherServlet(处理剩余所有请求,包括@RequestMapping映射的请求、静态资源请求)
/------------------------org.apache.catalina.servlets.DefaultServlet
按照上述Servlet能够处理的请求类型,可以把springmvc的请求分类:JSP请求、@RequestMapping映射的请求、其他请求(html、js、png等静态请求);
1. 如果是JSP请求,由于JspServlet的匹配程度最高,这种请求由tomcat处理;
2. 如果是@RequestMapping映射的请求,由DispatcherServlet处理;
3. 如果是其他请求,由DispatcherServlet处理,由于没有配置请求映射,所以无法处理
(@RequestMapping对应的处理函数内部跳转到静态资源不算,这属于Servlet的内部逻辑);
也就是说,如果DispatcherServlet的url-pattern配置成"/",默认情况下springmvc是没有处理静态资源请求能力的。
这时就需要用到<mvc:default-servlet-handler/>, 也就引出了<mvc:default-servlet-handler/>、<mvc:annotation-driven />两个配置。
无论有没有这两个配置,JSP请求都是由tomcat处理的,没有问题。
其他请求都是由DispatcherServlet处理的,问题点在于有没有组件可以处理@RequestMapping映射的请求和静态资源请求。
1 两个都没配置的时候,DispatcherServlet中的组件情况如下:
HandlerMapping:BeanNameUrlHandlerMapping、RequestMappingHandlerMapping;
HandlerAdapter:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter;
@RequestMapping映射的请求可以由RequestMappingHandlerMapping、RequestMappingHandlerAdapter两个组件处理;
静态资源请求没有组件可以处理,所以无法处理;
2 只配置<mvc:annotation-driven />,DispatcherServlet中的组件情况如下;
BeanNameUrlHandlerMapping、RequestMappingHandlerMapping;
RequestMappingHandlerAdapter、HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter;
和没有配置的时候一致,@RequestMapping映射的请求可以处理,静态资源请求无法处理;
3 只配置<mvc:default-servlet-handler/>,DispatcherServlet中的组件情况如下;
BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping;
HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter;
SimpleUrlHandlerMapping、SimpleControllerHandlerAdapter配合使用的效果就是调用tomcat的DefaultServlet处理请求,
相当于DispatcherServlet把请求转给了tomcat的DefaultServlet处理,DefaultServlet能够处理静态资源请求,当然它肯定不知道
DispatcherServlet中映射的请求,所以:
静态资源请求可以处理;
@RequestMapping映射的请求无法处理;
4 两个配置都引入,DispatcherServlet中的组件情况如下;
BeanNameUrlHandlerMapping、RequestMappingHandlerMapping、SimpleUrlHandlerMapping
RequestMappingHandlerAdapter、HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter
这就不用多说了,两对CP都在,分工明确,静态资源请求、@RequestMapping映射的请求都能处理。