SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

以上一篇SpringMVC+Maven构建的项目为demo,看下在url-partten为/,/*情况下有什么不一样,为啥不一样。

 

准备了三种资源: jsp, html, restController返回的字符串。对应到web项目中是动态资源,静态资源,自定义映射器。

 

 

 SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

1: /

把 <url-pattern> 改成/ 。

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 1)访问restController:

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 2)访问jsp

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 3)访问html

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 我们看下控制台输出的信息:

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 

2:/* 

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

  1)访问restController:

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 

 2)访问jsp

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 

 3)访问html

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 3: *do

1)访问restcontroller

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

2)访问jsp

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 

 

3)访问html

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 


 

我们看到三种资源只有在配置路径为*.do的时候才能全部正常访问。这和tomcat中的DefaultServlet,JspServlet有关系。

我们的Servlet是tomcat初始化的,在tomcat的conf下面也有一个web.xml,所有我们自己的项目都会继承这个web.xml,就和Java中类继承一样,也会初始化这个web.xml。这个Web.xml里有:

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 DefaultServlet:我们看上面对它的注释:

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 这个默认的Servlet是为了所有部署的web应用提供静态资源服务的。它作为兜底的servelet,在其他地方定义的(包括自己定义的)servlet都没办法映射到的时候执行。它的拦截路径为/。

JspServlet:

SpringMVC(二)/ ,/*拦截路径引起的静态资源无法访问的问题

 

 它是tomcat支持jsp 页面用来Jsp页面编译和执行的servlet。 一般这个servlet拦截*.jsp。

好了,我们来分析下上面DispatcherServlet三种拦截路径。

/:代表拦截除后缀名以外的路径,即它只拦截路径,不拦截带后缀的url,若请求为/user/login.jsp,jsp不会进入DispatcherServlet类,即不会被过滤。
/*:代表拦截所有路径和后缀,会匹配所有的url,若请求为/user/login.jsp,会出现jsp进入DispatcherServlet类,导致找不到对应的controller,所以报404错误。
所以我们使用 /的时候,jsp可以访问,/*的时候访问jsp也报错。

静态页面只有在匹配到DefaultServlet的时候才能访问,但是上面两种路径方式都会被DispatcherServlet拦截到,所以都会报404,最好的方法是自定义的Servlet拦截指定后缀名。像上面的*.do,这样三个Servelet都有自己的拦截路径,DefaultSevlet可以兜底。三种资源都可以正常访问。

 

如果配置/的拦截路径,还可以在application.xml中增加:

  <mvc:annotation-driven />
   <mvc:default-servlet-handler />

 

这样三种资源也可以正常访问。

default-servlet-handler将在SpringMVC上下文中定义一个DefaultServletHttpRequestHandler

DefaultServletHttpRequestHandler的javadoc如下:

/**
 * An {@link HttpRequestHandler} for serving static files using the Servlet container's "default" Servlet.
 *
 * <p>This handler is intended to be used with a "/*" mapping when the
 * {@link org.springframework.web.servlet.DispatcherServlet DispatcherServlet}
 * is mapped to "/", thus  overriding the Servlet container's default handling of static resources.
 * The mapping to this handler should generally be ordered as the last in the chain so that it will
 * only execute when no other more specific mappings (i.e., to controllers) can be matched.
 *
 * <p>Requests are handled by forwarding through the {@link RequestDispatcher} obtained via the
 * name specified through the {@link #setDefaultServletName "defaultServletName" property}.
 * In most cases, the {@code defaultServletName} does not need to be set explicitly, as the
 * handler checks at initialization time for the presence of the default Servlet of well-known
 * containers such as Tomcat, Jetty, Resin, WebLogic and WebSphere. However, when running in a
 * container where the default Servlet's name is not known, or where it has been customized
 * via server configuration, the  {@code defaultServletName} will need to be set explicitly.
 *
 * @author Jeremy Grelle
 * @author Juergen Hoeller
 * @since 3.0.4
 */
/*使用servlet容器的默认servlet处理静态资源*/
An {@link HttpRequestHandler} for serving static files using the Servlet container's "default" Servlet.

/*当DispatcherServlet url-pattern为"/"时,该handler将会使用"/*"去匹配请求路径;因此,重置了servlet容器对静态资源的默认处理*/
This handler is intended to be used with a "/*" mapping 
when the {@link org.springframework.web.servlet.DispatcherServlet DispatcherServlet} is mapped to "/", 
thus overriding the Servlet container's default handling of static resources.

/*匹配该handler的mapping 应该是最后到达,当没有其他mapping可以处理请求时才会执行该handler匹配的mapping。*/
The mapping to this handler should generally be ordered as the last in the chain 
so that it will only execute when no other more specific mappings (i.e., to controllers) can be matched. 

annotation-driven 配置的作用如下:

主要是注册了 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter bean,存储了请求url到Controller方法的映射关系
注册了异常处理器

RequestMappingHandlerMapping:HandlerMapping的实现类,它处理的是@RequestMapping注解,并将其注册到映射表中,即url对应的Controller的方法
RequestMappingHandlerAdapter:HandlerAdapter的实现类,它是处理请求的适配器,就是确定调用哪个Controller的 哪个方法

 

Spring MVC 中如果配置了 <mvc:annotation-driven> ,则所有的 Controller 就会被解析,所以相应的请求就会被 Controller 处理,因此这个配置至关重要。当请求没有匹配到处理类(其中包括没有配置 <mvc:annotation-driven> 或者 访问的是静态资源文件)时,就会去找 <mvc:default-servlet-handler> (处理静态资源文件)配置的 DefaultServletHttpRequestHandler 默认处理器处理了

<mvc:annotation-driven />:使用默认的servlet来响应静态文件,建议放在开始;
<mvc:default-servlet-handler/>:放在注解处理映射器的后面,可以直接放在文件最后面

这样就不会出现<mvc:default-servlet-handler/>导致controller失效

 

上一篇:SpringMVC笔记(一)


下一篇:springmvc学习笔记