(一)SpringMVC之配置DispatcherServlet的一些坑

匿名 (未验证) 提交于 2019-12-03 00:22:01

DispatcherServlet是SpringMVC的核心控制器,就像是SpringMVC的心脏,几乎所有的请求都会经过这个控制器,通过它,大大的降低了模块之间的耦合度。所有学SpringMVC的同学们第一步肯定都是先配置这个Servlet,不然还写啥SpringMVC啊。

那其实我第一次写SpringMVC的时候就遇到了好多坑,这里记录一下,只是冰山一角,但希望能帮助一些人。

为了更好的说明情况,我先写一些代码

首先新建一个MyController继承自Controller

public class MyController implements Controller {      @Override     public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {         ModelAndView mav = new ModelAndView();         // 增加一个属性到model中,底层是调用了request.setAttribute()方法         mav.addObject("hello", "hello springmvc");         // 为这个模型视图起一个逻辑视图名         mav.setViewName("hello");         return mav;     } }

在WEB-INF目录下建一个springmvc-servlet.xml

<?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:aop="http://www.springframework.org/schema/aop"         xmlns:tx="http://www.springframework.org/schema/tx"          xmlns:jdbc="http://www.springframework.org/schema/jdbc"         xmlns:context="http://www.springframework.org/schema/context"         xsi:schemaLocation="http://www.springframework.org/schema/beans          http://www.springframework.org/schema/beans/spring-beans.xsd         http://www.springframework.org/schema/tx          http://www.springframework.org/schema/tx/spring-tx.xsd         http://www.springframework.org/schema/aop          http://www.springframework.org/schema/aop/spring-aop.xsd         http://www.springframework.org/schema/jdbc          http://www.springframework.org/schema/jdbc/spring-jdbc.xsd         http://www.springframework.org/schema/context          http://www.springframework.org/schema/context/spring-context.xsd">       <!-- 这个文件默认放在WEB-INF文件夹下 ,如果不是,则需要在web.xml中进行指定-->     <!-- 注册处理器 ,id的属性值为请求的url-->     <bean id="/my.do" class="com.codeliu.controller.MyController"></bean>      <!-- 注册视图解析器 -->     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">         <!-- 视图资源url的前缀 -->         <property name="prefix" value="/WEB-INF/jsp/"></property>         <!-- 视图资源url的后缀 -->         <property name="suffix" value=".jsp"></property>     </bean> </beans>

配置完这些,就应该去web.xml中配置DispatcherServlet了。

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">   <display-name>SpringMVC_01</display-name>   <!-- 注册中央调度器 -->   <servlet>     <servlet-name>springmvc</servlet-name>     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>     <!-- tomcat启动时自动创建servlet,数字越小优先级越高(>0) -->     <load-on-startup>1</load-on-startup>   </servlet>    <servlet-mapping>     <servlet-name>springmvc</servlet-name>     <url-pattern>*.do</url-pattern>   </servlet-mapping> </web-app>

之后我们在WEB-INF目录下新建一个jsp文件夹,在jsp文件夹里新建一个hello.jsp

<body>     <!-- 等价于${requestScope.hello} -->     ${hello} </body>

到这里,基本就完成了,我们启动tomcat,输入localhost:8080/SpringMVC_01/my.do,能正常显示。

如果把上面配置文件的名字由springmvc-servlet.xml改为springmvc.xml,则启动tomcat时就会报错,提示在WEB-INF目录下找不到一个springmvc-servlet.xml的文件

我们从配置文档中可以找到答案

 * <p>Passes a "contextConfigLocation" servlet init-param to the context instance,  * parsing it into potentially multiple file paths which can be separated by any  * number of commas and spaces, like "test-servlet.xml, myServlet.xml".  * If not explicitly specified, the context implementation is supposed to build a  * default location from the namespace of the servlet.  * <p>The default namespace is "'servlet-name'-servlet", e.g. "test-servlet" for a  * servlet-name "test" (leading to a "/WEB-INF/test-servlet.xml" default location  * with XmlWebApplicationContext). The namespace can also be set explicitly via  * the "namespace" servlet init-param.

从这里可以知道两个信息,一个是SpringMVC配置文件的默认路径是WEB-INF下面,另一个是配置文件的name默认应该是你配置的DispatcherServlet的servlet-name+servlet.xml。

知道了这个,那么这个问题也就迎刃而解了。

  • 如果你配置文件放在WEB-INF目录下,但名字不想按照那个格式,可以通过namespace这个初始化参数进行指定。

比如我想把配置文件的名字改成springmvc.xml,但文件位置不移动,则在注册servlet时加上初始化参数如下

    <init-param>         <!-- 如果springmvc的配置文件放在WEB-INF目录下,但不想名字的形式为*-servlet.xml,         则可以通过namespace属性值进行指定 -->         <param-name>namespace</param-name>         <param-value>springmvc</param-value>     </init-param>
  • 如果你的配置文件不想放在WEB-INF目录下,则通过contextConfigLocation这个初始化参数进行指定

比如我把springmvc.xml移动到src目录下,就进行如下配置

    <init-param>         <!-- 默认Springmvc的配置文件是在WEB-INF目录下,如果要放在其他目录,则需要指定 -->         <param-name>contextConfigLocation</param-name>         <param-value>classpath:springmvc.xml</param-value>          <!-- 如果springmvc的配置文件放在WEB-INF目录下,但不想名字的形式为*-servlet.xml,         则可以通过namespace属性值进行指定 -->         <!-- <param-name>namespace</param-name>         <param-value>springmvc</param-value> -->     </init-param>

配置了这个参数则namespace这个参数就不用配置了,因为通过这个参数已经把路径和名字都指定了。

从上面的信息我们也可以看到,如果在默认情况下,你的servlet-name值必须和配置文件的前缀保持一致,但如果你通过上面的初始化参数进行了设置,那就无关紧要了。

这个也是大有文章啊。我们上面写的是*.do的形式。我们分析一下下面三种情况

  • /*.do的形式:我们把url-pattern值的值改成/*.do,这种情况你会发现连tomcat都无法启动,所以以后遇到这种情况得想想是不是自己的url-pattern值多写了一个/。

  • /*的形式:我们把url-pattern值改成/*,这时启动tomcat没有错误,当你输入

http://localhost:8080/SpringMVC_01

或者

http://localhost:8080/SpringMVC_01/my.do

的时候,发现都是404

这个404就有点怪,因为它完全不知道你访问的是哪个资源。原因如下

当你写成这个形式的时候,DispatcherServlet会讲将动态页面(注意是动态页面)的跳转请求也当做是一个controller请求,然后它就会调用处理器映射器为其查找相应的处理器,这种情况下,毫无疑问是找不到的,所以你访问所有的jsp页面都会404。

  • /的形式:我们把url-pattern值改成/*,这时启动tomcat没有错误,当你输入
http://localhost:8080/SpringMVC_01/

或者

http://localhost:8080/SpringMVC_01/my.do

诶发现都没错,那这种情况有什么问题呢?

我们修改默认的index.jsp如下

<body>     <img alt="picture" src="images/1.jpg"> </body>

在里面放一张图片

接着重新打开

http://localhost:8080/SpringMVC_01/

你会发现图片无法正常显示。原因就是写成这种形式,DispatcherServlet会将向静态资源的请求(注意是静态资源如css,png,jpg,js等),当前是一个controller请求,中央调度器会调用处理映射器为其查找相应的处理器,毫无疑问,这也是不可能找到的,所以这种情况下,静态资源的请求也全部是404。

(1)/*之类的肯定不能写,因为访问啥都出错

(2)/的形式访问静态资源会出错

如果我们url-pattern的值还就成/咋的啦,也不是不行,不过就得进行另外的一些配置了。

  • 使用tomcat默认的servlet
    <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的介绍如下,是专门用于处理静态资源的。

<!-- The default servlet for all web applications, that serves static     -->   <!-- resources.  It processes all requests that are not mapped to other   -->   <!-- servlets with servlet mappings (defined either here or in your own   -->   <!-- web.xml file).   -->

这样我们可以直接在web.xml中进行这个servlet的映射,而不用注册了。

<servlet-mapping>     <servlet-name>default</servlet-name>     <url-pattern>*.jpg</url-pattern>   </servlet-mapping>    <servlet-mapping>     <servlet-name>default</servlet-name>     <url-pattern>*.png</url-pattern>   </servlet-mapping>   <servlet-mapping>     <servlet-name>default</servlet-name>     <url-pattern>*.js</url-pattern>   </servlet-mapping>   <servlet-mapping>     <servlet-name>default</servlet-name>     <url-pattern>*.css</url-pattern>   </servlet-mapping>

这样可以把静态资源的请求转向默认的servlet进行处理,就不会出现找不到静态资源的情况了。

  • 使用mvc:default-servlet-handler解决

我们得先在springmvc.xml中引入mvc的约束

xmlns:mvc="http://www.springframework.org/schema/mvc" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd

只需在springmvc.xml中添加一条语句即可

<mvc:default-servlet-handler/>

通过它,静态资源也能正常访问。原理如下:该标签会将对静态资源的请求添加到SimpleUrlHandlerMapping的urlMap中,key就是请求的url,而value则是默认servlet请求处理器DefaultServletHttpRequestHandler对象,而该处理器调用了tomcat的默认servlet来处理静态资源。

所以归根到底,还是使用了tomcat的默认servlet。

  • 使用mvc:resources解决

在spring3.0.4版本之后,spring中有了专门处理静态资源访问请求的处理器ResourceHttpRequestHandler。并且添加了mvc:resources标签,专业用于处理静态资源无法访问的问题。所有我们只需要springmvc.xml中加入下面的语句

<mvc:resources location="/images/" mapping="/images/**"></mvc:resources>

location表示静态资源所在的目录,包含WEB-INF目录及其子目录。

mapping表示对该资源的请求。后面是两个星号*

该标签会把对静态资源的请求添加到SimpleUrlHandlerMapping的urlMap中,key就是与mapping属性匹配的url,而value则是静态处理器对象ResourceHttpRequestHandler

相比于第二种方式,这种方式的缺点是如果有css资源、js资源那么你还得添加标签。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!