Xdoclet生成SessionBean 和 EntityBean代碼(初識(shí)ejb)
Posted on 2006-09-29 10:16 非洲小白臉 閱讀(1204) 評(píng)論(0) 編輯 收藏 所屬分類: ejbXdoclet 生成 SessionBean 和 EntityBean 代碼
xDoclet 簡介
????????????? 使用 XDoclet ,你能夠在 J2EE 環(huán)境下更加高效地工作,你所看到的 Bean 以及 Bean 之間的關(guān)系將更加簡單,許多繁雜的事情將遠(yuǎn)離你的 EJB 開發(fā)過程。
?????? XDoclet 從 Rickard Oberg 創(chuàng)建的 EJBDoclet 工具發(fā)展而來,它的設(shè)想很簡單:避免為每個(gè) EJB 提供多個(gè)文件,而是從單一 Bean 類文件中提供組件需要的所有信息。那么,這是如何實(shí)現(xiàn)的呢? Java 沒有 .NET 吹噓的“屬性”,但 Java 有 Javadoc 標(biāo)記。我們可以把一個(gè)特殊的 @ 標(biāo)記放入 Javadoc 注釋,然后讓一個(gè) Doclet 工具處理這些標(biāo)記。由工具為指定的 Bean 生成合適的 XML 描述器文件和接口文件。 XDoclet 建立在 EJBDoclet 思想的基礎(chǔ)上,但適用范圍不再局限于 EJB ?,F(xiàn)在,我們已經(jīng)可以用 XDoclet 生成 Web 服務(wù)、 Web 應(yīng)用描述器,甚至還可以對(duì)它進(jìn)行擴(kuò)展,滿足自己的特殊需要。
@ 標(biāo)記有一個(gè)標(biāo)準(zhǔn)的格式,包含一個(gè)“名稱空間”以及一個(gè)屬于該名稱空間的“標(biāo)記名稱”。標(biāo)記的屬性以“名字 = 值”的形式在標(biāo)記中指定。下面是一個(gè)例子:
/**
* @namespace:tag name="value" name2="value2" ...
*/
當(dāng)前可用的名稱空間包括:
ejb 標(biāo)準(zhǔn)的 EJB 信息(非廠商私有的信息)
jboss 面向 JBoss 應(yīng)用服務(wù)器的信息。
weblogic 面向 BEA Weblogic 應(yīng)用服務(wù)器的信息。
webSphere 面向 IBM WebSphere 應(yīng)用服務(wù)器的信息。
orion 面向 Orion 應(yīng)用服務(wù)器( Oracle )的信息。
castor 為 Castor 框架生成映射信息。
mvcsoft 為 MVCSoft EJB 2.0 持久化管理器生成文件。
soap 生成 SOAP 描述器。
struts 生成 struts-config.xml 。
web 為 Web 應(yīng)用生成 web.xml 配置文件。
jsp 生成標(biāo)記庫擴(kuò)展描述器信息。
從上面的清單可以看出,除了 EJB 之外, XDoclet 還提供了許多其它方面的支持(因此它的名字也從 EJBDoclet 變成了 XDcolet )。
在 myEclipse 中的配置
?????? 以下本文使用 eclipse 結(jié)合 myeclipse 插件,進(jìn)行 ejb 的開發(fā)和演示。安裝好 eclipse 和 myeclipse 以后,就可以新建項(xiàng)目進(jìn)行 ejb project 的開發(fā)。
1.?????? 新建立 EJB Project 。
輸入工程名稱: myEJB ,注意, src 是默認(rèn)的源碼輸出文件夾,因?yàn)樵?/span> myeclipse 中很多 xdoclet 配置文件的輸出文件目標(biāo)路徑默認(rèn)值都是該文件夾,所以建議大家不要修改這個(gè)默認(rèn)值。
新建立項(xiàng)目后,由于目前沒有 ejb-jar.xml 的配置文件,所以會(huì)有一個(gè) warning 信息:
這個(gè)警告信息會(huì)在 xdoclet 運(yùn)行生成 ejb-jar.xml 文件后消失。
2.?????? 鼠標(biāo)右鍵選擇新建的 myejb 項(xiàng)目,彈出窗口中選擇 properties
進(jìn)入到 myeclipse-xdoclet ,準(zhǔn)備進(jìn)行項(xiàng)目的 xdoclet 配置
增加一個(gè)標(biāo)準(zhǔn)的配置,然后選擇 ejb 的標(biāo)準(zhǔn)配置
這個(gè)操作將生成 ejb 代碼的選項(xiàng)都進(jìn)行默認(rèn)的配置,不依賴于任何的應(yīng)用程序服務(wù)器
不過我這個(gè)演示是用的 jboss 的服務(wù)器,所以還需要增加 jboss 的選項(xiàng),右鍵點(diǎn)上圖中的 ejbdoclet 的根節(jié)點(diǎn),選擇 add 來增加 ejb 的生成項(xiàng)目,在出現(xiàn)的選擇列表中,選擇 jboss
然后配置新增加的 jboss 的選項(xiàng),一般來說,有如下 4 項(xiàng)需要填寫,見下圖標(biāo)記部分:
其中,
version
表明你用的
jboss
的版本,我用的是
jboss-
第二個(gè)是你在 jboss 中配置的 datasource 的名稱
第三個(gè)是你用到的數(shù)據(jù)源映射名稱,這個(gè)名稱是不能夠任意填寫,必須按照
jboss
配置文件中填寫,配置文件在
C:\jboss-
最后一個(gè)是生成 jboss.xml 和 jbosscmp-jdbc.xml 的目標(biāo)文件夾,一般生成到 src/META-INF 文件夾。
到這里, xdoclet 的配置完成,下面將創(chuàng)建 EntityBean 的類并根據(jù)定義的 tag 來生成代碼。
生成 EntityBean 代碼
首先創(chuàng)建一個(gè) entitybean ,名稱為 User ,如下圖所示,需要注意,包名必須最后是 .ejb 結(jié)尾,否則 xdoclet 不認(rèn)
創(chuàng)建完成后,檢查生成的代碼, User.java, 會(huì)發(fā)現(xiàn)在類的上方,會(huì)出現(xiàn)如下的 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"
這些是默認(rèn)生成的 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 增加它的幾個(gè)相關(guān)的方法
在相關(guān)的地方修改這個(gè)抽象的類,修改后,紅色為增加的部分:
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 修改成為這樣以后就可以生成相關(guān)的接口和實(shí)現(xiàn)類了
如果運(yùn)行正常,在控制臺(tái)窗口中會(huì)出現(xiàn)如下提示:
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
如果你在運(yùn)行中,出現(xiàn)了
N65540:
BUILD FAILED
java.lang.UnsupportedClassVersionError: xjavadoc/ant/XJavadocTask (Unsupported major.minor version 49.0)
的異常,建議你更換以下
eclipse
的
jre
環(huán)境。例如當(dāng)我用
jdk
生成 SessionBean 代碼
?
修改生成的類為抽象的類
public abstract class UserManager implements SessionBean {
…………….
修改 UserManager 的 xdoclet 標(biāo)簽為:
* @ejb.bean name="UserManager"
?*?????????? display-name="Name for UserManager"
?*?????????? description="Description for UserManager"
?*?????????? jndi-name="ejb/UserManagerHome"
?*?????????? type="Stateless"
?*?????????? view-type="both"
下面將增加一個(gè) login 的方法,將 UserManager.java 移動(dòng)到最下方,你會(huì)發(fā)現(xiàn) xdoclet 已經(jīng)給你創(chuàng)建了一個(gè)現(xiàn)有的方法:
?????? /**
?????? ?* 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
?????? }
根據(jù)你自己的需要修改這個(gè)方法,或者增加新的方法,不過一定要保留它的 ejb 的標(biāo)簽
例如增加一個(gè)方法 :
?????? /**
?????? ?* @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(" 用戶名與密碼匹配 , 允許登錄系統(tǒng) ");
???????????????????? loginresult = true;
????????????? }else{
???????????????????? System.out.println(" 用戶名與密碼不匹配 , 不登錄失敗 ");
???????????????????? loginresult = false;
????????????? }
????????????? return loginresult;
?????? }
然后再次運(yùn)行 xdoclet
運(yùn)行成功后會(huì)生成如下圖所示結(jié)構(gòu)的代碼:
這個(gè)時(shí)候就生成了最常用的 SessionBean 的代碼。
部署 EJB 程序
1、?
部署
ejb
代碼,首先需要設(shè)置你的應(yīng)用程序服務(wù)器,以下我配置了一個(gè)
jboss
的應(yīng)用程序服務(wù)器。在
eclipse
的
windows
菜單下選擇
preferences
,選擇
myeclipse
選項(xiàng),選擇你需要使用的服務(wù)器,并配置相關(guān)的路徑,如下圖所示:
2、? 在 Jboss 下面的進(jìn)一步的選項(xiàng)中能夠選擇運(yùn)行的模式,可以選擇 debug 模式和 run 模式,建議現(xiàn)在選擇 debug 模式
3、? JDK 選用你正在使用的 jdk ,點(diǎn) ok 配置結(jié)束
4、?
由于發(fā)布的
jboss
的
ejb
程序需要用到
mySQL
數(shù)據(jù)庫,所以還需要配置一下
JBoss
,首先拷貝
mysql
的數(shù)據(jù)庫配置文件,從
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>
然后啟動(dòng)你自己的
mysql
的數(shù)據(jù)庫,并創(chuàng)建
MyEJB
數(shù)據(jù)庫以及相關(guān)的
User
表。
另外,還需要將用到的數(shù)據(jù)庫連接驅(qū)動(dòng)程序
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
的工具欄中找到如圖所示的一個(gè)按鈕
6、?
增加一個(gè)配置
7、?
選擇剛才配置的
jboss
服務(wù)器
8、?
選擇完成。
9、?
部署完成
10、?????????????
運(yùn)行
ejb
,點(diǎn)擊部署旁邊的一個(gè)按鈕:
11、?????????????
Jboss
啟動(dòng)過程中,可以看到,剛才寫的
ejb
部分已經(jīng)發(fā)布成功。
在控制臺(tái)的啟動(dòng)
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
部署運(yùn)行成功。
在
JBoss
的管理界面中,也可以找到如下的關(guān)于
myejb.jar
的部署說明:
測試 EJB 程序
1、?
新建一個(gè)
java project
,
project name
為
MyEJBTest
在項(xiàng)目的
libraries
中,將
J2EE
的包添加到項(xiàng)目中,另外還需要增加一個(gè)變量,如下圖所示:
然后將新增加的變量也增加到你的項(xiàng)目
libories
中:
2、? 在項(xiàng)目的構(gòu)建路徑中增加對(duì) MyEJB 項(xiàng)目的引用:
3、? 新建一個(gè)類 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(" 登錄測試結(jié)果 :" + t.testLogin("gary", "gzllm"));
????????????? System.out.println(" 登錄測試結(jié)果 :" + 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 ,運(yùn)行生成的 Test ,可以看到如下輸出結(jié)果:
整個(gè)程序測試成功。
總結(jié)與補(bǔ)充
1.?????? 由于 EJB 的一個(gè)最基本的設(shè)計(jì)模式 Session Fa?ade ,我并沒有在測試程序中直接調(diào)用 User 這個(gè) entitybean ,甚至為了簡便,甚至生成了這個(gè)類以后就沒有使用它。建議在 SessionBean 中再調(diào)用 EntityBean ,也就是說,你可以在 UserManager 這個(gè) sessionbean 中調(diào)用 User 這個(gè) EntityBean 進(jìn)行進(jìn)一步的讀取數(shù)據(jù)庫,驗(yàn)證輸入的用戶名稱與密碼是否和數(shù)據(jù)庫表中的數(shù)據(jù)一致,具體的訪問操作,在 EntityBean 中操作。
2.?????? Hibernate 的出現(xiàn),給 ejb 的使用帶來了新的機(jī)遇,你可以生成 hibernate 的相關(guān)對(duì)象,然后在 SessionBean 的方法中不調(diào)用 EntityBean ,而是直接調(diào)用 Hibernate 的對(duì)象,進(jìn)行數(shù)據(jù)庫的訪問。這將帶來更大的靈活性,并能提高程序開發(fā)的效率
3.?????? 在測試程序中,可以使用 Factory 模式,簡化 SessionBean 對(duì)象的創(chuàng)建,并能夠提高重用。
4.?????? xdoclet 不止能夠創(chuàng)建 ejb 的代碼,還能夠產(chǎn)生 hibernate 等很多代碼,需要進(jìn)行相關(guān)的配置即可,這需要對(duì) xdoclet 的文檔進(jìn)行進(jìn)一步的查看與研究,另外還能夠自定義 tag ,例如生成 javascript 的校驗(yàn)代碼。 Xdoclet 是個(gè)好東西,就是用起來很復(fù)雜。
5.?????? eclipse 的 export 功能可以輸出 ant 的 build.xml 文件,不過這個(gè)配置文件很基本,你可以根據(jù)生成的 build 配置文件,進(jìn)一步的擴(kuò)充,使開發(fā) - 〉測試 - 〉打包 - 〉部署自動(dòng)化,能提高開發(fā)效率。