MVC是Web开发的一种流行架构思想,为了改正以前代码逻辑视图混乱不堪的状况而总结出来的一种模式。在最早是受到观察者模式的启发(观察者模式类似于Java Swing里的ActionListener)。记得大三还在学校自己泡图书馆的时候Struts是很风靡的MVC框架,也可以说是流行起来的第一个比较标准的MVC实现。在Spring推出之后,Spring自己也提供了一套MVC框架,在工作和学习中二者都用得比较频繁,还是比较偏向Spring MVC一点,这里也做一下总结:
MVC模型(这里不讨论MVC Model-1)的核心思想就是Web开发的前后端解耦合,前端组件只负责视图,后端组件关注业务逻辑调用;MVC的核心组件就是连接前后端的Controller(也就是Struts里面的Action)。理想的解耦合状态就是能使得前后端组件像搭积木一样可以自由组合,比如视图组件有View-1、View-2、View-3,业务组件有Business-1、Business-2,那么MVC的Controller就应该能负责把任意一个View引导向任意一个Business,使得二者合作单向就应该有2×3种组合方式,这也符合J2EE组件和容器核心规范的原则。而之前的Struts-1之所以不那么标准多少起源习惯问题,Struts-1中充当Controller的Action类容易跟业务组件密切相关,也许是因为当时没有依赖注入,程序员总是喜欢把本来只属于业务组件Service里的代码写到Action的execute方法中,使得业务代码跟HttpRequest封装在同一方法里。
下面列举Spring MVC的核心组件:
DispatcherServlet
前端控制器,等同于Struts中的ActionServlet,仅仅负责分发不同的HttpRequest给不同的后端控制器即各种Controller,分发的时候需要借助映射工具类来解析请求映射关系。
Controller
后端控制器解析用户输入,并将其转换成合理的模型数据,从而可以进一步由视图展示给用户。包括表单控制器、命令控制器和向导型控制器等。所有Spring Controller都继承了AbstractController,它提供了缓存支持和MIME-TYPE设置这样的功能。
最常用的要属MultiActionActionController,它能将多个HttpRequest请求处理方法封装在同一个控制器里,便于组合相关功能。它需要指定一个映射工具类MethodNameResolver,告诉控制器如何根据请求参数执行正确的Controller方法。常用的有ParameterMethodNameResolver和PropertiesMethodNameResolver,前者指定根据前台提交Request域中某一特定属性值(比如?action=method)来找到方法,后者根据配置文件配置。
HandlerMapping
处理器映射请求到特定的控制器,Spring内置了很多种映射策略。当DispatcherServelt收到请求时将会交给处理器映射,让它检查并查找到一个适当的HandlerExecutionChain,这个Chain必须包含一个处理器(Handler),同时可选的包含许多拦截器(Interceptor)。
最常用的两个处理器映射对象是SimpleUrlHandlerMapping和BeanNameUrlHandlerMapping。前者可以在应用上下文中配置,具有Ant风格的路径匹配功能,后者简单的根据Http请求串中的最后一截串匹配Web应用上下文中定义的Bean Name。
在上述两种HandlerMapping中都可以配置拦截器(HandlerInterceptor),针对各种特殊需求拦截请求并执行过滤。这里利用了Spring内置的AOP技术。
ViewResolver
当控制器执行完处理方法之后会返回一个ModelAndView对象,该对象封装着简单的Model数据和视图对象View。这个时候需要一个视图解析器来完成请求回复的视图定位工作。Spring内置的视图解析器包括XmlViewResolver、ResourceBundleViewResolver、UrlBasedViewResolver等。比如针对Jsp视图层就可以选择较为通用的UrlBasedViewResolver,它将返回一个url做为解析结果给RequestDispatcher转发。其它的解析器可以针对XML或者Velocity等不同的表示层技术来返回最终视图定位。
核心组件就这么几个,除此之外Spring MVC内置的其它组件也非常全面,适合各种Web应用开发需求。例如MultipartResolver支持分段文件上传;Spring允许通过主题(theme)来控制网页的风格,进一步改善用户的体验; Spring还提供了一套支持数据绑定的标签集合,用于处理表单元素等等。在新的版本Spring2.5中为了配合J2EE5规范的出台又增加了注释配置的支持,例如使用@Controller来指定一个类具有控制器的职责、使用@RequestParam绑定请求参数到方法参数、使用@SessionAttributes指定存储在会话中的属性等。
说了这么多,简单的看一个配置范例结束对Spring MVC的总结——
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"> <bean id="urlMapping" class="org.springframework.web.sevlet.handler.SimpleUrlHandlerMapping"> <props> <prop key="/login.do">loginController</prop> <prop key="/register.do">registerController</prop> </props> </bean> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <bean id="paraMethodResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMEthodParameterMethodResolver"> <property name="paramName" value="action"/> <property name="defaultMethodName" value="handleRequest"/> </bean> <bean id="loginController" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController"> <property name="methodNameResolver" ref="paraMethodResolver"/> <property name="delegate" ref="loginDelegate"/> </bean> <bean id="loginDelegate" class="com.myBusiness.LoginComponent"> <property name="success" value="mainPage"/> <property name="error" value="errorPage"/> </bean> <bean id="registerController" class="com.myBusiness.controller.RegisterController"> <property name="success" value="mainPage"/> <property name="fail" value="loginPage"> </bean> </beans>