Xdoclet
生成
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
。現(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-4.0.3
,但是只需要標(biāo)記
4.0
即可
,
如果你使用的是
3.2.*
的版本,那就填寫成為
3.2
,
第二個(gè)是你在
jboss
中配置的
datasource
的名稱
第三個(gè)是你用到的數(shù)據(jù)源映射名稱,這個(gè)名稱是不能夠任意填寫,必須按照
jboss
配置文件中填寫,配置文件在
C:\jboss-4.0.3\server\default\conf\standardjbosscmp-jdbc.xml
(我的
jboss
安裝目錄)我測試用的是
mysql
,所以填寫
mySQL
。如果是
oracle9i
的數(shù)據(jù)庫,則為
Oracle9i
,更加詳細(xì)的信息,察看
standardjbosscmp-jdbc.xml
文件
最后一個(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)我用
jdk1.4.2
的時(shí)候就出現(xiàn)上述異常,更換為
jdk1.5
后即正常運(yùn)行。
生成
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("gary") && password.equals("gzllm")){
???????????????????? 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-4.0.3\docs\examples\jca\mysql-ds.xml
拷貝到需要發(fā)布的服務(wù)器中,修改配置文件數(shù)據(jù)庫連接部分為:
??? <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-3.1.10-bin.jar
(我用的
mysql
的
jdbc
驅(qū)動(dòng)程序是
mysql-connector-java-3.1.10
)拷貝到應(yīng)用程序服務(wù)器的
lib
目錄中,我的目錄是
C:\jboss-4.0.3\server\default\lib
,否則在啟動(dòng)
jboss
的時(shí)候會(huì)報(bào)異常:
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-4.0.3/server/default/deploy/MyEJB.jar/
說明
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ā)效率。
?