source 
            code
 
 数据库设计
            
            我们为该范例应用创建了包含4个表的数据库,如图5所示:
 
            
 类设计
            
            图6显示了JCatalog的类图
 
            
            “编程到接口”的思想贯穿了整个设计实现中,在表示层,共用到四个backing bean:ProductBean、ProductListBean、UserBean和MessageBean;业务逻辑层包含两个业务服务 
            (CatalogService和UserService)和三个业务对象(Product、Category和User);Integration层有两个Dao接口和它们相应的Hibernate实现,Spring的application 
            context用来管理绝大多数的业务逻辑层和integration层的对象;ServiceLocator将JSF和业务逻辑层整合在了一起。
 
            
 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取决于项目目前的状况和功能需求,以及开发团队的意见等。