`
gao_xianglong
  • 浏览: 461781 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

详解SSJ(Spring3.x mvc + Spring3.x Core + JPA2.x)轻量级集成开发—第8章 Spring3.x mvc核心类库及基础构建

阅读更多

上一章 详解SSJ(Spring3.x mvc + Spring3.x Core + JPA2.x)轻量级集成开发—第7章 笔者带走进Spring3.x MVC的世界

 

目录

一、HandlerMapping接口;

二、Controller接口;

三、HandlerInterceptor接口;

四、ViewResolver接口;

五、ExceptionResolver接口;

六、DispatcherServlet类型;

七、ModelAndView类型;

八、构件依赖管理;

九、基于web.xml配置Font Controller;

十、构建基础Spring MVC应用;

 

前言

笔者在上一章为大家简单介绍了Spring3.x MVC的工作流程,但其中并未牵扯到过多的技术细节。那么从本章开始,笔者就要正式带领大家展开Spring3.x MVC的学习。近期笔者博文一直保持着较为缓慢的更新速度,因为这段时间确实工作较忙,望体谅。

本章内容笔者会大致向大家介绍Spring3.x MVC的一些核心类库及Spring MVC应用的基础构建。在开始正式讲解之前笔者提醒各位,如果你对Spring Core本身并不了解,那么你应该仔细阅读笔者早期的系列博文。

 

一、HandlerMapping接口

Spring MVC的工作流程机制参考于Struts2.x,但整体构架却大相庭径。简单来说Struts2.x的内核中充斥着大量的内置拦截器(约70%),但Spring MVC却并没有选择这么做。在Spring MVC的工作流程机制中,客户端的请求响应/分发工作全由DispatcherServlet(前端控制器)负责,DispatcherServlet仅只是一个普通的Servlet。当DispatcherServlet成功拦截客户端请求后,便会加载WEB-INF目录下的Spring MVC配置文件。然后根据HandlerMapping的实例(配置文件中的映射信息)分发给对应的Controller(业务控制器)处理。Controller在调用具体的业务实现之前,会负责一系列的参数预处理工作(包含:解析参数、类型转换、封装DTO等)。最后Controller根据处理结果forward到具体的View层组件。

Spring MVC工作流程示例图:

 

HandlerMapping的常用实现如下:
1、BeanNameUrlHandlerMapping;
2、SimpleUrlHandlerMapping;

 

在缺省状态下,DispatcherServlet为HandlerMapping接口预设的实现为BeanNameUrlHandlerMapping,当然开发人员也可以显式指定HandlerMapping的实现。相对于BeanNameUrlHandlerMapping而言,SimpleUrlHandlerMapping才是HandlerMapping接口最为常用的实现,因为BeanNameUrlHandlerMapping仅适用于一些请求较小的应用场景,反之我们则可以考虑使用SimpleUrlHandlerMapping。

 

二、Controller接口

笔者上述章节提到过Controller(业务控制器)才是处理实际请求的操作者它的任务来源取决于DispatcherServlet的任务分发。Spring MVC为开发人员提供了一系列非常丰富的Controller实现,因此我们可以根据实际的需求来继承指定Controller实现,以便更好的完成请求处理。

Controller派生依赖示例图:

 

AbstractController作为Controller接口的派生类,并提供有Session读/取与线程安全(synchronized)的处理。开发人员可以在POJO中直接继承AbstractController,并重写handleRequestInternal()方法处理实际的用户请求。

 

提示

实际开发过程中,开发人员一般都会仅选择实现Controller接口。当然如果为了满足其它特定应用场景,则应该选择相应的Controller接口实现。关于其它Controller接口的派生类本章将不再继续讲解,如果大家感兴趣,则请参阅Spring3.x MVC官方手册。
 

三、HandlerInterceptor接口

HandlerInterceptor作为自定义拦截器接口,使得开发人员可以通过实现该接口很方便的编写拦截器。既然提到拦截器,笔者还是有必要为大家简单介绍一下拦截器的工作机制。首先为什么需要使用拦截器?在实际开发过程中,控制层组件往往需要在调用业务操作之前,进行一系列的控制逻辑操作,这些操作包含:权限验证、粗粒度日志记录等。但我们并不希望这些控制逻辑耦合在我们的业务操作中,也就是说我们希望控制逻辑独立于业务逻辑或业务控制成员,并且最好是以可插拔的方式进行松耦合配置。谈到这里或许大家会想到AOP(Aspect Oriented Programming,面向切面编程),没错拦截器实现确实就是基于AOP原理。

在实际开发过程中,开发人员除了允许实现HandlerInterceptor接口定义拦截器外,还可以选择继承HandlerInterceptor接口的派生类HandlerInterceptorAdapter。

 

四、ViewResolver接口

ViewResolver接口作为视图解析器,作用于视图资源拼接。当Controller处理完用户请求后,会返回指定的逻辑视图名称。ViewResolver则会根据这些返回的逻辑视图名称,通过前后拼接的方式解析出实际的物理视图名称(既URL)返回给DispatcherServlet进行对应的视图组件forward

ViewResolver接口的常用派生类有:InternalResourceViewResolverUrlBasedViewResolver,但一般相对来说使用InternalResourceViewResolver则更能满足于多数应用场景。

 

五、ExceptionResolver接口

如果JSP或者Servlet在运行过程中触发异常,开发人员可以采用多种方式来捕获这些异常。但在实际开发过程中,最为常用的做法是在web.xml文件中配置<error-page/>标签进行异常捕获:

<error-page>
	<error-code>404</error-code>
	<location>/error.jsp</location>
</error-page>

 

当然除了可以在web.xml文件中配置<error-page/>标签捕获异常之外,开发人员还可以通过指定JSP网页“Page”指令的“errorPage”属性。当然除了上述2种做法之外,Spring MVC也为开发人员提供了用于捕获异常的ExceptionResolver接口,我们只需在Spring配置文件中定义一个ExceptionResolverBean实例即可。

定义ExceptionResolver捕获异常示例:

<bean id="exceptionResolver" class="org.springframework.web.servlet.
	handler.SimpleMappingExceptionResolver">
	<property name="exceptionMappings">
		<props>
			<prop key="java.sql.SQLException">error</prop>
		</props>
	</property>
</bean>

 

通过上述配置文件我们可以看出,异常信息我们是配置在<props/>根标签中的。在<props/>标签内部我们可以定义多个<prop/>子标签来配置这些异常信息,其中属性“key”指定了异常类型,而值”error“则定义了当触发异常时,需要跳转的“逻辑视图”名称。

 

六、DispatcherServlet类型

Struts2.x中,核心控制器我们称之为FileterDispatcher,由它负责请求拦截及调用内置的拦截器完成一些参数的预处理工作。而DispatcherServlet作为Spring MVC的前端控制器,和Struts2.x中的FileterDispatcher作用类似。由它负责请求拦截,及根据映射文件中的描述信息分发任务给具体的Controller处理。在Spring MVCDispatcherServlet作为Servlet存在,也就是说我们必须在web.xml文件中对DispatcherServlet进行配置。

 

七、ModelAndView类型

ModelAndView作为Controller处理用户请求缺省返回类型,由它封装并返回View组件的名称及Model参数。

在Spring MVC中ModelAndView最常用的2个方法:

方法名称 返回类型 方法描述
addAllObjects(Map<String, ?> modelMap) ModelAndView 用于添加客户端请求的所有Model参数。
setViewName(String viewName) void 指定逻辑视图名称。


在使用addAllObjects()方法显式添加Model参数时务必注意,该方法参数为一个Map集合。也就是说如果你需要先将请求参数封装置一个Map集合中,然后才能添加至该方法中。然而setViewName()方法则用于设定指定“逻辑视图”名称。

 使用ModelAndView示例:

ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/success");
modelAndView.addAllObjects(new HashMap());

 

开发人员除了可以显式调用ModelAndView的方法指定“逻辑视图”名称以及Model参数外,Spring MVC还允许在ModelAndView构造时进行添加:

return new ModelAndView("/success", new HashMap());

  

八、构件依赖管理

如果你是使用Spring Tool Suite工具进行Maven3.x的项目管理,那么你将完全不必担心依赖构件管理。因为Spring Tool Suite缺省已经为你配置好了Spring3.x MVC所需的依赖构件。

下述为构建Spring MVC应用的核心构件:

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>${org.springframework-version}</version>
</dependency>

 

九、基于web.xml配置Font Controller

在正式开始构建Spring MVC应用之前,我们首先需要在web.xml文件中配置Font Controller。也就是说我们需要对Web容器添加DispatcherServlet(前端控制器)支持,一旦成功配置Font Controller,客户端提交的所有请求信息,都将会被DispatcherServlet拦截(开发人员可以指定拦截行为)。
添加DispatcherServlet支持:

<!-- 定义DispatcherServlet控制器 -->
<servlet>
	<servlet-name>appServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

	<!-- 显式定义配置文件路径 -->
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
	</init-param>

	<!-- 定义加载优先级 -->
	<load-on-startup>1</load-on-startup>
</servlet>

<!-- 定义拦截行为 -->
<servlet-mapping>
	<servlet-name>appServlet</servlet-name>
	<url-pattern>/</url-pattern>
</servlet-mapping>

 

上述配置文件中我们通过使用<servlet/>标签添加了Web容器对DispatcherServlet的支持,这样一来客户端提交的请求信息都将被拦截,并由它负责分发任务给Controller进行处理。<load-on-startup/>标签定义DispatcherServlet的加载优先级,也就是说一旦Web容器启动,首先务必加载DispatcherServlet。当然我们也可以对DispatcherServlet的加载优先级进行设定,数值越小那么优先级越高。
<url-pattern>标签指定了DispatcherServlet的拦截行为,上述配置为“/”时,DispatcherServlet则会拦截客户端所有请求。除此之外我们还可以显式指定DispatcherServlet的拦截行为,比如“*.do”,这样一来DispatcherServlet只会拦截后缀为“.do”的请求,其余则全部过滤

 

提示

当Web容器加载DispatcherServlet时,缺省情况下会在WEB-INF目录下寻找一个名为(servlet-name)-servlet.xml的文件,该文件为Spring MVC的映射文件。<servlet-name/>标签中所指定的名称便是映射文件的名称,当然我们也可以通过使用<init-param/>标签显式指定映射文件的加载路径
显式指定Spring映射文件的加载路径:

<!-- 加载映射文件 -->
<init-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/spring/spring-servlet.xml</param-value>
</init-param>

 

显式指定多个Spring映射文件的加载路径:

<!-- 加载多个映射文件 -->
<init-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/spring/*.xml</param-value>
</init-param>

 

十、构建基础Spring MVC应用

当我们成功在web.xml配置文件中配置好DispatcherServlet(前端控制器)支持后,我们还需在web.xml文件中添加IOC容器的自动初始化。因为在实际开发过程中,Spring的配置文件会因为职责的不同而进行划分。

配置自动初始化IOC容器示例:

<!-- 初始化IOC容器 -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>

 

当成功配置好IOC容器后,一旦Web容器成功运行时,便会自动初始化咱们的IOC容器。上述程序我们采用监听的形式配置IOC容器,当然此方式仅限于Servlet2.4及以上规范的Servlet容器。如果你的Servlet容器规范低于2.4你可以选用ContextLoaderServlet的方式实现:

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:spring-config/root-context.xml</param-value>
</context-param>
<servlet>
	<servlet-name>context</servlet-name>
	<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

 

提示

当Web容器启动的时候,Listener组件的加载顺序必然优先于Servlet组件。 至于ContextLoaderServlet的出现其最大的目的还是为了满足那些低于2.4 Servlet容器规范的Web容器。

 

接下来我们先编写一个简单的View组件,该组件的目的就是用于提交请求参数至Controller进行处理。

编写Login.jsp示例:

<body>
	<form action="login" method="post">
		userLogin: <input type="text" name="userName"/><br>
		password: <input type="text" name="passWord"/><br>
		<input type="submit" value="Login"/>
	</form>
</body>

 

当成功编写好View组件后,我们接下来要做的事情就是配置Spring所需的一系列配置文件。如果你Spring Tool Suite工具进行Maven3.x的项目管理,则会缺省生成Spring MVC所需的配置文件。这些配置文件主要分成2部分,其中既包含Controller所需的配置文件,同样也包含Bean配置文件(不好归类)。

Controller配置文件:

<!-- 定义组件自动扫包 -->
<context:component-scan base-package="*" />

<!-- 定义视图解析器 -->
<bean id="viewResolver"
	class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<!-- 注入viewClass实例 -->
	<property name="viewClass"
		value="org.springframework.web.servlet.view.JstlView" />
	<!-- URL前缀 -->
	<property name="prefix" value="/WEB-INF/views/" />
	<!-- URL后缀 -->
	<property name="suffix" value=".jsp" />
</bean>

<!-- 定义login.do请求 -->
<bean name="/login" class="org.johngao.controller.LoginController" />

 

上述配置文件中,我们通过使用InternalResourceViewResolver作为viewResolver的实例。其中属性“prefix”定义了URL的前缀,而属性“prefix”则用于定义后缀。当Controller返回“逻辑视图”名称时,ViewResolver则会通过前后拼接的方式将其拼接出一个完整的“物理视图”名称。

定义实际的请求处理我们还是采用传统的<bean/>定义方式,只不过不是采用属性“id”而是属性“name”。属性“class”则用于指定实际的Controller,当DispatcherServlet成功拦截客户端请求后,便会加载WEB-INF目录下的Spring MVC配置文件。然后根据HandlerMapping的实例(配置文件中的映射信息)分发给对应的Controller(业务控制器)处理。

定义Bean配置文件:

<!-- 引用其他配置文件 -->
	<import resource="appServlet/servlet-context.xml" />

	<!-- 定义modelMap实例 -->
	<bean id="modelMap" class="java.util.HashMap" />

	<!-- 定义modelAndView实例 -->
	<bean id="modelAndView" class="org.springframework.web.servlet.ModelAndView" />

 

上述配置文件中,笔者显式的使用了<import/>标签引用了其它Spring配置文件,因为实际的开发过程中配置文件由于责任分工不同,有可能不同处一个目录下。

当一切准备工作都完成后,我们还需要编写实际的Controller处理用户请求。

编写Controller实现:

public class LoginController implements Controller{
	@Resource
	private LoginBean loginBean;

	@Resource
	private Map<String, LoginBean> modelMap;

	@Resource
	private ModelAndView modelAndView;

	@Override
	public ModelAndView handleRequest(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		/* 接受表单参数并类型转换 */
		loginBean.setUserName(request.getParameter("userName"));
		loginBean.setPassWord(request.getParameter("passWord"));
		modelMap.put("loginInfo", loginBean);

		/* 定义逻辑视图名称 */
		modelAndView.setViewName("success");
		modelAndView.addAllObjects(modelMap);
		return modelAndView;
	}
}

  

笔者上述程序示例中定义了一个处理登陆请求的Controller,并显式的实现了Controller接口及重写了该接口中的handleRequest()方法。可以发现该方法返回的是一个ModelAndView实例,该实例中我们需要显示的封装2个参数,一个是“逻辑视图”名称,一个则是Model参数,最后返回即可。

和Strus2.x一样的是,Spring仍然支持自动类型转换。只不过为了更好的实现解耦,笔者将请求参数单独定义为一个POJO,并且Spring3.x MVC也建议这么做,至于为什么后续章节笔者会着重介绍。

最后开发人员可以从返回的ModelAndView实例中获取到一系列的请求参数。

获取请求参数:

<body>
	${loginInfo.userName}
	${loginInfo.passWord}
</body>

 

本章内容到此结束,由于时间仓库,本文或许有很多不尽人意的地方,希望各位能够理解和体谅。关于下一章笔者打算继续讲解Spring MVC的相关内容,谢谢各位的支持,晚安。

Our Team:154414028。

5
2
分享到:
评论
5 楼 kazaff 2013-11-27  
怎么断了?换地方发布了么?
4 楼 蒙太奇 2013-05-31  
怎么没JAP呀。。。
3 楼 liuhaixiao 2013-04-02  
楼主要抓紧啊。
2 楼 zhangyiwen1999 2013-03-18  
    学习了 多谢多谢
1 楼 duoduodeai 2013-03-17  
  绝对要支持

相关推荐

Global site tag (gtag.js) - Google Analytics