Xdoclet
生成
SessionBean
和
EntityBean
代碼
GzlLm
MSN
:
GzlLm@msn.com
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-4.0.3
,但是只需要標記
4.0
即可
,
如果你使用的是
3.2.*
的版本,那就填寫成為
3.2
,
第二個是你在
jboss
中配置的
datasource
的名稱
第三個是你用到的數據源映射名稱,這個名稱是不能夠任意填寫,必須按照
jboss
配置文件中填寫,配置文件在
C:\jboss-4.0.3\server\default\conf\standardjbosscmp-jdbc.xml
(我的
jboss
安裝目錄)我測試用的是
mysql
,所以填寫
mySQL
。如果是
oracle9i
的數據庫,則為
Oracle9i
,更加詳細的信息,察看
standardjbosscmp-jdbc.xml
文件
最后一個是生成
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
環境。例如當我用
jdk1.4.2
的時候就出現上述異常,更換為
jdk1.5
后即正常運行。
生成
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("gary") && password.equals("gzllm")){
???????????????????? 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-4.0.3\docs\examples\jca\mysql-ds.xml
拷貝到需要發布的服務器中,修改配置文件數據庫連接部分為:
??? <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-3.1.10-bin.jar
(我用的
mysql
的
jdbc
驅動程序是
mysql-connector-java-3.1.10
)拷貝到應用程序服務器的
lib
目錄中,我的目錄是
C:\jboss-4.0.3\server\default\lib
,否則在啟動
jboss
的時候會報異常:
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-4.0.3/server/default/deploy/MyEJB.jar/
說明
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
配置文件,進一步的擴充,使開發
-
〉測試
-
〉打包
-
〉部署自動化,能提高開發效率。