使用 mvc:default-servlet-handler 中的一个bug

来源:互联网 发布:mac共享wifi 编辑:程序博客网 时间:2024/05/18 02:59

一个简单的SpringMVC Hello World程序如下:

package com.xiya.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;/** * Created by N3verL4nd on 2017/5/19. */@Controllerpublic class TestController {    @RequestMapping("/test1")    public String test1() {        return "/WEB-INF/views/hello.jsp";    }    @RequestMapping("/test2/test2")    public String test2() {        return "/WEB-INF/views/hello.jsp";    }}
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:context="http://www.springframework.org/schema/context"       xmlns:mvc="http://www.springframework.org/schema/mvc"       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">    <context:component-scan base-package="com.xiya.controller"/>    <!--<mvc:default-servlet-handler/>-->    <!--<mvc:annotation-driven/>--></beans>

项目结构如下:


当我们访问:curl http://localhost:8080/SpringMVC/test1,是可以正常访问的。

但是当我们访问根目录下的abc.html,是不能访问的,因为我们在web.xml的url-pattern设置的是:

<url-pattern>/</url-pattern>

即拦截所有请求,当然也包括静态资源。

如上配置,DispatcherServlet不会拦截*.jsp,*.html等文件。而交由默认的Servlet处理器来进行处理。

conf/web.xml

<servlet>        <servlet-name>default</servlet-name>        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>        <init-param>            <param-name>debug</param-name>            <param-value>0</param-value>        </init-param>        <init-param>            <param-name>listings</param-name>            <param-value>false</param-value>        </init-param>        <load-on-startup>1</load-on-startup></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>        <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>
我们在SpringMVC中的配置

<url-pattern>/</url-pattern>

覆盖掉了默认的DefaultServlet,所以导致静态文件无法被处理。而*.jsp文件则由JspServlet进行处理。



Spring MVC会将它们当成一个普通请求处理,因此找不到对应处理器将导致错误。

可以如下作验证:

@RequestMapping("/abc.html")public String test3() {    return "/WEB-INF/views/hello.jsp";}
为了解决以上问题,我们可以在SpringMVC配置文件中作如下配置:

<mvc:default-servlet-handler/>
但是问题又来了:原先可以访问的curl http://localhost:8080/SpringMVC/test1 现在不能访问了。

所以接着要配置:

<mvc:annotation-driven/>


我们通过debug来试着找找原因:

推荐IntelliJ IDEA的 IDEA Jetty Runner插件,比Tomcat在部署项目速度上快很多。 


IntelliJ IDEA是我用过和VS一样牛逼的IDE。

我们在DispatcherServlet的

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

处下断点,debug走起:

我们分三种情况来展示:

1、<mvc:default-servlet-handler/>与<!--<mvc:annotation-driven/>都不配置


2、只写<mvc:default-servlet-handler/>


3、两个都配置。


Spring3.2以前由org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter来处理@RequestMapping,

3.2以后由org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter处理。


在SpringMVC spring-webmvc 源码里也可看出点端倪:org\springframework\web\servlet\DispatcherServlet.properties

# Default implementation classes for DispatcherServlet's strategy interfaces.# Used as fallback when no matching beans are found in the DispatcherServlet context.# Not meant to be customized by application developers.org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
这些都是SpringMVC默认加载的。

所以我们可以不配置视图解析器。

@RequestMapping("/test1")public String test1() {    return "/WEB-INF/views/hello.jsp";}

参考:

http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.html

http://www.cnblogs.com/hujingwei/p/5349983.html

http://www.cnblogs.com/fangqi/archive/2012/10/28/2743108.html