Wire everything up
由于篇幅所限,我们仅举例说明,范例中use case CreateProduct展示了如何装配和构建应用,在详细讲述细节前,我们利用sequence图(图7)来说明所有层的end-tp-end整合。
表示层
表示层实现包括创建JSP页面、定义页导航、创建和配置backing bean以及将JSF与业务逻辑层整合。
◆JSP page:createProduct.jsp是用来创建新产品的页面,它包含UI组件并将组件打包成ProductBean,ValidateItemsRange标签用来验证用户选择的种类数量,对每一个产品至少要有一个种类被选中。
◆页面导航:应用中的导航被定义在应用的配置文件faces-navigation.xml中,CreateProduct的导航准则如下:
* createProduct /createProduct.jsp
/createProduct.jsp
success /uploadImage.jsp
retry /createProduct.jsp
cancel /productList.jsp
|
◆Backing bean:ProductBean不仅包含有将数据映射到页面上的UI组件的属性,还包括三个action:createAction、editAction和deleteAction,下面是createAction方法的代码:
public String createAction() { try { Product product = ProductBeanBuilder.createProduct(this); //Save the product. this.serviceLocator.getCatalogService().saveProduct(product); //Store the current product id inside the session bean. //For the use of image uploader. FacesUtils.getSessionBean().setCurrentProductId(this.id); //Remove the productList inside the cache. this.logger.debug("remove ProductListBean from cache"); FacesUtils.resetManagedBean(BeanNames.PRODUCT_LIST_BEAN); } catch (DuplicateProductIdException de) { String msg = "Product id already exists"; this.logger.info(msg); FacesUtils.addErrorMessage(msg); return NavigationResults.RETRY; } catch (Exception e) { String msg = "Could not save product"; this.logger.error(msg, e); FacesUtils.addErrorMessage(msg + ": Internal Error"); return NavigationResults.FAILURE; } String msg = "Product with id of " + this.id + " was created successfully."; this.logger.debug(msg); FacesUtils.addInfoMessage(msg); return NavigationResults.SUCCESS; }
|
◆Managed-bean声明:ProductBean必须在JSF配置文件faces-managed-bean.xml中配置:
Backing bean that contains product information. productBean catalog.view.bean.ProductBean request id #{param.productId}
serviceLocator #{serviceLocatorBean}
|
◆表示层和业务逻辑层之间的整合: ServiceLocator抽象了查找服务的逻辑,在范例应用中,ServiceLocator被定义为一个接口,该接口实现为一个JSF的 managed bean,即ServiceLocatorBean,它将在Spring的application context中寻找服务:
ServletContext context = FacesUtils.getServletContext(); this.appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context); this.catalogService = (CatalogService)this.lookupService(CATALOG_SERVICE_BEAN_NAME); this.userService = (UserService)this.lookupService(USER_SERVICE_BEAN_NAME);
|
业务逻辑层
◆业务对象:由于采用Hibernate提供持久化,因此Product和Category两个业务对象需要为它们的所有field提供getter和setter。
◆业务服务:CatalogService接口中定义了所有的与Catalog management相关的服务:
public interface CatalogService { public Product saveProduct(Product product) throws CatalogException; public void updateProduct(Product product) throws CatalogException; public void deleteProduct(Product product) throws CatalogException; public Product getProduct(String productId) throws CatalogException; public Category getCategory(String categoryId) throws CatalogException; public List getAllProducts() throws CatalogException; public List getAllCategories() throws CatalogException; }
|
◆Spring Configuration:这里是CatalogService的Spring配置:
PROPAGATION_REQUIRED,readOnly PROPAGATION_REQUIRED PROPAGATION_REQUIRED PROPAGATION_REQUIRED
|
◆Spring和Hibernate的整合:下面是HibernateSessionFactory的配置:
<!-- Hibernate SessionFactory Definition --> <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean"> <property name="mappingResources"> <list> <value>catalog/model/businessobject/Product.hbm.xml</value> <value>catalog/model/businessobject/Category.hbm.xml</value> <value>catalog/model/businessobject/User.hbm.xml</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cglib.use_reflection_optimizer">true</prop> <prop key="hibernate.cache.provider_class">net.sf.hibernate.cache.HashtableCacheProvider</prop> </props> </property> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> CatalogDao uses HibernateTemplate to integrate between Hibernate and Spring. Here's the configuration for HibernateTemplate: <!-- Hibernate Template Defintion --> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate.HibernateTemplate"> <property name="sessionFactory"><ref bean="sessionFactory"/></property> <property name="jdbcExceptionTranslator"><ref bean="jdbcExceptionTranslator"/></property> </bean>
|
Integration层
Hibernate通过xml配置文件来映射业务对象和关系数据库,在JCatalog中,Product.hbm.xml表示了Product对象的映射,Category.hbm.xml则用来表示Category的映射,Product.hbm.xml如下:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping package="catalog.model.businessobject"> <class name="Product" table="product"> <id name="id" column="ID" unsaved-value="null"> <generator class="assigned"/> </id> <property name="name" column="NAME" unique="true" not-null="true"/> <property name="price" column="PRICE"/> <property name="width" column="WIDTH"/> <property name="height" column="height"/> <property name="description" column="description"/> <set name="categoryIds" table="product_category" cascade="all"> <key column="PRODUCT_ID"/> <element column="CATEGORY_ID" type="string"/> </set> </class> </hibernate-mapping> CatalogDao is wired with HibernateTemplate by Spring: <!-- Catalog DAO Definition: Hibernate implementation --> <bean id="catalogDao" class="catalog.model.dao.hibernate.CatalogDaoHibernateImpl"> <property name="hibernateTemplate"><ref bean="hibernateTemplate"/></property> </bean>
|
结论
本文主要讲述了如何将JSF与Spring、Hibernate整合在一起来构建实际的Web应用,这三种技术的组合提供了一个强大的Web应用开发框架。在Web应用的高层设计中应该采用多层构架体系,JSF非常适合MVC设计模式以实现表示层,Spring可用在业务逻辑层中管理业务对象,并提供事物管理和资源管理等,Spring与Hibernate结合的非常出色,Hibernate是强大的O/R映射框架,它可以在integration层中提供最好的服务。
通过将整个Web应用分割成多层,并借助于“编程到接口”,应用程序的每一层所采用的技术都是可替换,例如Struts可以用来替换JSF,JDO可替换Hibernate。各层之间的整合不是不值得研究,采用IoC和ServiceLocator设计模式可使得整合非常容易。JSF提供了其它Web框架欠缺的功能,然而,这并不意味着你马上抛弃Struts而开始使用JSF,是否采用JSF取决于项目目前的状况和功能需求,以及开发团队的意见等。
(责任编辑 火凤凰 sunsj@51cto.com TEL:(010)68476636-8007)