出现这个问题真的是太菜了,在springmvc中的配置如下
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
十分常规配置,大多数应该都是这样配置的,至于/和/*的区别,不配置成/*主要是为了让tomcat内部对于jsp的处理生效。
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>fork</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>xpoweredBy</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
可以看到tomcat内部配置了针对于.jsp请求处理的servlet,由于.jsp是属于后缀匹配,/*是属于路径匹配,/是属于缺省匹配。
路径匹配的优先级高于后缀匹配,所以配置成/*时SpringMVC会连.jsp请求一起处理了,但是springMVC并没有处理jsp的能力,最终就导致出现了错误。
问题来了
因为/是缺省匹配,所以我们配置SpringMVC是使用的缺省匹配模式,我们知道tomcat中存在一个defalutServlet,其也是缺省匹配。
我曾经以为,两个servlet的url相同的时候,他们两个是共存的,但是事实证明,如果我们把SpringMVC的url-pattern配置为了缺省匹配,默认的servlet就不能处理请求了,这个看源码应该能看出来,有兴趣的可以去看看。
所以,这时候tomcat默认的servlet是不生效的,导致对于一些.html的请求不能被处理,首先SpringMVC我们不配置资源路径的情况下其是肯定不能处理这样的请求的,tomcat默认的servlet具有处理.html请求的能力。
而<mvc:default-servlet-handler/>这个注解其作用就是使默认的servlet生效,当springMVC有处理不了的请求的时候,就会交给默认的servlet去进行处理。
这个标签干了什么?为啥配置上他就行了
发现配置上了之后,我们的springMVC中的handlerMappings会有一个上面图示的SimpleUrlHandlerMapping,也就是多了一个根据简单的url映射的handler的简单映射,可以看出映射的url:/**,那就是所有的路径都能映射上了。那我们再来看看他映射的handler是个什么神秘人物,上面可以看到类名为DefaultServletHttpRequestHandler。
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Assert.state(this.servletContext != null, "No ServletContext set");
RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
if (rd == null) {
throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" + this.defaultServletName + "'");
} else {
rd.forward(request, response);
}
}
可以看出,直接就forward到了我们默认的servlet上了