您的位置:首页 > 编程语言 > Java开发

spring MVC详解(转)

2016-06-01 13:41 323 查看




 

如图 

请求首先通过DispatcherServlet。servlet根据HandlerMapping,来处理请求,并根据请求,来找到Controller,Controller执行完毕后,发送一个ModelAndView,并告诉需要展示哪个视图。根据这个视图,servlet找到这个视图的ViewResolver,并由这个ViewResolver生成对应的view,并输出。 

配置servlet 

springmvc是基于servlet的,因此需要在web.xml配置。 

<servlet> 

<servlet-name>roadrantz</servlet-name> 

<servlet-class>org.springframework.web.servlet.DispatcherServlet 

</servlet-class> 

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

</servlet> 

默认情况下,DispatcherServlet会加载这个servletname-servlet.xml文件,将这个文件作为spring的配置文件(淡然可以和全局的加载器,也就是全局的监听器和监听器加载的配置文件结合使用)。如上面我们定义的servlet-name的名字是roadrantz,因此它会加载roadrantz-servlet.xml。 

之后当然是要配置这个servlet对应的映射的了。 

<servlet-mapping> 

<servlet-name>roadrantz</servlet-name> 

<url-pattern>*.htm</url-pattern> 

</servlet-mapping> 

事实上,我们应该把配置分成多个文件。这样,基于springmvc的配置只在servletname-servlet.xml中,和其他部分的配置(如事务管理,数据源等配置则在另外一个地方,因为他们是通用的)是分开的。 

WebApplicationContext 

WebApplicationContext是ApplicationContext的子类它提供了为WEB应用服务的更多功能。 

我们可以通过RequestContextUtils来获取WebApplicationContext 

DispatcherServlet 

会配置如下的bean 

Bean type Explanation 

controllers mvc中的C 

handler mappings 处理器影射器,它会根据请求,查找到实际的请求处理者 

view resolvers 视图解析器 

locale resolver 本地化解析器,提供国际化的支持 

Theme resolver 主题解析器 

multipart file 文件上传解析器 

handler exception resolvers 异常处理器 

DispatcherServlet配置完成后,当相应的请求到达时,处理就开始了。 处理流程是 

1.找到WebApplicationContext并将其绑定到请求的一个属性上, 以便控制器和处理链上的其它处理器能使用WebApplicationContext。 默认的属性名为DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE。 

2.将本地化解析器(localResolver)绑定到请求上,这样使得处理链上的处理器在处理请求(准备数据、显示视图等等) 时能进行本地化处理。若不使用本地化解析器,也不会有任何副作用,因此如果不需要本地化解析,忽略它即可。 

3.将主题解析器绑定到请求上,这样视图可以决定使用哪个主题。如果你不需要主题,可以忽略它,不会有任何影响。 

4.如果上传文件解析器被指定,Spring会检查每个接收到的请求是否存在上传文件,如果存在, 这个请求将被封装成MultipartHttpServletRequest以便被处理链中的其它处理器使用 (关于文件上传的更多内容请参考Section 13.8.2, “使用MultipartResolver”)。 

5.找到合适的处理器,执行和这个处理器相关的执行链(预处理器,后置处理器,控制器),以便为视图准备模型数据(用于渲染)。 

6.如果模型数据被返回,就使用配置在WebApplicationContext中的视图解析器显示视图, 否则视图不会被显示。有多种原因可以导致返回的数据模型为空,比如预处理器或后处理器可能截取了请求,这可能是出于安全原因, 也可能是请求已经被处理,没有必要再处理一次。 

DispatcherServlet的初始化参数 

contextClass 实现了WebApplicationContext的类。默认是XmlWebApplicationContext。 

contextConfigLoSctraintgitohnat 与全局的contextConfigLoSctraintgitohnat参数可以共存 

namespace WebApplicationContext的命名空间。默认是[servlet-name]-servlet 

多个配置文件的方式 

1.基于监听器的方式: 

定义监听器 

<listener> 

<listener-class>org.springframework. 

web.context.ContextLoaderListener</listener-class> 

</listener> 

以及配置全局监听器的配置属性。 

注意 

有些比较老的容器,在初始化servlet之前,并不会初始化监听器,因此如果可能会被部署到这样的容器的话,需要将监听器,改成另外一个servlet 

ContextLoaderServlet 

将它置于DispatcherServlet之前。 

不管是监听器还是ContextLoaderServlet,这两个全局的装载器,在没有指定配置文件的情况下,会查找/WEB-INF/applicationContext.xml。 

但我们会有更多的配置文件,可以通过属性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> 

这个属性的值,和spring的资源Resource加载方式一样,可以带classpath:,file:,等前缀。 

这里先给出一个非注解方式的使用方式。 

主页 

主页是一个web应用必须有的(这里说的必须,你懂得)。 

当然先需要一个controller了。 

package com.roadrantz.mvc; 

import java.util.List; 

import javax.servlet.http.HttpServletRequest; 

import javax.servlet.http.HttpServletResponse; 

import org.springframework.web.servlet.ModelAndView; 

import org.springframework.web.servlet.mvc.AbstractController; 

import com.roadrantz.service.RantService; 

public class HomePageController extends AbstractController { 

public HomePageController() { 



protected ModelAndView handleRequestInternal( 

HttpServletRequest request, HttpServletResponse response) 

throws Exception { 

List recentRants = rantService.getRecentRants(); 

//定义modelandview,home表示会返回home.jsp(是不是jsp由视图解析器决定)。 

return new ModelAndView("home", 

"rants", recentRants); 



private RantService rantService; 

public void setRantService(RantService rantService) { 

this.rantService = rantService; 





ModelAndView对象 

ModelAndView封装了视图已经模型数据。 

注意,如果一个controller,return类型非null或者非viod,且没有写@ResponseBody注解的,最后都会被封装成ModelAndView,对与返回的一个普通的bean的时候,分装后的ModelAndView如下图 


  

new ModelAndView("home", "rants", recentRants); 

如上,第一个参数是视图名字。之后的参数是以模型对象将被传递给视图。 

下面是配置这个controller 

<bean
4000
name="/home.htm" 

class="com.roadrantz.mvc.HomePageController"> 

<property name="rantService" ref="rantService" /> 

</bean> 

这里首先没有使用id,而是使用name,这里的原因是因为有特殊字符/和.id不支持。而使用name。 

当一个请求home.htm(这个请求位于根目录下,如果非根目录是无法访问的,如127.0.0.1/daowole/home.htm是可以访问的,但是127.0.0.1/daowole/abc/home.htm是无法访问的。如果想要它不管通过哪个目录,只要是最后的资源是home.htm都可以访问,可以把bean的name改成name="home.htm",那么127.0.0.1/daowole/abc/home.htm还是127.0.0.1/daowole/home.htm都可以访问了。)的话,那么就会被访问到这里来。这里可以发现我们无需配置HandlerMapping,因为springmvc有一个默认的handlermapping,BeanNameUrlHandlerMapping。它是使用URL模式的基本名字。 

由于上面的的视图使用的是jsp视图,因此直接return一个jsp页面,自然没有问题了。 

而对应jsp视图,springmvc自然还提供了其他配置(相对普通jsp而言),这需要使用到一个jsp的解析器,org.springframework.web.servlet.view.InternalResourceViewResolver。 

<bean id="viewResolver" 

class="org.springframework.web. 

servlet.view.InternalResourceViewResolver"> 

<property name="prefix"> 

<value>/WEB-INF/jsp/</value> 

</property> 

<property name="suffix"> 

<value>.jsp</value> 

</property> 

</bean> 

这个会再controller返回的时候,会拼装前缀和后缀,再查找文件。如果找到,它来处理是自然的。 

home拼装前缀和后缀后就是/WEB-INF/jsp/home.jsp 

对于spring3.0版本的,如果使用了Spring 3.0.4或以上版本的话,可以使用 

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

在servletname-servlet.xml文件中。 

这种情况就解决了如果我们把url映射定义为/(这会由springmvc处理所有的请求),那么图片,js等静态资源会被由springmvc处理。它会把mapping指定的路径(ant风格)映射到location中。 

<mvc:resources mapping="/resources 

public class HelloController 

    extends AbstractCommandController { 

... 



<bean id="urlMapping" 

class="org.springframework.web.servlet.handler.metadata.CommonsPathMapHandlerMapping" /> 

SimpleUrlHandlerMapping 

<bean id="simpleUrlMapping" 

class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> 

<property name="mappings"> 

<props> 

<prop key="test.html">homeController</prop> 

</props> 

</property> 

</bean> 

如上,当任何一种方式访问到test.html,都由id=homeController的bean处理 

mappings是一个java.util.Properties类型的。 

ControllerClassNameHandlerMapping使用 

package com.cgodo.daowole.action; 

import javax.servlet.http.HttpServletRequest; 

import javax.servlet.http.HttpServletResponse; 

import org.springframework.web.servlet.ModelAndView; 

import org.springframework.web.servlet.mvc.AbstractController; 

public class SampleController extends AbstractController { 

protected ModelAndView handleRequestInternal(HttpServletRequest arg0, 

HttpServletResponse arg1) throws Exception { 

ModelAndView mav = new ModelAndView("index"); 

mav.addObject("message", "Hello World!"); 

return mav; 





<bean id="urlMapping" 

class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" /> 

如上,我们可以通过test.html(这里的后缀.html和你的web.xml配置有关)。就能访问。而不需要再增加其他的配置了。 

DefaultAnnotationHandlerMapping 根据@RequestMapping注解要查找action 

对于支持DefaultAnnotationHandlerMapping 版本的spring,如果没有对应 

handlermapping,那么DispatcherServlet会分别建立 

BeanNameUrlHandlerMapping 

和 

DefaultAnnotationHandlerMapping 

多个handlemapping同时处理,也是可以的。我们也可以通过order属性。来配置mapping的排序。 

如 

<bean id="beanNameUrlMapping" class="org.springframework.web. 

➥ servlet.handler.BeanNameUrlHandlerMapping"> 

<property name="order"><value>1</value></property> 

</bean> 

<bean id="simpleUrlMapping" class="org.springframework.web. 

➥ servlet.handler.SimpleUrlHandlerMapping"> 

<property name="order"><value>0</value></property> 

<property name="mappings"> 

… 

</property> 

</bean> 

这里的话,SimpleUrlHandlerMapping排序是0,因此它首先被servlet询问,如果这个SimpleUrlHandlerMapping有结果回来(标示它来处理),那么就进行处理,而没有的话,将询问下一个,也就是BeanNameUrlHandlerMapping。 

控制器 


  

如图,spring的控制器,由Controller接口定义。 

可以将控制器归类为6类 

View类型: 

ParameterizableViewController 

UrlFilenameViewController 

当控制器只需要显示静态视图时。 

Simple类型 

Controller (interface) 

AbstractController 

Throwaway类型 

ThrowawayController 

Multiaction类型 

MultiActionController 

当action中有多个执行代码(方法)。 

Command类型 

BaseCommandController 

AbstractCommandController 

action可以获取请求的一个或多个参数,并将参数封装成一个对象。还能对参数进行验证。 

Form类型 

AbstractFormController 

SimpleFormController 

拥有表单处理功能。 

Wizard类型 

AbstractWizardFormController 

当一个应用,由多个步骤组成,每一个步骤走完之后,得到一个结果,类似向导。 

AbstractCommandController 

直接继承AbstractController,自然可以访问到request,来获取参数,完成参数验证,但是这样会让你的action变得复杂。 

package com.cgodo.daowole.action; 

import javax.servlet.http.HttpServletRequest; 

import javax.servlet.http.HttpServletResponse; 

import org.springframework.validation.BindException; 

import org.springframework.web.servlet.ModelAndView; 

import org.springframework.web.servlet.mvc.AbstractCommandController; 

import com.cgodo.daowole.model.Page; 

@SuppressWarnings("deprecation") 

public class SampleController extends AbstractCommandController { 

public SampleController() { 

setCommandClass(Page.class); 

setCommandName("page"); 



@SuppressWarnings("unchecked") 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: