Xdoclet生成SessionBean 和 EntityBean代碼(初識ejb)
Posted on 2006-09-29 10:16 非洲小白臉 閱讀(1203) 評論(0) 編輯 收藏 所屬分類: ejbXdoclet 生成 SessionBean 和 EntityBean 代碼
xDoclet 簡介
????????????? 使用 XDoclet ,你能夠在 J2EE 環境下更加高效地工作,你所看到的 Bean 以及 Bean 之間的關系將更加簡單,許多繁雜的事情將遠離你的 EJB 開發過程。
?????? XDoclet 從 Rickard Oberg 創建的 EJBDoclet 工具發展而來,它的設想很簡單:避免為每個 EJB 提供多個文件,而是從單一 Bean 類文件中提供組件需要的所有信息。那么,這是如何實現的呢? Java 沒有 .NET 吹噓的“屬性”,但 Java 有 Javadoc 標記。我們可以把一個特殊的 @ 標記放入 Javadoc 注釋,然后讓一個 Doclet 工具處理這些標記。由工具為指定的 Bean 生成合適的 XML 描述器文件和接口文件。 XDoclet 建立在 EJBDoclet 思想的基礎上,但適用范圍不再局限于 EJB 。現在,我們已經可以用 XDoclet 生成 Web 服務、 Web 應用描述器,甚至還可以對它進行擴展,滿足自己的特殊需要。
@ 標記有一個標準的格式,包含一個“名稱空間”以及一個屬于該名稱空間的“標記名稱”。標記的屬性以“名字 = 值”的形式在標記中指定。下面是一個例子:
/**
* @namespace:tag name="value" name2="value2" ...
*/
當前可用的名稱空間包括:
ejb 標準的 EJB 信息(非廠商私有的信息)
jboss 面向 JBoss 應用服務器的信息。
weblogic 面向 BEA Weblogic 應用服務器的信息。
webSphere 面向 IBM WebSphere 應用服務器的信息。
orion 面向 Orion 應用服務器( Oracle )的信息。
castor 為 Castor 框架生成映射信息。
mvcsoft 為 MVCSoft EJB 2.0 持久化管理器生成文件。
soap 生成 SOAP 描述器。
struts 生成 struts-config.xml 。
web 為 Web 應用生成 web.xml 配置文件。
jsp 生成標記庫擴展描述器信息。
從上面的清單可以看出,除了 EJB 之外, XDoclet 還提供了許多其它方面的支持(因此它的名字也從 EJBDoclet 變成了 XDcolet )。
在 myEclipse 中的配置
?????? 以下本文使用 eclipse 結合 myeclipse 插件,進行 ejb 的開發和演示。安裝好 eclipse 和 myeclipse 以后,就可以新建項目進行 ejb project 的開發。
1.?????? 新建立 EJB Project 。
輸入工程名稱: myEJB ,注意, src 是默認的源碼輸出文件夾,因為在 myeclipse 中很多 xdoclet 配置文件的輸出文件目標路徑默認值都是該文件夾,所以建議大家不要修改這個默認值。
新建立項目后,由于目前沒有 ejb-jar.xml 的配置文件,所以會有一個 warning 信息:
這個警告信息會在 xdoclet 運行生成 ejb-jar.xml 文件后消失。
2.?????? 鼠標右鍵選擇新建的 myejb 項目,彈出窗口中選擇 properties
進入到 myeclipse-xdoclet ,準備進行項目的 xdoclet 配置
增加一個標準的配置,然后選擇 ejb 的標準配置
這個操作將生成 ejb 代碼的選項都進行默認的配置,不依賴于任何的應用程序服務器
不過我這個演示是用的 jboss 的服務器,所以還需要增加 jboss 的選項,右鍵點上圖中的 ejbdoclet 的根節點,選擇 add 來增加 ejb 的生成項目,在出現的選擇列表中,選擇 jboss
然后配置新增加的 jboss 的選項,一般來說,有如下 4 項需要填寫,見下圖標記部分:
其中,
version
表明你用的
jboss
的版本,我用的是
jboss-
第二個是你在 jboss 中配置的 datasource 的名稱
第三個是你用到的數據源映射名稱,這個名稱是不能夠任意填寫,必須按照
jboss
配置文件中填寫,配置文件在
C:\jboss-
最后一個是生成 jboss.xml 和 jbosscmp-jdbc.xml 的目標文件夾,一般生成到 src/META-INF 文件夾。
到這里, xdoclet 的配置完成,下面將創建 EntityBean 的類并根據定義的 tag 來生成代碼。
生成 EntityBean 代碼
首先創建一個 entitybean ,名稱為 User ,如下圖所示,需要注意,包名必須最后是 .ejb 結尾,否則 xdoclet 不認
創建完成后,檢查生成的代碼, User.java, 會發現在類的上方,會出現如下的 tag :
* @ejb.bean name="User"
?*?????????? display-name="Name for User"
?*?????????? description="Description for User"
?*?????????? jndi-name="ejb/User"
?*?????????? type="CMP"
?*????????? ?cmp-version="2.x"
?*?????????? view-type="both"
這些是默認生成的 tag ,不能完全的符合我們的要求,我們修改成為如下,紅色為增加的部分:
* @ejb.bean name = "User"
* ????????????????? type = "CMP"
* ????????????????? cmp-version = "2.x"
* ????????????????? display-name = "User"
* ????????????????? description = "User"
* ????????????????? view-type = "both"
* ????????????????? jndi-name = "ejb/UserHome"
* ????????????????? local-jndi-name = "ejb/UserLocalHome"
* ????????????????? primkey-field = "userId"
* @ejb.persistence table-name = "systemuser"
* @jboss.persistence table-name = "systemuser"
* @ejb:util
* generate="physical"
然后,需要為 user entity 增加它的幾個相關的方法
在相關的地方修改這個抽象的類,修改后,紅色為增加的部分:
public abstract class User implements EntityBean {
?????? /** The entity context */
?????? private EntityContext context;
?????? /**
?????? * @ejb.interface-method view-type = "both"
?????? * @ejb.persistence column-name = "userId"
?????? * @ejb.pk-field
?????? *
?????? * @return
?????? */
?????? public abstract String getUserId();
?????? /**
?????? * @ejb.interface-method view-type = "both"
?????? *
?????? * @param userId
?????? */
?????? public abstract void setUserId(String userId);
?????? /**
?????? * @ejb.interface-method view-type = "both"
?????? * @ejb.persistence column-name = "userName"
?????? *
?????? * @return
?????? */
?????? public abstract String getUserName();
?????? /**
?????? * @ejb.interface-method view-type = "both"
?????? *
?????? * @param userName
?????? */
?????? public abstract void setUserName(String userName);
?????? /**
?????? * @ejb.interface-method view-type = "both"
?????? * @ejb.persistence column-name = "Password"
?????? *
?????? * @return
?????? */
?????? public abstract String getPassword();
?????? /**
?????? * @ejb.interface-method view-type = "both"
?????? *
?????? * @param password
?????? */
?????? public abstract void setPassword(String Password);
好了, entitybean 修改成為這樣以后就可以生成相關的接口和實現類了
如果運行正常,在控制臺窗口中會出現如下提示:
Buildfile: F:\workspace\MyEJB\.xdoclet-build.tmp.xml
N65540:
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <remoteinterface/>
[ejbdoclet] Generating Remote interface for 'com.mycom.myejb.entity.ejb.User'.
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <localinterface/>
[ejbdoclet] Generating Local interface for 'com.mycom.myejb.entity.ejb.User'.
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <homeinterface/>
[ejbdoclet] Generating Home interface for 'com.mycom.myejb.entity.ejb.User'.
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <localhomeinterface/>
[ejbdoclet] Generating Local Home interface for 'com.mycom.myejb.entity.ejb.User'.
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <dataobject/>
[ejbdoclet] Generating Data Object class for 'com.mycom.myejb.entity.ejb.User'.
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <valueobject/>
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <entitypk/>
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <entitycmp/>
[ejbdoclet] Generating CMP class for 'com.mycom.myejb.entity.ejb.User'.
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <entitybmp/>
[ejbdoclet] (XDocletMain.start?? ????????????????47? ) Running <session/>
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <dao/>
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <utilobject/>
[ejbdoclet] Generating Util class for 'com.mycom.myejb.entity.ejb.User'.
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <deploymentdescriptor/>
[ejbdoclet] Generating EJB deployment descriptor (ejb-jar.xml).
[ejbdoclet] (XDocletMain.start?????????????????? 47? ) Running <jboss/>
[ejbdoclet] Generating jboss.xml.
[ejbdoclet] Generating jbosscmp-jdbc.xml.
_xdoclet_generation_:
BUILD SUCCESSFUL
Total time: 8 seconds
如果你在運行中,出現了
N65540:
BUILD FAILED
java.lang.UnsupportedClassVersionError: xjavadoc/ant/XJavadocTask (Unsupported major.minor version 49.0)
的異常,建議你更換以下
eclipse
的
jre
環境。例如當我用
jdk
生成 SessionBean 代碼
?
修改生成的類為抽象的類
public abstract class UserManager implements SessionBean {
…………….
修改 UserManager 的 xdoclet 標簽為:
* @ejb.bean name="UserManager"
?*?????????? display-name="Name for UserManager"
?*?????????? description="Description for UserManager"
?*?????????? jndi-name="ejb/UserManagerHome"
?*?????????? type="Stateless"
?*?????????? view-type="both"
下面將增加一個 login 的方法,將 UserManager.java 移動到最下方,你會發現 xdoclet 已經給你創建了一個現有的方法:
?????? /**
?????? ?* An example business method
?????? ?*
?????? ?* @ejb.interface-method view-type = "both"
?????? ?*
?????? ?* @throws EJBException Thrown if method fails due to system-level error.
?????? ?*/
?????? public void replaceWithRealBusinessMethod() throws EJBException {
????????????? // rename and start putting your business logic here
?????? }
根據你自己的需要修改這個方法,或者增加新的方法,不過一定要保留它的 ejb 的標簽
例如增加一個方法 :
?????? /**
?????? ?* @ejb.interface-method view-type = "both"
?????? ?*
?????? ?* @param username
?????? ?* @param password
?????? ?* @return
?????? ?* @throws EJBException
?????? ?*/
?????? public boolean login(String username,String password) throws EJBException {
????????????? boolean loginresult = false;
????????????? if(username.equals("
???????????????????? System.out.println(" 用戶名與密碼匹配 , 允許登錄系統 ");
???????????????????? loginresult = true;
????????????? }else{
???????????????????? System.out.println(" 用戶名與密碼不匹配 , 不登錄失敗 ");
???????????????????? loginresult = false;
????????????? }
????????????? return loginresult;
?????? }
然后再次運行 xdoclet
運行成功后會生成如下圖所示結構的代碼:
這個時候就生成了最常用的 SessionBean 的代碼。
部署 EJB 程序
1、?
部署
ejb
代碼,首先需要設置你的應用程序服務器,以下我配置了一個
jboss
的應用程序服務器。在
eclipse
的
windows
菜單下選擇
preferences
,選擇
myeclipse
選項,選擇你需要使用的服務器,并配置相關的路徑,如下圖所示:
2、? 在 Jboss 下面的進一步的選項中能夠選擇運行的模式,可以選擇 debug 模式和 run 模式,建議現在選擇 debug 模式
3、? JDK 選用你正在使用的 jdk ,點 ok 配置結束
4、?
由于發布的
jboss
的
ejb
程序需要用到
mySQL
數據庫,所以還需要配置一下
JBoss
,首先拷貝
mysql
的數據庫配置文件,從
C:\jboss-
??? <jndi-name>MyEJB</jndi-name>
??? <connection-url>jdbc:mysql://192.168.2.26:3306/MyEJB</connection-url>
??? <driver-class>com.mysql.jdbc.Driver</driver-class>
??? <user-name>root</user-name>
??? <password>root</password>
??? <connection-url>jdbc:mysql://192.168.2.26:3306/MyEJB</connection-url>
然后啟動你自己的
mysql
的數據庫,并創建
MyEJB
數據庫以及相關的
User
表。
另外,還需要將用到的數據庫連接驅動程序
mysql-connector-java-
16:48:25,078 WARN? [JBossManagedConnectionPool] Throwable while attempting to get a new connection: null
org.jboss.resource.JBossResourceException: Could not create connection;
- nested throwable: (org.jboss.resource.JBossResourceException: Failed to register driver for: com.mysql.jdbc.Driver;
- nested throwable: (java.lang.ClassNotFoundException:
No ClassLoaders found for: com.mysql.jdbc.Driver))
5、?
在
eclipse
的工具欄中找到如圖所示的一個按鈕
6、?
增加一個配置
7、?
選擇剛才配置的
jboss
服務器
8、?
選擇完成。
9、?
部署完成
10、?????????????
運行
ejb
,點擊部署旁邊的一個按鈕:
11、?????????????
Jboss
啟動過程中,可以看到,剛才寫的
ejb
部分已經發布成功。
在控制臺的啟動
log
中,你可以看到類似以下語句:
17:00:16,453 INFO? [ConnectionFactoryBindingService] Bound ConnectionManager 'jboss.jca:name=MyEJB,service=DataSourceBinding' to JNDI name 'java:MyEJB'
17:00:17,312 INFO? [EjbModule] Deploying User
17:00:17,812 INFO? [EjbModule] Deploying UserManager
17:00:18,250 INFO? [BaseLocalProxyFactory] Bound EJB LocalHome 'User' to jndi 'ejb/UserLocalHome'
17:00:18,328 INFO? [ProxyFactory] Bound EJB Home 'User' to jndi 'ejb/UserHome'
17:00:22,796 INFO? [BaseLocalProxyFactory] Bound EJB LocalHome 'UserManager' to jndi 'UserManagerLocal'
17:00:22,812 INFO? [ProxyFactory] Bound EJB Home 'UserManager' to jndi 'ejb/UserManagerHome'
17:00:22,828 INFO? [EJBDeployer] Deployed: file:/C:/jboss-
說明
entitybean
與
sessionbean
部署運行成功。
在
JBoss
的管理界面中,也可以找到如下的關于
myejb.jar
的部署說明:
測試 EJB 程序
1、?
新建一個
java project
,
project name
為
MyEJBTest
在項目的
libraries
中,將
J2EE
的包添加到項目中,另外還需要增加一個變量,如下圖所示:
然后將新增加的變量也增加到你的項目
libories
中:
2、? 在項目的構建路徑中增加對 MyEJB 項目的引用:
3、? 新建一個類 Test :
4、?
編輯生成的
Test
的類,修改后的代碼如下所示:
package com.mycompany.myejb.test;
import java.rmi.RemoteException;
import java.util.Properties;
import javax.ejb.CreateException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import com.mycom.myejb.session.interfaces.UserManager;
import com.mycom.myejb.session.interfaces.UserManagerHome;
public class Test {
?????? Properties properties;
??????
?????? public Test() {
????????????? properties = new Properties();
????????????? properties.put("java.naming.factory.initial",
????????????? "org.jnp.interfaces.NamingContextFactory");
????????????? properties.put("java.naming.factory.url.pkgs",
????????????? "org.jboss.naming:org.jnp.interfaces");
????????????? properties.put("java.naming.provider.url", "jnp://localhost:1099");
????????????? properties.put("jnp.disableDiscovery", "true");
?????? }
??????
?????? /**
?????? ?* @param args
?????? ?*/
?????? public static void main(String[] args) {
????????????? // TODO Auto-generated method stub
????????????? Test t = new Test();
????????????? System.out.println(" 登錄測試結果 :" + t.testLogin("gary", "gzllm"));
????????????? System.out.println(" 登錄測試結果 :" + t.testLogin("errorUser", "gzllm"));
?????? }
??????
?????? public boolean testLogin(String username, String password) {
????????????? boolean loginresult = false;
????????????? Context ctx;
????????????? try {
???????????????????? ctx = new InitialContext(properties);
???????????????????? Object object = ctx.lookup(UserManagerHome.JNDI_NAME);
???????????????????? UserManagerHome userManagerHome = (UserManagerHome) PortableRemoteObject
???????????????????? .narrow(object, UserManagerHome.class);
???????????????????? UserManager userManager = userManagerHome.create();
???????????????????? loginresult = userManager.login(username, password);
????????????? } catch (NamingException e) {
???????????????????? e.printStackTrace();
????????????? } catch (RemoteException e) {
???????????????????? e.printStackTrace();
????????????? } catch (CreateException e) {
???????????????????? e.printStackTrace();
????????????? }
????????????? return loginresult;
?????? }
??????
}
5、? 如上的測試程序測試部署成功的 myejb.jar 中的 login 的方法,如果輸入的用戶名與密碼為 gary/gzllm 則返回 true ,否則其他的就返回 false ,運行生成的 Test ,可以看到如下輸出結果:
整個程序測試成功。
總結與補充
1.?????? 由于 EJB 的一個最基本的設計模式 Session Fa?ade ,我并沒有在測試程序中直接調用 User 這個 entitybean ,甚至為了簡便,甚至生成了這個類以后就沒有使用它。建議在 SessionBean 中再調用 EntityBean ,也就是說,你可以在 UserManager 這個 sessionbean 中調用 User 這個 EntityBean 進行進一步的讀取數據庫,驗證輸入的用戶名稱與密碼是否和數據庫表中的數據一致,具體的訪問操作,在 EntityBean 中操作。
2.?????? Hibernate 的出現,給 ejb 的使用帶來了新的機遇,你可以生成 hibernate 的相關對象,然后在 SessionBean 的方法中不調用 EntityBean ,而是直接調用 Hibernate 的對象,進行數據庫的訪問。這將帶來更大的靈活性,并能提高程序開發的效率
3.?????? 在測試程序中,可以使用 Factory 模式,簡化 SessionBean 對象的創建,并能夠提高重用。
4.?????? xdoclet 不止能夠創建 ejb 的代碼,還能夠產生 hibernate 等很多代碼,需要進行相關的配置即可,這需要對 xdoclet 的文檔進行進一步的查看與研究,另外還能夠自定義 tag ,例如生成 javascript 的校驗代碼。 Xdoclet 是個好東西,就是用起來很復雜。
5.?????? eclipse 的 export 功能可以輸出 ant 的 build.xml 文件,不過這個配置文件很基本,你可以根據生成的 build 配置文件,進一步的擴充,使開發 - 〉測試 - 〉打包 - 〉部署自動化,能提高開發效率。