OSGi原理与最佳实践:第二章 基于Spring-DM实现Petstore(3)

 由  ValRay 发布

2.1.3.4 模块设计

Petstore 是一个 Web 应用,我们知道,构建基于 OSGi 的 Web 应用有两种方式,一种是采用 Bridge 方式进行部署,也就是把 OSGi 框架嵌入到 Web 服务器中,另外一种是把 Web 服务器嵌入到 OSGi 容器中,我们这次采用的是把 Web 服务器嵌入到 OSGi 容器中的方式。

从“即插即用、即删即无”的部署角度来看,要增加什么新的模块来支持现有的功能模块的部署:

部署 Bootstrap 模块,这个时候,可以看到应用的页面,但是页面只有一个简单的 Header 和 Footer,没有内容的显示。

部署 Utils 模块,这是一个基础模块,在外部展示我们看不到变化。

部署 ProductDal 模块,这是一个基础模块,在外部展示我们看不到变化。

部署 ShoppingCartDal 模块,这是一个基础模块,在外部展示我们看不到变化。

部署购物车模块,这个时候我们可以在 Header 上看到“我的购物车”的链接。 并且可以进入到展示购物车的页面。

部署 ProductManagement 模块,这个时候我们可以在 Header 上看到“库存维护”的链接。 并且可以进入到库存维护的页面。 可以进入到具体产品的页面。

部署 ProductList 模块,这个时候我们可以在 Header 上看到“宠物类目”的链接。 并且可以进入到宠物类目的页面

可以进入到具体产品的页面。

可以将产品条目加入到购物车中。

好,这个时候,我们整个的系统是部署完毕了。我们看一下模块之间的关系(见图 2-2)。 分析完模块之间的关系后,我们就要来结合各个模块具体要实现的功能进行模块自身的设计。

1.Bootstrap模块

这个模块是 Petstore 中的一个核心的控制模块。在 Bootstrap 模块中,我们做了如下几个事情:

总控的 Servlet。

定义 PageHeader,PageFooter 接口,用于扩展页面的头部和底部的实现。

定义 DefaultPage 接口,用于进行默认页面的处理。

定义 MenuItem 接口,用于其他模块注册自己模块需要的菜单。

【图 2-2 系统模块设计 】

定义ActionHandler 接口,用于其他模块注册自身提供服务的 URI,以及对应的ActionHandler。

启动了 HSQLDB 数据库,并且进行了数据初始化工作。

启提供了 PageHeader 的实现。

提供了 PageFooter 的实现。

注册了自身管理的静态资源。 看到上面的列表,可以看到 Bootstrap 模块做的事情还是比较多的,下面就来分别看一下这些功能的设计。

ControllerServlet
在整个应用中(包括其他的模块),我们只有这么一个 Servlet,用户的请求(除了资源的请求)都会进入到这个 Servlet。在这个 Servlet 中,我们首先是向 HttpService 注册了自身。并且管理了 PageHeader 、PageFooter 的实现,各个模块提供的 DefaultPage,以及各个模块提供的 ActionHandler 和 URI 的映射。 ControllerServlet 定义了页面显示的格式,分为上中下三个部分,上面是 Header,下面是 Footer,而中间就是根据请求来显示的不同内容,而如果没有找到URI对应的ActionHandler,则会显示默认的页面。

PageHeader 接口

PageHeader 接口中定义了两个方法:

String getHeadInfo(String resourcePath);

这个方法返回的是放在 HTML 页面中的之间的内容,一般我们是可以放 css 文件的连接等信息。这个方法有一个参数-resoucePath,这个参数的意思是资源文件的完整路径的前缀。方便 PageHeader 的实现者能够生成正确的 URI。

String getPageHeader(String servletPath, String resourcePath);

这个方法返回的就是 Header 本身内容对应的 HTML。两个参数,其中第二个 resourcePath 和前一个方法中的 resourcePath 含义相同。第一个 servletPath 的含义是 Petstore 应用的 URI 的前缀,方便应用生成正确的链接。

PageFooter 接口

PageFooter 接口中定义了两个方法:

String getHeadInfo(String resourcePath);

这个方法返回的是放在 HTML 页面中的之间的内容,一般我们是可以放 css 文件的连接等信息。这个方法有一个参数-resoucePath,这个参数的意思是资源文件的完整路径的前缀。方便 PageHeader 的实现者能够生成正确的 URI。

String getPageFooter(String servletPath, String resourcePath);

这个方法返回的就是 Footer 本身内容对应的 HTML。两个参数,其中第二个 resourcePath 和前一个方法中的 resourcePath 含义相同。第一个 servletPath 的含义是 Petstore 应用的 URI 的前缀,方便应用生成正确的链接。

DefaultPage 接口

DefaultPage 接口中定义了两个方法:

String getUri();

这个方法返回了一个 Uri,也就是如果当前请求的 Uri 没有对应的 ActionHandler,则会使用这个 Uri 作为替代的 Uri 进行处理。

int getPriority();

这个方法返回了一个整型值,越小表明这个 DefaultPage 的优先级越高,在不同模块注册的 DefaultPage 之间,是通过 Priority 的值来进行比较的。

MenuItem 接口

这个接口只包含了一个方法:

MenuItemInfo getMenuItemInfo();

这个方法返回了一个 MenuItemInfo 对象,代表了一个菜单项。MenuItemInfo 中主要包含了如表 2-4 所示的内容。

表 2-4 MenuItemInfo 内容

名称  

描述  

caption 

菜单显示的名称  

imgURL 

菜单的图片 URL,如果不设置,则表示菜单没有图片  

position 

菜单的位置,越小的越靠左  

url 

菜单指向的 URL 

一个模块可以实现一个或多个的 MenuItem。

ActionHandler 接口

这个接口包含了两个方法:

    String handleRequest(HttpServletRequest request, String servletPath,
 String resourcePath);

这个方法用于生成响应的 HTML 内容,有三个传入的参数,request 包含了请求的内容, servletPath 同前面我们看到的 servletPath,是 petstore 应用的 URI 的前缀。resourcePath 是静态资源请求的前缀,用于生成正确的静态资源的链接。

String getHeadInfo(String resourcePath);

这个方法和 PageHeader 及 PageFooter 中的那个同名方法的意义是一样的,用于获取这个页面要在 HTML 的加入的内容。模块通过实现一个或多个 Action- Handler 来提供对 URI 的响应。

HSQLDB 数据库

为了简化 Petstore 的环境,我们没有使用 Mysql、Oracle 这样类型的数据库,我们使用的是 HSQLDB。在应用启动的时候,我们会启动 HSQLDB,并且完成数据库的初始化工作。

PageHeader 的实现

在 Boostrap 中,我们定义了 PageHeader 接口,并且也提供了一个默认的实现。在这个默认的 PageHeader 实现中,我们主要实现了模块注册的菜单展示。

PageFooter 的实现

相对于 PageHeader 的实现,PageFooter 的实现非常简单,只是输出了一行版权的信息。

注册自身用到的静态资源

在 Bootstrap 模块中的 PageHeader 实现里面,要用到静态的图片及 css 的文件,所以我们要注册静态资源到 HttpService 中。这个工作是通过 Utils 工程中的一个辅助类来完成的。在 Utils 工程中,我们会介绍这个类,并且这个类也被其他要注册静态资源的模块所使用。

2.Utils模块

Utils 模块主要提供了多个模块都需要的功能的实现,以方便其他功能模块的功能编写。Utils 主要实现了两个功能:

模块 Web 静态资源注册管理。完成模块内部的 Web 静态资源向 HttpService 的注册和注销。注册管理器实现了 ServiceListener 接口,注册了对 HttpService 服务变化的感知。在服务发 生变化的时候,根据变化的类型来进行相应的动作。

Web 应用的配置管理。这里面的管理主要是 Web 应用的 Servlet 的 URI 前缀和静态资源的 URI 前缀的配置。这个配置管理器在整个应用中是同一个对象,由 Bootstrap 模块提供。不同模块使用同样的 Web 应用配置管理,能够保证模块生成的链接和资源链接的一致和可移植。

3.ProductDal模块

这个模块是数据访问的模块,提供了数据的存取服务。在这里,我们没有采用 Hibernate 或 iBatis 这样的框架,而是简单地使用 JDBC 的方式直接和数据库交互。并且定义了供其他模块使用的和持久数据相关的数据对象(DataObject)。ProductDal 是一个底层的模块,对外提供服务,而自身并不依赖于其他的模块。

ProductDal 中的一个示意的类图如图 2-3 所示。

【图 2-3 ProductDao 接口和其实现 】

其他的几个 Dao 接口和实现的类图,我们这里就不再一一列出了。

4.ShoppingCartDal模块

ShoppingCartDal 提供了用户的购物车数据管理的功能。思路和 ProductDal 模块是类似的,只是在实现上,我们实现了一个基于内存的 ShoppingCart 数据管理,也提供了外部使用的数据对象。感兴趣的读者,可以改写 ShoppingCartDal 模块,可以考虑使用 iBatis 或者 Hibernate 来实现 ShoppingCartDal 中的 Dao 接口,提供持久的数据存取服务。

5.ProductList模块

ProductList 模块提供了类目列表页面,页面上显示了所有的类目,以及类目中包含的产品。点击产品的链接,会进入到产品信息的页面,列出了该产品下包含的具体条目,也显示了产品和条目相关的信息,用户可以在这个页面中把选中的条目加入到购物车中。这里,ProductList 模块要用到ShoppingCartDal 和 ProductDal 中的一些 Dao 接口的实现,用于访问相关的数据。在 ProductList 中,要实现多个 ActionHandler,来提供对页面请求的处理。并且提供了菜单给 Bootstrap 中的 PageHeader 模块。用于展示菜单。我们来看下 ProductList 模块中的类的类图。

DefaultPage 的实现,如图 2-4 所示。

【图 2-4 DefaultPage 接口及实现 】

MenuItem 的实现,如图 2-5 所示。

【图 2-5 MenuItem 接口及实现 】
ActionHandler的实现,如图2-6所示。

【图2-6 ActionHandler 接口及实现】

BaseActionHandler 主要实现了对 Web 静态资源的配置管理,而从 BaseActionHandler 派生出的 CategoryListActionHandler 和 ProductListActionHandler 是实际处理 URI 的 ActionHandler。

6.ProductManagement模块

这个模块提供了产品维护的功能,目前主要实现的是库存的修改功能。和之前提到的 ProductList 模块类似,ProductManagement 模块也要响应 Dal 模块提供的 Dao 接口的实现。并且要提供 MenuItem 和 ActionHandler 的实现。整体思路同 ProductList 模块。

7.ShoppingCart模块

这同样也是一个展现用的模块。功能是展现用户当前购物车的状况,以及对购物车中的产品条目进行删除和修改数量的操作。从设计上,ShoppingCart 和之前的 ProductList、ProductManagement 模 块是一样的。

完成了模块的设计,下面就让我们来实现这些模块,完成 Petstore 的编码

查看评论