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

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

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

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

首先新建一个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,能正常显示。

##(1)SpringMVC配置文件的名字

如果把上面配置文件的名字由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这个参数就不用配置了,因为通过这个参数已经把路径和名字都指定了。

##(2)配置Servlet的servlet-name值

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

##(3)配置servlet-mapping时的url-pattern值

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

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

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

http://localhost:8080/SpringMVC_01

或者

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

的时候,发现都是404
3.png

这个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)/的形式访问静态资源会出错

##(4)/的救星

如果我们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资源那么你还得添加标签。

关注微信公众号:秃头哥编程(ID:xp_1311664842),领取编程大礼包。
在这里插入图片描述

  • 14
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值