《基于Jazz技术构建企业级Web2.0应用》系列第一部分:第1部分:数据模型设计与持久化
【IT168 专稿】
在本系列文章的第一部分里详细介绍了怎样基于Jazz提供的O-R mapping机制来实现数据层的持久化。本文将详细描述怎样利用Jazz平台提供的基础服务来为我们的企业级应用提供业务服务层支持的全过程。通过阅读本文,你将了解如何来构建基于Jazz的RPC服务、REST服务以及DTO设计。文章的最后还阐述了怎样基于Jazz提供的测试框架来对服务层进行单元测试。
Jazz服务层介绍
构建在Jazz平台上的服务分为四类:
· RPC服务:通常负责底层业务逻辑的实现,如对数据进行增、删、改、查(C/R/U/D)操作,类似于J2EE开发中的数据访问对象(Data Access Object, DAO)
· REST服务:REST服务是一种无状态的轻量级的Web服务,主要负责向客户端(如Web客户端)提供REST风格的服务,一般构建在RPC服务层之上并通过调用RPC服务实现其业务功能,并把处理结果以SOAP的消息形式返回给客户端。
· HTTP:负责直接处理和响应http请求(如HTTP POST GET DELETE等)类似于Servlet
· CONTENT:主要负责二进制数据类型content(Jazz定义的特殊数据类型)的存取,如用于实现附件上传等功能。Jazz会将这些二进制数据储存于文件系统或者数据库的BLOB字段中。
PetStore服务层介绍
在一个典型的Jazz Web应用中,通常需要实现一组RPC服务实现对数据的操作,并在此基础上通过REST服务向Web客户端提供服务接口。本文将以PetStore为例介绍如何实现Jazz平台上的服务实现和测试。内容包括:
· 实现一组RPC服务以完成PetStore中各种数据类型的CRUD功能。
· 实现一个REST服务IPetStoreRestService,封装RPC服务的功能供给Web Client调用,实现宠物出售、查询、购买等业务逻辑。
· 通过一个JUnit插件项目实现对RPC服务和REST服务层的单元测试。
PetStore RPC服务的定义和实现
在Jazz服务开发中,通常需要为每种数据类型实现一个RPC服务提供CRUD功能。下面我们以PetStore中的IProductService为例介绍RPC服务定义和实现。
PetStore RPC服务涉及两个bundle,其中RPC服务的定义在bundle com.ibm.petstore.common中,RPC服务的具体实现在bundle com.ibm.petstore.service中。具体步骤如下
1.在com.ibm.petstore.common中定义RPC服务的接口,如清单1所示
清单1. IProductService服务接口定义
public interface IProductService {
//创建或修改宠物信息
public IProduct createProduct(int id, String name, String description,
ICategoryHandle category, ISellerHandle seller, int price,
String tags) throws TeamRepositoryException;
//保存宠物信息
public IProduct saveProduct(IProduct workingCopy)
throws TeamRepositoryException;
//查找所有的宠物
public IProduct[] findAllProducts() throws TeamRepositoryException;
//查找id对应的宠物
public IProduct findProductById(int id) throws TeamRepositoryException;
}
注意:服务中每个方法都需要抛出TeamRepositoryException。
2.在com.ibm.petstore.common的plugin.xml中进行RPC服务的注册, 如清单2所示
清单2. IProductService服务接口注册
<service
kind="RPC"
name="IProductService"
uri="com.ibm.petstore.common.service.IProductService"
version="1">
</service>
注意:这里“kind”属性为“RPC”,表示注册的是一个RPC服务,“uri”属性为第(1)步中定义的服务接口,Jazz在服务器启动时会自动地对这个RPC服务进行实例化。
3.在com.ibm.petstore.service中实现各个RPC服务,如清单3所示
清单3. IProductService服务实现
public class ProductService extends AbstractService implements
IProductService {
……
}
注意:RPC服务的实现类需要继承com.ibm.team.repository.service.AbstractService,并实现第(1)步中定义的服务接口。其中AbstractService是Jazz中所有服务的抽象基类,提供了服务的上下文、服务绑定以及一些公用的基础设施。
4.在com.ibm.petstore.service的plugin.xml中进行RPC服务和实现类的绑定,如清单4所示
清单4. IProductService服务实现注册
<serviceProvider
componentId="com.ibm.petstore"
implementationClass="com.ibm.petstore.service.ProductService">
<provides>
<providedService
interface="com.ibm.petstore.common.service.IProductService">
</providedService>
</provides>
<prerequisites>
<requiredService
interface="com.ibm.team.repository.common.service.IQueryService">
</requiredService>
<requiredService
interface="com.ibm.team.repository.service.IRepositoryItemService">
</requiredService>
</prerequisites>
</serviceProvider>
在服务实现的注册中我们将服务com.ibm.petstore.common.service.IProductService与其实现类com.ibm.petstore.service.ProductService绑定,并通过requiredService字段声明了其依赖的两个服务com.ibm.team.repository.common.service.IQueryService和com.ibm.team.repository.service.IRepositoryItemService,这样Jazz在加载一个IProductService服务的实例前会先为其加载这两个服务的实例。
在调用依赖的服务时,可以使用Jazz提供的依赖注入机制,通过getService方法(由RPC服务实现类的基类com.ibm.team.repository.service.AbstractService提供)获得任何一个服务实例,然后就可以使用该服务了。清单5展示了在ProductService类中获得IRepositoryItemService和IQueryService实例来实现查找所有宠物的代码片段:
清单5. getService方法示例
public IProduct[] findAllProducts() throws TeamRepositoryException {
IQueryService queryService = getService(IQueryService.class);
ProductQueryModel queryModel = BaseProductQueryModel.ProductQueryModel.ROOT;
IItemQuery itemQuery = IItemQuery.FACTORY.newInstance(queryModel);
IItemQueryPage itemQueryPage = queryService.queryItems(itemQuery,
IQueryService.EMPTY_PARAMETERS,
IQueryService.ITEM_QUERY_MAX_PAGE_SIZE);
IRepositoryItemService repositoryItemService =
getService(IRepositoryItemService.class);
IItem[] items = repositoryItemService.fetchItems(itemQueryPage
.handlesAsArray(), null);
ArrayList<IProduct> products = new ArrayList<IProduct>();
for (IItem item : items) {
if (item instanceof IProduct) {
products.add((IProduct) item);
}
}
return (IProduct[]) products.toArray(new IProduct[products.size()]);
}