Spring MVC

  对于很多Java开发人员来说,基于Web的应用程序是主要的关注点。如果你有这方面经验的话,你会意识到这种系统所面临的挑战。具体来说,状态管理、工作流以及验证都是需要解决的重要特性。HTTP协议的无状态性决定了这些问题都不容易解决。

  Spring的Web框架就是为了解决这些问题而设计的。Spring MVC基于模型-视图-控制器(Model-view-Controller,MVC)模式实现,它能够帮你构建像Spring框架那样灵活和松耦合的Web应用程序。

  Spring将请求在调度Servlet、处理器映射(handler mapping)、控制器以及视图解析器(view resouver)之间移动。请求从离开浏览器开始到获取响应返回,它经历好多站,在每站都会留下一些信息同时也会带上其他信息。如图:

  请求会由DispatcherServlet分配给控制器(根据处理器映射来决定)。在控制器完成处理后,接着请求会被发送给一个视图(根据视图解析器来确定)来呈现输出结果。

  请求旅程的第一站市Spring的DispatcherServlet。与大多数基于Java的Web框架一样,Spring MVC所有的请求都会通过一个前端控制器Servlet。前端控制器是常用的Web应用程序模式,在这里一个单实例的Servlet将请求委托给应用程序的其他组件来执行实际的处理。在Spring MVC中,DispatcherServlet就是前端控制器。

  DispatcherServlet的任务是将请求发送给Spring MVC控制器。控制器是一个用于处理请求的spring组件。在典型的应用程序中可能会有多个控制器,DispatcherServlet需要知道应该将请求发送给哪个控制器。所以DispatcherServlet会查询一个或多个处理器映射来确定请求的下一站在哪里。处理器映射会根据请求所携带的URL信息来进行决策。

  一旦选择了合适的控制器,DispatcherServlet会将请求发送给选中的控制器。到达了控制器,请求会卸下器负载(用户提交的信息)并耐心等待控制器处理这些信息。

  控制器在完成逻辑处理后,通常会产生一些信息,这些信息需要返回给用户并在浏览器上显示。这些信息被称为模型(model)。不过仅仅给客户返回原始的信息市不够的——这些信息需要以用户友好的方式进行格式化,一般市HTML。所以,信息需要发送给一个视图(view),通常会是JSP。

  控制器所做的最后一件事是将模型数据打包,并且标示出用于渲染输出的视图名称。它接下来会将请求连同模型和视图名称发送回DispatcherServlet。

  这样,控制器就不会与特定的视图相耦合,传递给DispatcherServlet的视图名称并不直接表示某个特定的JSP。实际上,它甚至并不能确定视图是JSP。相反,它仅仅传递了一个逻辑名,这个名字将会用来查找用来产生结果的真正视图。DispatcherServlet将会使用视图解析器来将逻辑视图名匹配为一个特定的视图实现,它不一定是JSP。

  既然DispatcherServlet已经知道由哪个视图渲染结果,那么请求的任务基本上也就完成了。它的最后一个站是视图的实现(可能是JSP),在这里它交付模型数据。请求的任务九完成了。视图将使用模型数据渲染输出,并通过这个输出将响应对象传递给客户端。

  Spring MVC的核心是DispatcherServlet。与其他Servlet一样,DispatcherServlet必须在Web应用程序的web.xml文件中进行配置。所以在应用程序中使用Spring MVC的第一件事就是将DispatcherServlet声明放入web.xml中:

<servlet>

  <servlet-name>spitter</servlet-name>

  <servlet-class>

    org.springframework.web.servlet.DispatcherServlet

  </servlet-class>

  <load-on-startup>1</load-on-startup>

</servlet>

  为这个Servlet所设置的<servlet-name>是很重要的。默认情况下,DispatcherServlet在加载时会从一个基于这个Servlet名字的XML文件中加载Spring应用上下文。在这个示例中,因为servlet的名字为spitter,DispatcherServlet将尝试从一个名为spitter-servlet.xml的文件(位于应用程序的WEB-INF目录下)来加载应用上下文。

  接下来我们必须声明DispatcherServlet处理哪些URL。如下:

<servlet-mapping>

  <servlet-name>spitter</servlet-name>

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

</servlet-mapping>

  通过将DispatcherServlet映射到/,声明了它会作为默认的servlet并且会处理所有的请求,包括对静态资源的请求。为使DispatcherServlet不用处理静态资源的请求,Spring提供了一个很方便的配置,使得我们不必过于担心细节。Spring的mvc命名空间包含了一个新的<mvc:resources>元素,它会处理静态资源的请求。我们所要做的就是在Spring配置文件中对其进行配置。如下:<mvc:resources mapping="/resources/**" location="/resources/*">

  <mvc:resources>建立了一个服务于静态资源的处理器。属性mapping被设置为/resources/**,它包含了Ant风格的通配符以表明路径必须以/resources开始,而且也包括它的任意子路径。属性location表明了要提供服务的文件位置。以上配置表明,所有以/resources路径开头得到请求都会自动由应用程序根目录下的/resources目录提供服务。因此,我们的所有图片、样式表、JavaScript以及其他的静态资源都必须放在应用程序的/resources目录下。

  正如前面所述,DispatcherServlet需要咨询一个或多个处理器映射(handle mapping)来明确地将请求分发给哪个控制器。Spring自带了多个处理器映射实现供我们选择,具体如下:

  BeanNameUrlHandlerMapping:根据控制器Bean的名字将控制器映射到URL。

  ControllerBeanNameHandlerMapping:与BeanNameUrlHandlerMapping类似,根据控制器Bean的名字将控制器映射到URL。使用该处理器映射实现,Bean的名字不需要遵循URL的约定。

  ConctrollerClassNameHandlerMapping:通过使用控制器的类名作为URL基础将控制器映射到URL。

  DefaultAnnotationHandlerMapping:将请求映射给使用@RequestMapping注解的控制器和控制器方法。

  SimpleUrlHandlerMapping:使用定义在Spring应用上下文的属性集合将控制器映射到URL。

  使用如上这些处理器映射通常只需在Spring中配置一个Bean。如果没有找到处理映射Bean,DispatcherServlet将创建并使用BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping。配置如下:

<bean class="org.springframework.web.servlet.mvc.annotation.DeaultAnnotationHandlerMapping"/>

  DefaultAnnotationHandlerMapping将请求映射到使用@RequestMapping注解的方法。但是,实现注解驱动的Spring MVC并不仅仅是将请求映射到方法上。在构建控制器的时候,我们还需要使用注解将请求参数绑定到控制器的方法参数上进行校验以及信息转换。所以,只是用defaultAnnotationHandlerMapping还不行。需要在配置文件中添加Spring MVC所提供的注解驱动特性:<mvc:annotation-driven/>

  为了使用@Component注解,我们需要在上下文中配置一个<context:component-scan>,配置如下:

<context:component-scan base-package="com.zhyypt.mvc"/>

  处理请求的最后一件必须要做的事情就是为用户渲染输出。为了确定指定的请求需要使用哪个视图,DispatcherServlet会查找一个视图解析器来将控制器返回的逻辑视图名称转换成渲染结果的实际视图。

  实际上,视图解析器的工作是将逻辑视图的名字与org.springframework.web.servlet.View的实现相匹配。Spring自带了多个视图解析器实现供选择,如图:

  在Spring MVC中,大量使用了约定优于配置的开发模式。InternalResourceViewResolver就是一个面向约定地点元素。它将逻辑视图名称解析为View对象,而该对象将渲染的任务委托给Web应用程序上下文中的一个模板(通常是JSP)。如图:

  它通过逻辑视图名称添加前缀和后缀来确定Web应用程序中模板的路径。配置如下:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

  <property name="prefix" value="/jsp/"/>

  <property name="suffix" value=".jsp"/>

</bean>

  默认情况下,InternalResourceViewResolver创建的View对象是InternalResourceView的实例,它只会简单的将请求传递给渲染的JSP。但JSP会使用一些JSTL标签,因此需要通过设置viewClass属性来将InternalResourceView替换为JstlView,如下所示:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>

  <property name="prefix" value="/jsp/"/>

  <property name="suffix" value=".jsp"/>

</bean>

  正如前面所提到的,DispatcherServlet会根据一个XML文件来加载其Spring应用上下文,而这个文件的名字基于它的<servlet-name>属性来确定。但我们可以将Spring配置分成多个XML文件:一个用于服务层、一个用于持久层还有一个用于数据源配置。尽管不是严格要求,但是将Spring配置文件组织到多个文件中是很好的主意。基于这样的理念,将Web层的配置都放在spitter-servlet.xml文件中是在情理之中的,这个文件会被DispatcherServlet加载。但是我们还需要一种方式来加载其他的配置文件。

  这就是ContextLoaderListener能够发挥作用的地方了。ContextLoaderListener是一个Servlet监听器,除了DispatcherServlet创建的应用上下文以外,它能够加载其他的配置文件到一个Spring应用上下文中。为了使用ContextLoaderListener,需要在web.xml文件中添加如下的<listener>声明:

<listener>

  <listener-class>

    org.springframework.web.context.ContextLoaderListener

  </listener-class>

</listener>

  我们必须告诉ContextLoaderListener需要加载哪些配置文件。如果没有指定,上下文加载器会查找/WEB-INF/applicationContext.xml这个Spring配置文件。但是这个文件本身并没有做到将应用上下文分为多个片段。所以,我们需要重写默认实现。

  为了给ContextLoaderListener指定一个或多个Spring配置文件,需要在servlet上下文中配置contextConfigLocation参数:

<context-param>

  <param-name>contextConfigLocation</param-name>

  <param-value>

    /WEB-INF/spitter-security.xml

    classpath:service-context.xml

    classpath:persistence-context.xml

    classpath:dataSource-context.xml

  </param-value>

</context-param>

  contextConfigLocation参数指定了一个路径的列表。除非特别声明,路径是相对于应用程序根目录的。但我们的Spring配置分成了多个XML文件,并分散在Web应用程序的多个JAR文件中,所以对其中的一些我们添加了classpath:前缀,使得它们能够以资源的方式在应用程序中的类路径中加载,而其他的文件则添加了Web应用程序的本地路径。

原文地址:https://www.cnblogs.com/jizhuan/p/6608001.html