程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用Spring,JSF,EJB3設計企業應用程序

使用Spring,JSF,EJB3設計企業應用程序

編輯:關於JAVA

概述

Java EE 5.0 的核心框架是 EJB(Enterprise JavaBeans)3.0 和 JSF (JavaServerFaces)1.2 。 EJB 3.0 是一個基於 POJO(Plain Old Java Objects) 的服務端業務服務和數據庫持久化的組件模型。 JSF 是一個基於 MVC(Model- View-Controller) 的 Web 應用框架。大多數的應用都將包含有業務邏輯的 EJB3 組件和用於 Web 應用前端顯示的 JSF 組件。從表面上看,EJB3 和 JSF 互補, 但是他們是根據各自的理念設計的獨立的框架,這二者都無法獨自解決所有的計 算問題。例如,EJB3 使用注解(annotation)來配置服務,而 JSF 使用的是 XML 文件。 EJB3 和 JSF 組件在框架層面上是互不敏感,最好結合使用。但是 Java EE 5 規范並沒有提供如何整合這兩個組件模型的標准方法。要整合 EJB3 和 JSF,開發者必須手動地將業務組件(EJB) 與 Web 組件(JSF) 聯結起來,以便 能跨框架調用方法。

Spring 作為一個輕量級的容器,常被認為是 EJB 的替代品,對於很多應用情 況,采用 Spring 作為容器,並借助它對事務和 ORM 等的支持,是一種比采用 EJB 容器以實現同樣功能的另一個選擇。但也不是使用了 Spring 就不能使用 EJB 了。實際上,Spring 使得訪問和實現 EJB 更加方便。 Spring 分別提供了 集成 JSF 和 EJB 的方法。本文將使用 Eclipse 開發一個示例來演示這個過程。

示例介紹

本文的示例實現了對產品信息的增刪改查等基本操作。只用到了一個域模型: Product,下面是它的 UML 圖:

圖 1. Product 類圖

搭建開發環境

本文的開發平台采用的是 Windows Vista 操作系統,因此以下的環境設置都 是針 WindowsVista 操作系統的。

從 Java 站點 下載最新的 JDK,並安裝至任意目錄下。本文采用的是 jdk1.6.0_01 。

從 Eclipse 站點 下載 Eclipse for Java EE Developers 3.4 或更新版本, 解壓至任意目錄。本文采用的是 eclipse3.4.1 。

從 JBoss 站點 下載 Jboss Application Server 4.2 或更新版本,解壓至任 意目錄。本文采用的是 jboss-4.2.2.GA 。

從 Spring 站點 下載 Spring Framework 2.5 或更新版本,解壓至任意目錄 。本文采用的是 spring-framework-2.5.4 。

創建 EAR Application Project

設置 JRE,這一步在 JBoss 運行時需要。依次打開 Windows > Preferences > Java > Installed JRES,確保選中的 JRE 的 Locaton 為 JDK 的安裝目錄。本文 JDK 安裝目錄為 C:\soft\Java\jdk1.6.0_01 。

圖 2. 設置 JDK

設置 Server Runtime Environments,這一步配置應用程序的運行環境。依次 打開 Windows > Preferences > Server > Runtime Environments,點 擊 Add 按鈕,選擇 JBoss > JBoss v4.2,點擊 Next 。 JRE 選擇第一步中 設置的 JRE,本文中為 jdk1.6.0_01,Application Server Directory 選擇 [Jboss 安裝目錄 ]/ server/default 。點擊完成按鈕。如下圖:

圖 3. 配置運行環境

新建名稱為 simple 的 EAR Application Project,這個工程包括 3 個工程 ,分別是 JPA Project、EJB Project、WEB Project,以下步驟將分別介紹這三 個工程。 Target Runtime 為 JBoss v4.2,EAR version 為 5.0, Configuration 為 Default Configuration for JBoss v4.2 。如下圖:

圖 4. 創建 EAR 工程項目

點擊 Next 選擇 Generate Deployment Descriptor,點擊完成。

開發 JPA Project

新建名稱為 simpleJPA 的 JPA 工程,Configuration 為 Default Configuration for JBoss v4.2,選中 Add project to anEAR,如下圖:

圖 5. 創建 JPA 項目

點擊 Next,選擇默認,點擊完成。

編輯 JPA persistence.xml 文件,內容如下:

清單 1. JPA persistence.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
  xmlns="http://java.sun.com/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
  http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="simpleJPA">
   <!-- 使用JBoss默認的數據源 -->
   <jta-data-source>java:/DefaultDS</jta-data-source>
   <properties>
    <!-- 使用Hibernate的hbm2ddl工具在啟動時生成表結構 -->
    <property name="hibernate.hbm2ddl.auto"  value="update"/>
    <!-- 顯示最終執行的SQL -->
    <property name="hibernate.show_sql" value="true" />
    <!-- 格式化顯示的SQL -->
    <property name="hibernate.format_sql" value="true" />
   </properties>
  </persistence-unit>
</persistence>

persistence-unit 節點可以有一個或多個,每個 persistence-unit 節點定 義了持久化內容名稱、使用的數據源及持久化產品專有屬性。 name 屬性定義了 persistence-unit 的名稱,該屬性是必需的,本例設置的名稱為“ simpleJPA ”。

在 JavaEE 環境中的默認的事務是 JTA,而在 JavaSE 環境中則為 RESOURCE_LOCAL 。使用 <jta-data-source> 指定數據源的 JNDI 名稱。 Jboss 數據源的 JNDI 名稱在局部命名空間,因此數據源名稱前必須帶有 java:/ 前綴,數據源名稱大小寫敏感。在本文中采用 JBoss 容器中默認的數據源,JNDI 為 java:/DefaultDS,詳情請查看:[Jboss 安裝目 錄]/server/default/deployhsqldb-ds.xml。

<properties> 指定持久化產品的專有屬性,各個應用服務器使用的持 久化產品都不一樣,如 Jboss 使用 Hibernate,weblogic 使用 Kodo(實際上是 基於 OpenJPA 的封裝),glassfish/sun application server/Oralce 使用 Toplink 。對於 Hibernate 而言,它的 hibernate.hbm2ddl.auto 屬性指定實體 Bean 發布時是否同步數據庫結構, 如果 hibernate.hbm2ddl.auto 的值設為 create-drop,實體 Bean 發布及卸載時將自動創建及刪除相應數據庫表(注意: Jboss 服務器啟動或關閉時也會引發實體 Bean 的發布及卸載)。 TopLink 產品 的 toplink.ddl-generation 屬性也起到同樣的作用。關於 Hibernate 的可用屬 性及默認值您可以在 [Jboss 安裝目錄] \server\default\deploy\ejb3.deployer\META-INF/persistence.properties 文 件中找到。在開發階段,Hibernate 的 hibernate.show_sql 和 hibernate.format_sql 屬性特別有用,它們可以格式化顯示 Hibernate 執行的 SQL 語句。

新建名稱為 org.zhouxing.simple.Product 的 Entity class, 根據示例介紹 小節中的 UML 類圖添加 Entity Fields,如下圖:

圖 6. 新建 Entity class

id 為主鍵,在 EJB3.0 中,每個實體 Bean 必須具有一個主鍵,主鍵可以是 基本類型,也可以是一個類。主鍵既作為實體 Bean 在內存中的標識符,也作為 數據表中一行的標識符。它在實體 Bean 中是不可缺少的,並且必須是唯一的

表名為 product。實體 Bean 的成員屬性分別映射到 product 表的對應字段 。

修改主鍵的生成方式為自增,給主鍵添加如下代碼: @GeneratedValue(strategy = GenerationType.AUTO)

@javax.persistence.GeneratedValue 注釋指定主鍵值生成方式,該注釋與 @Id 注釋結合使用在主鍵屬性上。只有在使用持久化驅動生成數據表 schema 時 才需指定該注釋。如果您的數據表已經存在,那麼該注釋不需要指定。 strategy() 屬性指定字段值生成策略。 GenerationType.AUTO:由容器根據數據 庫類型選擇一種合適的生成方式,這種方式帶有隨機性,不同的 JPA 實現產品的 做法各有不同 (JBoss 將 JPA 實現為 Hibernate),對於本文而言,Hibernate 知道 HSQL 支持 ID 自增長,所以會選擇 GenerationType.IDENTITY。

清單 2. 修改之後的代碼

package org.zhouxing.simple;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
Entity implementation class for Entity: Product 
*/
@Entity
@Table(name = "product")
public class Product implements Serializable {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private long id;
   private String name;
   private String description;
   private Double price;
   private Integer inventory;

   public Product() {
     super();
   }
   ...setters,getters 方法省略
}

@javax.persistence.Entity 注釋指明這是一個實體 Bean,name() 屬性指定 實體 bean 的名稱,在本文中沒有為該屬性提供取值,默認值為 bean class 的 非限定類名。 @javax.persistence.Table 注釋指定了實體 Bean 所要映射的表 ,name() 屬性指定映射表的名稱。如果缺省 @Table 注釋,系統默認采用實體名 稱作為映射表的名稱。在本文中采用的表名為product 。

至此 JPA Project 完成,接下來是 EJB Project 。

開發 EJB Project

新建名稱為 simpleEJB 的 EJB 工程,EJB Module version 為 3.0, Configuration 為 Default Configuration for JBoss v4.2,選中 Add project to anEAR,如下圖:

圖 7. 新建 EJB 工程

點擊 Next,取消選擇 Create an EJB Clicent JAR,點擊完成。

新建名稱為 org.zhouxing.simple. ProductDAOBean 的 Session Bean,如下 圖:

圖 8. 新建 Session Bean

選擇生成 Local 和 Remote 接口。

同時實現 Remote 與 Local 接口是一種比較好的做法。這樣您既可以在遠程 訪問 EJB,也可以在本地訪問 EJB 。在本地接口中寫出業務方法,遠程接口繼承 本地接口的所有方法。代碼如下:

清單 3. Remote 與 Local 接口

本地接口:
package org.zhouxing.simple;
import java.util.List;

/**
本地接口
*
@author 周行
*/
public interface ProductDAOLocal {
   /**
   查詢所有的 Product 
   @return
   */
   public List<Product> findAll();
   /**
   添加 Product 
   @param product 
   */
   public void add(Product product);
}


遠程接口:
package org.zhouxing.simple;

/**
遠程接口
@author 周行
*/

public interface ProductDAORemote extends ProductDAOLocal {

}



無狀態會話 BEAN
package org.zhouxing.simple;

import java.util.List;

import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
無狀態會話 BEAN
*
@author 周行
*/
@Stateless
@Remote(ProductDAORemote.class)
@Local(ProductDAOLocal.class)
public class ProductDAOBean implements ProductDAORemote,
   ProductDAOLocal {
   /**
   注入 EntityManager
   */
   @PersistenceContext(unitName = "simpleJPA")
   protected EntityManager em;

   /**
   Default constructor.
   */
   public ProductDAOBean() {

   }

   @Override
   public void add(Product product) {
     em.persist(product);
   }

   @SuppressWarnings("unchecked")
   @Override
   public List<Product> findAll() {
     Query query = em.createQuery("select o from  Product o");
     return query.getResultList();
   }

}

@Stateless 注釋指明這是一個無狀態會話 Bean,@Remote 注釋指定這個無狀 態 Bean 的 remote 接口。 Bean 類可以具有多個 remote 接口,每個接口之間 用逗號分隔,如:@Remote ({ProductDAORemote.class,ProductDAORemote2.class,ProductDAORemote3.clas s}) 。如果您只有一個接口,您可以省略大括號,對於本文而言,可以寫成這樣 :@Remote (ProductDAORemote.class) 。 @Local 注釋指定這個無狀態 Bean 的 local 接口,和 @Remote 注釋一樣,@Local 注釋也可以定義多個本地接口。

當 @Local 和 @Remote 注釋都不存在時,容器會將 Bean class 實現的接口 默認為 Local 接口。如果 EJB 與客戶端部署在同一個應用服務器,采用 Local 接口訪問 EJB 優於 Remote 接口。因為通過 Remote 接口訪問 EJB 需要在 TCP/IP 協議基礎上轉換和解釋 Corba IIOP 協議消息,在調用 EJB 的這一過程 中存在對象序列化、協議解釋、TCP/IP 通信等開銷。而通過 Local 接口訪問 EJB 是在內存中與 Bean 彼此交互的,沒有了分布式對象協議的開銷,大大提高 了性能。

@PersistenceContext 注釋動態注入 EntityManager 對象。在 EJB 的 JNDI ENC 中注冊一個指向該資源的引用。 EntityManager 是由 EJB 容器自動管理和 配置的,這包括 EntityManager 的創

建及清理工作。所以我們不需要調用它的 close() 方法釋放資源, 如果您試 圖這樣做, 反而會得到 IllegalStateException 例外。借助 EntityManager, 我們可以創建、更新、刪除及查詢實體 bean 。 EntityManager 負責將固定數量 的一組類映射到數據庫中,這組類被稱作持久化單元 (persistence unit) 。 persistence unit 是在 persistence.xml 中定義的。根據持久化規范的要求, 該部署描述文件是必須提供的,如果不提供這一文件,則持久化單元也將不存在 ,因此應用也不能夠獲得和使用 EntityManager 。本文的持久化單元為 simpleJPA 。

至此 EJB Project 開發完畢,接下來是 WEB Project 。

開發 WEB Project

WEB Project 是本文的重點,在這小節中我們將用 JSF 通過 Spring 來調用 EJB,體驗 Spring 的便利。

新建名稱為 simpleWEB 的 Dynamic WEB Project,Dynamic WEB Project version 為 2.5,Configuration 為 JavaServer Faces v1.1 Project,選中 Add project to anEAR,如下圖:

圖 9. 新建 Web 項目

點擊 Next,默認下一步,JSF Libraries 選擇 Server Supplied JSF Implementation,修改 URL Mapping Patterns 為 *.jsf,如下圖:

圖 10. 配置項目對 JSF 的支持

所有以 *.jsf 結尾的請求都有 JSF 處理。

配置 WEB Project 。

拷貝 SPRING_HOME/dist/spring.jar 到 WebContent/WEB-INF/lib 目錄。在 WebContent/WEB-INF 下新建 spring 配置文件 applicationContext.xml 。

一個 Spring 為框架的 Web 項目,通常以 web.xml 為入口,在 Web 應用啟 動時,讀入 context-param 中批量的配置文件,初始化配置文件裡所定義的 Bean,通過ContextLoaderListener在 web 應用程序的 servlet context 建立後 立即執行建立 Spring 的ApplicationContext。

編輯 web.xml

添加 ContextParam:

<context-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>/WEB-INF/applicationContext.xml</param- value>
</context-param>

添加 Spring listener:

<listener>
   <listener-class>
   org.springframework.web.context.ContextLoaderListener
   </listener-class>
</listener>

編輯 applicationContext.xml,內容如下:

清單 4. applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jee="http://www.springframework.org/schema/jee"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans- 2.5.xsd
  http://www.springframework.org/schema/jee
  http://www.springframework.org/schema/jee/spring-jee- 2.5.xsd">

  <jee:jndi-lookup id="productDAO" jndi- name="simple/ProductDAOBean/remote"
  proxy- interface="org.zhouxing.simple.ProductDAORemote" />
  </beans>

Spring 通過 jndi-lookup 來訪問 EJB,以後就可以在本地 EJB 組件,遠程 EJB 或者 POJO 這些變體之間透明地切換實現方式,而不需要改變客戶端的代碼 。

新建名稱為 org.zhouxing.simple.ProductBean 的一個類作為 JSF 的 managed Bean 。 JSF 使用 JavaBean 來達到程序邏輯與視圖分離的目的,在 JSF 中的 Bean 其角色是屬於 Backing Bean,又稱之為 Glue Bean,其作用是在 真正的業務邏輯 Bean 及 UI 組件之間搭起橋梁,在 Backing Bean 中會呼叫業 務邏輯 Bean 處理使用者的請求,或者是將業務處理結果放置其中,等待 UI 組 件取出當中的值並顯示結果給使用者。

主要有兩個方法實現業務功能,代碼如下:

清單 5. 業務功能代碼

package org.zhouxing.simple;

import java.util.List;

/**
JSF Managed Bean 實現 Product 的查詢,添加
@author 周行
*
*/
public class ProductBean {
   private ProductDAORemote productDAO;
   private Product product;

   public ProductBean() {
     product = new Product();
   }

   public void setProductDAO(ProductDAORemote productDAO)  {
     this.productDAO = productDAO;
   }

   public String add() {
     productDAO.add(product);
     return "";
   }

   public List<Product> getProducts() {
     return productDAO.findAll();
   }

   public Product getProduct() {
     return product;
   }
}

屬性 productDAO 通過 JSF 配置文件用 Spring 注入,屬性 product 為簡單 起見作為表單 Form 。

在 JSF 中使用 Spring 的注入功能需要在 JSF 配置文件中使用 Spring 的變 量解析器 DelegatingVariableResolver 類。 DelegatingVariableResolver 類 首先會查詢請求委派到 JSF 實現的默認的解析器中,然後才是 Spring 的“ business context ”。代碼片段如下:

清單 6. 在 faces-config.xml 文件中指定使用 Spring 變量解析器

<application>
    <variable-resolver>
      org.springframework.web.jsf.DelegatingVariableResolver
    </variable-resolver>
    <locale-config>
      <default-locale>en</default-locale>
    </locale-config>
  </application>

在 JSF 配置文件中配置 Managed Bean,代碼片段如下:

清單 7. 配置 Managed Bean

<managed-bean>
   <managed-bean-name>productBean</managed-bean-name>
   <managed-bean- class>org.zhouxing.simple.ProductBean</managed-bean-class>
   <managed-bean-scope>session</managed-bean-scope>
   <managed-property>
     <property-name>productDAO</property-name>
     <value>#{productDAO}</value>
   </managed-property>
</managed-bean>

#{productDAO} 表達式將通過 Spring 注入。

在 JSF 配置文件中配置 navigation Rule,請求轉向 index.jsp 。代碼片段 如下:

清單 8. 配置 navigation Rule

<navigation-rule>
   <navigation-case>
     <to-view-id>/index.jsp</to-view-id>
   </navigation-case>
</navigation-rule>

創建 index.jsp,頁面顯示表單和查詢結果。代碼片段如下:

清單 9. 創建 index.jsp

<f:view>
   <h:form>
     名稱 <h:inputText value="# {productBean.product.name}"/><p>
     存貨 <h:inputText value="# {productBean.product.inventory}"/><p>
     單價 <h:inputText value="# {productBean.product.price}"/><p>
     描述 <h:inputTextarea value="# {productBean.product.description}"/>
     <h:commandButton value=" 添加 " action="#{productBean.add}"  />
   </h:form>

   <h:dataTable var="entry" value="#{productBean.products}"
     rendered="true">
     <h:column>
       <h:outputLabel value="#{entry.name}"/>
     </h:column>
     <h:column>
       <h:outputLabel value="#{entry.inventory}"/>
     </h:column>
     <h:column>
       <h:outputLabel value="#{entry.price}"/>
     </h:column>
     <h:column>
       <h:outputLabel value="#{entry.description}"/>
     </h:column>
   </h:dataTable>
</f:view>

JSF 組件必須在 <f:view> 之間,<h:form> 會產生一個表單, <h: inputText> 來顯示 product 對象的各個屬性, <h:commandButton> 會產生一個提交按鈕,調用 productBean 的 add 方 法處理。<h:dataTable> 調用 productBean 的 getProducts 方法迭代所 有 product 的信息。

部署應用程序

現在該看看 simple 的運行效果了。可以導出 EAR 文件拷貝到 [Jboss 安裝 目錄 ]\server\default 下,也可以用 Eclipse 的運行工具,下面介紹借助 Eclipse 運行應用程序。確保您的 simple 工程下的 META-INF/application.xml 文件內容包含以上開發的 3 個工程,代碼如下:

清單 10. application.xml

<?xml version="1.0" encoding="UTF-8"?>
<application
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:application="http://java.sun.com/xml/ns/javaee/application_5.xsd"
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
   http://java.sun.com/xml/ns/javaee/application_5.xsd"
   id="Application_ID" version="5">
   <display-name>simple</display-name>
   <module>
     <web>
       <web-uri>simpleWEB.war</web-uri>
       <context-root>simpleWEB</context-root>
     </web>
   </module>
   <module>
     <ejb>simpleEJB.jar</ejb>
   </module>
   <module>
     <ejb>simpleJPA.jar</ejb>
   </module>
</application>

右擊 simple 工程選擇 Run as > Run on Server 。

在 server type 選項中選擇 JBoss > JBoss v4.2, 點擊 Next,默認,點 擊 Next 完成。服務器將啟動並部署應用程序。

打開 Web 浏覽器,並訪問 http://localhost:8080/simpleWEB/。

總結

Spring 帶來的解決方法是我們的代碼更簡潔更易擴展,不僅僅是 JSF 和 EJB ,對 JDBC、Java mail、JCA 及一些開源框架都提供了很多便利。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved