今天我们开始新的课程,看一下spring对于MVC模式是如何使用的。我先简单介绍一下MVC模式吧,MVC三层分别是Model、View、Controller三个层次,代表数据层、视图层、控制层。视图层先获取用户的输入,通过Controller层修改了Model层次的数据,Model层数据的改变,通过Controller层触发了View层的视图。

1、如何实现springmvc的hello world?

  如果使用springmvc框架,要导入相关的jar包,看一下我们pom.xml的依赖:
pom.xml

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.12.RELEASE</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>4.3.12.RELEASE</version>
		</dependency>

  访问springmvc的过程其实就是访问DispatcherServlet这个Servlet,这个Servlet我们后面会单独讲到。我们在web.xml中配置这个servlet如下:
web.xml

<?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_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>Test</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
  	<servlet-name>springmvc</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

  我们写出一个控制器,也就是访问的页面,但是这个控制器不再是Servlet,而是一个普通的类,实现了Controller接口,并重写他的handleRequest方法,代码如下:
SpringTest.java

package com.springmvc.test;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class SpringTest implements Controller{

	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("访问本网站成功。");
		return null;
	}

}

  springmvc会默认加载WEB-INF下的springmvc-servlet.xml(“-”前的名字和web.xml的servlet-name一致),我们在这个目录下创建xml文件如下:
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:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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/context 
        http://www.springframework.org/schema/context/spring-context-4.3.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-4.3.xsd">
	
	<!-- 配置处理映射器 -->
	<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
	<!-- 处理适配器 -->
	<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
	<!-- 视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"></bean>
	<bean id="test" name="/test" class="com.springmvc.test.SpringTest"></bean>
</beans>

  然后在tomcat上运行控制器,发现可以访问到一个空白网页,控制台上打印如下:

访问本网站成功。

  这样一个简单springmvc的helloworld就完成了,接下来我们仔细的分析这个demo,来对springmvc有个更深的了解。

2、怎么指定某个xml作为springmvc的配置文件?

  如果不想让spring加载默认的springmvc配置文件,也可以手动加载某文件,在web.xml的<servlet>中写上如下代码:

<init-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>/WEB-INF/springmvc-config.xml</param-value>
  	</init-param>

   这样,我们就可以将/WEB-INF/springmvc-config.xml当做springmvc的配置文件了。

3、springmvc的流程是什么样的?

  从接受到请求开始,springmvc各组件之间开始通力合作、各司其职,他们有条不紊的做着自己的工作,现在我们从上帝角度来看一下springmvc的各个组件是如何工作的吧!
  整个过程开始于用户发出的一个HTTP请求,web服务器接收到这个请求之后如果符合DispatcherServlet中央处理器的映射路径,那么web容器会将这个请求交给DispatcherServlet进行处理。
  中央处理器接收到这个信息,会根据HandlerMapping处理映射器进行匹配,找到处理请求的处理器,我们称之为handler,也就是我们上面demo的controller接口实现类,这个类是我们自己写的。
  HandlerMapping通过请求来找到对应的handler标识符,接下来就由HandlerAdapter处理适配器使用统一的接口来调用相应的handler。
  调用相应的handler后,接下来就是这个处理器对于业务逻辑的处理,然后这个处理器会再返回一个ModelAndView给DispatcherServlet,ModelAndView包含了视图逻辑名称也就是页面的路径,还包括模型数据信息也就是需要转发的参数。
  处理器的ModelAndView返回的视图逻辑名称并不是真正的视图对象,DispatcherServlet借助ViewResolver视图解析器完成逻辑视图名到真实视图对象的操作。
  视图解析器解析出来的真实对象再对ModelAndView中的模型数据信息进行渲染,然后客户端就可以得到这个响应了。
  我们上面几个步骤说的是一个请求的处理和响应,也可以说是View到Controller层再反馈给View的过程,为了举例简单,我们没有说数据的持久层也就是Model层。

3、处理映射器的作用是什么?

  我们先来看一下HandlerMapping的结构图:

spring mvc 怎么打成jar包 spring mvc实现_xml


  我们看到上面有五个类都实现了同一个接口HandlerMapping,但无论是哪个实现类,他们都是将请求以不同的形式找到对应的处理器,还是以第一问的demo为例子,我们分别来看一下这些实现类有什么区别?

BeanNameURLHandlerMapping实现类配置处理器

<!-- 配置处理映射器 -->
	<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
	<!-- 给SpringTest处理器类添加映射注解“/test.action” -->
	<bean id="test.action" name="/test" class="com.springmvc.test.SpringTest"></bean>

  这种处理映射器使用bean的name属性,给处理器添加映射路径。

SimpleUrlHandlerMapping处理映射器

<!-- 配置处理映射器 -->
	<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<!-- 给SpringTest处理器类添加映射注解“/test.action” -->
		<property name="mappings">
			<props>
				<prop key="/test.action">test</prop>
				<prop key="/test.do">test</prop>
			</props>
		</property>
	</bean>
	<bean id="test" class="com.springmvc.test.SpringTest"></bean>

  这种处理映射器不再使用bean的name,而是在处理映射器的bean里面的属性给某个bean添加映射路径。这样做的好处是可以给一个bean赋予多个映射路径,也可以给多个bean赋予映射路径。

ControllerClassNameHandlerMapping处理映射器

<!-- 配置处理映射器 -->
	<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"></bean>
	<!-- 处理器的bean必须配置 -->
	<bean class="com.springmvc.test.SpringTest"></bean>

  这种处理映射器会自动将[处理映射器小写类名.do]映射成处理器的路径,类名必须全部小写。例如上面的处理器链接,可以访问如下url:

http://localhost:8080/Test/springtest.do

  剩下的两个处理映射器RequestMappingHandlerMapping和DefaultAnnotationHandlerMapping都是处理注解的处理映射器,前者在3.1版本开始提供,后者在2.5版本开始提供,前者比后者提供更多的扩展。

4、处理适配器的作用是什么?

  我们先来看一下HandlerAdapter的结构图:

spring mvc 怎么打成jar包 spring mvc实现_xml_02

  我们看到SimpleServletHandlerAdapter、HttpRequestHandlerAdapter、AnnotationMethodHandlerAdapter、SimpleControllerHandlerAdapter四个类共同实现了HandlerAdapter接口,那这四个处理适配器有什么区别呢?我们分别来看一下不同的处理适配器都是使用什么样的处理器:

SimpleControllerHandlerAdapter的配置

<!-- 处理适配器 -->
	<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

SimpleControllerHandlerAdapter的处理类

package com.springmvc.test;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class SpringTest implements Controller{

	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		System.out.println("访问本网站成功。");
		return null;
	}

}

  SimpleControllerHandlerAdapter的处理适配器会调用Controller接口的handleRequest方法。
SimpleServletHandlerAdapter处理适配器的配置

<!-- 处理适配器 -->
	<bean class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"></bean>

SimpleServletHandlerAdapter处理适配器的处理类

package com.springmvc.test;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class SpringTest extends HttpServlet{
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("访问网站成功。");
	}
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}

}

  SimpleServletHandlerAdapter处理适配器会调用Servlet的service方法,这个servlet不需要在xml中配置映射路径,也不需要注解配置,而是通过处理映射器进行配置映射路径。
HttpRequestHandlerAdapter处理适配器的配置

<!-- 处理适配器 -->
	<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>

HttpRequestHandlerAdapter处理适配器的处理类

package com.springmvc.test;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.HttpRequestHandler;

public class SpringTest implements HttpRequestHandler{

	public void handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		System.out.println("访问网站成功。");
	}

}

  HttpRequestHandlerAdapter处理适配器会调用HttpRequestHandler实现类的handleRequest方法。

  AnnotationMethodHandlerAdapter和RequestMappingHandlerAdapter处理适配器是注解的适配器,我们在这先不花费时间去研究,后面会专门讲到注解形式的springmvc。
  有人又问了,上面讲了四种适配器,那我应该选择哪个适配器呢?条条大路通罗马,只要是能达到你的目的的就是好适配器。

5、视图解析器的作用是什么?

  在控制器中,会返回String、View、ModelAndView或者ModelMap其中的一个,无论是什么对象,都会被springmvc封装成一个ModelAndView对象返回,最终 借助视图解析器得到最终的视图对象View,可以是jsp,可以使html等各种视图对象,最后调用View的render()方法进行视图渲染,得到相应结果。
  视图解析器就是讲逻辑视图转变成物理视图的过程。我们来看一下视图解析器的结构图:

spring mvc 怎么打成jar包 spring mvc实现_spring_03

  我们主要来了解一下常见的视图解析器InternalResourceViewResolver,他将视图名解析成一个url文件,一般使用该解析器将视图名映射为一个保存在WEB-INF下的视图文件。配置代码如下:

<!-- 视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- 设置视图的前缀 -->
		<property name="prefix" value="/WEB-INF/views/"></property>
		<!-- 设置视图的后缀 -->
        <property name="suffix" value=".jsp"></property>
	</bean>