第14章Web框架

优质
小牛编辑
135浏览
2023-12-01

第 14 章 Web框架

目录

14.1. 介绍
14.1.1. 与其他web框架的集成
14.1.2. Spring Web MVC框架的特点
14.2. DispatcherServlet
14.3. 控制器
14.3.1. AbstractControllerWebContentGenerator
14.3.2. 其它的简单控制器
14.3.3. MultiActionController
14.3.4. 命令控制器
14.4. 处理器映射(handler mapping)
14.4.1. BeanNameUrlHandlerMapping
14.4.2. SimpleUrlHandlerMapping
14.4.3. 拦截器(HandlerInterceptor
14.5. 视图与视图解析
14.5.1. 视图解析器
14.5.2. 视图解析链
14.5.3. 重定向(Rediret)到另一个视图
14.6. 本地化解析器
14.6.1. AcceptHeaderLocaleResolver
14.6.2. CookieLocaleResolver
14.6.3. SessionLocaleResolver
14.6.4. LocaleChangeInterceptor
14.7. 使用主题
14.7.1. 简介
14.7.2. 如何定义主题
14.7.3. 主题解析器
14.8. Spring对分段文件上传(multipart file upload)的支持
14.8.1. 介绍
14.8.2. 使用MultipartResolver
14.8.3. 在表单中处理分段文件上传
14.9. 使用Spring的表单标签库
14.9.1. 配置标签库
14.9.2. form标签
14.9.3. input标签
14.9.4. checkbox标签
14.9.5. radiobutton标签
14.9.6. password标签
14.9.7. select标签
14.9.8. option标签
14.9.9. options标签
14.9.10. textarea标签
14.9.11. hidden标签
14.9.12. errors标签
14.10. 处理异常
14.11. 惯例优先原则(convention over configuration)
14.11.1. 对控制器的支持: ControllerClassNameHandlerMapping
14.11.2. 对模型的支持:ModelMap (ModelAndView)
14.11.3. 对视图的支持: RequestToViewNameTranslator
14.12. 其它资源

14.1. 介绍

Spring的web框架是围绕DispatcherServlet来进行设计的。DispatcherServlet的作用是将请求分发到不同的处理器。Spring的web框架包括可配置的处理器(handler)映射、视图(view)解析、本地化(local)解析、主题(theme)解析以及对上传文件解析。处理器是对Controller接口的实现,该接口仅仅定义了ModelAndView handleRequest(request, response)方法。你可以通过实现这个接口来生成自己的控制器(也可以称之为处理器),但是从Spring提供的一系列控制器继承会更省事,比如AbstractControllerAbstractCommandControllerSimpleFormController。注意,你需要选择正确的基类:如果你没有表单,你就不需要一个FormController。这是和Structs的一个主要区别。

“遵循开闭原则”

贯穿整个Spring web框架(甚至整个Spring框架)的一个设计原则是:“对扩展开放,对修改封闭(开闭原则 OCP)

我们之所以在这里提到这个设计原则,是因为Spring Web MVC 框架中核心类的很多方法都被标记成final。这意味着你不可以通过复写(override)来修改这些方法的功能。这是遵从开闭原则(OCP)的决定,并不是故意刁难开发人员。

在Seth Ladd等人所着《Expert Spring Web MVC and Web Flow》一书中详细地解释了这个设计原则以及为什么要遵守它。如果有兴趣的话,你可以参考该书第一版117页。那一部分的标题为“A Look At Design”。

如果你找不到那本书,也可以参考下面这篇文档:Bob Martin, The Open-Closed Principle (PDF)。

你可以使用任何对象作为命令对象(或表单对象):不必实现某个接口或从某个基类继承。Spring的数据绑定相当灵活,例如,它认为类型不匹配这样的错误应该是应用级的验证错误,而不是系统错误。所以你不需要为了保证表单内容的正确提交,而重复定义一个和业务对象有相同属性的表单对象来处理简单的无类型字符串或者对字符串进行转换。这也是和Struts相比的另一个重要区别,Struts是围绕象ActionActionForm这样的基类构建的。

和WebWork相比,Spring将对象细分成更多不同的角色:控制器(Controller)、可选的命令对象(Command Object)或表单对象(Form Object),以及传递到视图的模型(Model)。模型不仅包含命令对象或表单对象,而且也可以包含任何引用数据。相比之下,WebWork的Action将所有的这些角色都合并在一个单独的对象里。WebWork的确允许你在表单中使用现有的业务对象,但是你必须把它们定义成相应的Action类的bean属性。更重要的是,在进行视图层(View)运算和表单赋值时,WebWork使用的是同一个处理请求的Action实例。因此,引用数据也需要被定义成Action的bean属性。这样一个对象就承担了太多的角色(当然,对于这个观点仍有争议)。

Spring的视图解析相当灵活。一个控制器甚至可以直接向response输出一个视图(此时控制器返回ModelAndView的值必须是null)。在一般的情况下,一个ModelAndView实例包含一个视图名字和一个类型为Map的model,一个model是一些以bean的名字为key,以bean对象(可以是命令或form,也可以是其他的JavaBean)为value的名值对。对视图名称的解析处理也是高度可配置的,可以通过bean的名字、属性文件或者自定义的ViewResolver实现来进行解析。实际上基于Map的model(也就是MVC中的M))是高度抽象的,适用于各种表现层技术。也就是说,任何表现层都可以直接和Spring集成,无论是JSP、Velocity还是其它表现层技术。Map model可以被转换成合适的格式,比如JSP request attribute或者Velocity template model。

14.1.1. 与其他web框架的集成

由于种种原因,许多团队倾向于使用其他的web框架。比如,某些团队已经在其他的技术和工具方面进行了投入,他们希望充分利用已有的经验。另外,Struts不仅有大量的书籍和工具,而且有许多开发者熟悉它。因此,如果你能忍受Struts的架构性缺陷,它仍然是web层一个不错的选择。WebWork和其它的web框架也是这样。

如果你不想使用Spring的web MVC框架,但仍希望使用Spring提供的其它功能,你可以很容易地将你选择的web框架和Spring结合起来。只需通过Spring的ContextLoadListener启动一个root application context,你就可以在Struts或WebWork的Action中,通过ServletContext属性(或者Spring提供的相应辅助方法)进行访问。请注意我们没有提到任何具体的“plugins”,因此也不必提及如何集成。从web层的角度看,你可以以root application context实例为入口,把Spring作为一个library使用。

即便你不使用Spring的web框架,经注册的所有bean和所有Spring服务仍然可以使用。从这个用法上来讲,Spring并没有和Struts或WebWork竞争,它只是提供这些纯粹的web框架所没有的功能,例如:bean的配置、数据访问和事务处理。因此你可以使用Spring的中间层或者数据访问层来增强你的应用,即便你只是需要使用像JDBC或Hibernate事务抽象这样的功能。

14.1.2. Spring Web MVC框架的特点

Spring Web MVC框架提供了大量独特的功能,包括:

  • 清晰的角色划分:控制器(controller)、验证器(validator)、命令对象(command object)、表单对象(form object)、模型对象(model object)、Servlet分发器(DispatcherServlet)、处理器映射(handler mapping)、视图解析器(view resolver)等等。 每一个角色都可以由一个专门的对象来实现。

  • 强大而直接的配置方式:将框架类和应用类都作为JavaBean配置,支持在一个context中引用其他context的中JavaBean,例如,在web控制器中对业务对象和验证器(validator)的引用。

  • 可适配、非侵入的controller:你可以根据不同的应用场景,选择合适的控制器子类(simple型、command型、form型、wizard型、multi-action型或者自定义),而不是从单一控制器(比如Action/ActionForm)继承。

  • 可重用的业务代码:你可以使用现有的业务对象作为命令或表单对象,而不需要在类似ActionForm的子类中重复它们的定义。

  • 可定制的绑定(binding) 和验证(validation):比如将类型不匹配作为应用级的验证错误,这可以保存错误的值。再比如本地化的日期和数字绑定等等。在其他某些框架中,你只能使用字符串表单对象,需要手动解析它并转换到业务对象。

  • 可定制的handler mapping和view resolution:Spring提供从最简单的的URL映射,到复杂的、专用的定制策略。与某些MVC框架强制开发人员使用单一特定技术相比,Spring显得更加灵活。灵活。

  • 灵活的model转换: 在Springweb框架中,使用基于Map的名/值对来达到轻易地与各种视图技术的集成。

  • 可定制的本地化和主题(theme)解析:支持在JSP中可选择地使用Spring标签库、支持JSTL、支持Velocity(不需要额外的中间层)等等。

  • 简单而强大的JSP标签库(Spring Tag Library):支持包括诸如数据绑定和主题(theme)之类的许多功能。它提供在标记方面的最大灵活性。如欲了解详情,请参阅附录附录 D, spring.tld

  • 新增加的JSP表单标签库:在Spring2.0中刚刚引入的表单标签库,使得在JSP中编写表单更加容易。如欲了解详情,请参阅附录附录 E, spring-form.tld

  • Spring Bean的生命周期可以被限制在当前的HTTP Request或者HTTP Session。准确的说,这并非Spring MVC框架本身特性,而应归属于Sping MVC使用的WebApplicationContext容器。该功能在第 4.4.3 节 “其他作用域”有详细描述。