EJB CMP

 转贴自  http://hi.baidu.com/zdtools/blog/item/714110a842ccb7b2cb130c53.html

 

7.6     在RAD中创建CMP Entity Bean

通过CMP来进行数据的持久化操作,这样开发人员就不需要在程序中写与数据库操作有关的SQL了。下面介绍如何在RAD中创建CMP Entity Bean。

7.6.1     在RAD中创建CMP Entity Bean

要实现对数据库的调用,则需要对每个表创建相应的CMP Entity Bean,其创建过程如下。

选择【EJB Projects】→【ejbProject】→【New】→【Other】命令,弹出“Create an enterprise bean”的EJB创建对话框,在对话框的“EJB”目录下选择“Enterprise Bean”,如图7-11所示。

选择“EJB”目录下的“Enterprise Bean”选项,单击【Next】按钮,弹出创建EJB的对话框,如图7-12所示。需要输入创建EJB的如下相关信息。

l            Select the EJB type:选“Entity bean with container-managed persistence(CMP)fields”,表示这里将用CMP。

l            EJB project:输入EJB Project的名字,这里就是上面刚建立的“ejbProject”,所有的EJB Project都是在这个EJB Project下面工作。以后布置到Enterprise Applications下面的EJB包也是以这个EJB Project的名字来命名的。如本例的EJB包的名字将为“ejbProject.jar”。

l            Source folder:远程序的目录。

l            Default package:默认的pacakge。

l            CMP Version:选2.x,2.x的版本支持本地接口和本地Home接口,这样性能比较好。

图7-11     选择Enterprise Bean

图7-12     创建EJB的对话框

7.6.2     创建CMP Entity Bean的字段

在创建完成上面的CMP的基本信息后,需要进一步加入CMP对应的数据库表的字段,其创建过程如下。

单击图7-12的【Next】按钮,转入EJB详细信息对话框,如图7-13所示。

图7-13     加入CMP的字段

在对话框中选中“Local client view”选项,表示它将只创建本地Home接口(Local home interface)和本地接口(Local interface)。默认会出现一个id字段,根据所要创建的CMP的实际情形进行选择,一般都不会选择这个字段。

还有一个选项是“Use the single key attribute type for the key class”,如果选中该选项,那么CMP将会用这个字段的Java类型作为CMP的主键类,不另外创建CMP主键类。否则,即使是单个主键字段,CMP 将会创建主键类,这只适合单个主键的情形。

对于多个主键字段的情形,CMP一定会创建主键类。

单击【Add】按钮,弹出“CMP Attribute”字段编辑对话框,如图7-14所示。

在对话框中需要输入的CMP的相关字段信息如下。

l            Name:输入CMP的字段。

l            Type:输入字段的Java类型。

l            Key field:确认该字段是否为主键字段。

值得注意的是,主键字段是不能修改的。所以如果选了“Key field”,就不能选下面的Promote方法。

图7-14     加入CMP的主键字段

加入所有字段后,在图7-13所示的“Enterprise Bean Details”界面单击【Finish】按钮就完成了CMP的创建工作。

7.6.3     RAD自动生成的CMP Entity Bean

完成了上面的步骤后,进一步完成对每一个数据库表的CMP的创建工作。本例将会创建对应于数据库表Account、数据库表SequenceNum、数据库表User所对应的3个CMP,如图7-15所示。

图7-15     在RAD中所自动创建的CMP

下面是所创建的CMP实现类AccountBean.java的代码。

package com.sample.cmp.account;

/**

* 实现EntityBean接口类

* Bean implementation class for Enterprise Bean: Account

*/

public abstract class AccountBean implements javax.ejb.EntityBean {

 

private javax.ejb.EntityContext myEntityCtx;

        /**

         * setEntityContext

         */

        public void setEntityContext(javax.ejb.EntityContext ctx) {

            myEntityCtx = ctx;

        }

        /**

         * getEntityContext

         */

        public javax.ejb.EntityContext getEntityContext() {

            return myEntityCtx;

        }

        /**

         * unsetEntityContext

         */

        public void unsetEntityContext() {

            myEntityCtx = null;

        }

        /**

         * ejbCreate

         */

        public com.sample.cmp.account.AccountKey ejbCreate(

            java.lang.Integer accountID,

            java.lang.Integer userID) throws javax.ejb.CreateException {

            setAccountID(accountID);

            setUserID(userID);

            return null;

        }

        /**

         * ejbPostCreate

         */

        public void ejbPostCreate(

            java.lang.Integer accountID,

            java.lang.Integer userID) throws javax.ejb.CreateException {

        }

        /**

         * ejbActivate

         */

        public void ejbActivate() {

        }

        /**

         * ejbLoad

         */

        public void ejbLoad() {

        }

        /**

         * ejbPassivate

         */

        public void ejbPassivate() {

        }

        /**

         * ejbRemove

         */

        public void ejbRemove() throws javax.ejb.RemoveException {

        }

        /**

         * ejbStore

         */

        public void ejbStore() {

        }

         /**

         * Get accessor for persistent attribute: accountID

         */

        public abstract java.lang.Integer getAccountID();

        /**

         * Set accessor for persistent attribute: accountID

         */

        public abstract void setAccountID(java.lang.Integer newAccountID);

        /**

         * Get accessor for persistent attribute: userID

         */

        public abstract java.lang.Integer getUserID();

        /**

         * Set accessor for persistent attribute: userID

         */

        public abstract void setUserID(java.lang.Integer newUserID);

        /**

         * Get accessor for persistent attribute: registrationFee

         */

        public abstract java.math.BigDecimal getRegistrationFee();

        /**

         * Set accessor for persistent attribute: registrationFee

         */

        public abstract void setRegistrationFee(

            java.math.BigDecimal newRegistrationFee);

}

CMP实现类所包含的内容如下。

l            myEntityCtx:CMP的Entity Bean的环境变量。

l            setEntityContext:设置环境变量。

l            getEntityContext:取出环境变量,以便EJB容器能找到此CMP实例。

l            unsetEntityContext:删除环境变量,以便释放相应的资源。

l            ejbCreate:RAD会自动生成以主键为输入参数的ejbCreate方法,这个自动生成的ejbCreate方法除主键字段外,没有其他字段的插入,所以一般需要创建新的ejbCreate方法。

l            ejbPostCreate:保持和ejbCreate的方法一致。

l            ejbActivate:在调用CMP前,准备调用CMP Entity Bean的相应资源。

l            ejbLoad:查询取出数据时,保持和数据库同步。

l            ejbPassivate:在调用CMP后,释放相应的资源。

l            ejbRemove:删除CMP实例,本质上是删除数据库表的一条数据。

l            ejbStore:修改或者插入数据库表时,保持和数据库表的同步。

l            所有字段的setter和getter方法。

7.6.4     RAD自动生成的CMP主键类

在创建CMP时,如果不选“Use the single key attribute type for the key class”选项,那么不管是单个主键还是多个主键,CMP都会生成相应的如下主键类。

l            accountID:主键字段。

l            userID:主键字段。

l            AccountKey:无参数的构造方法。

l            AccountKey (java.lang.Integer accountID, java.lang.Integer userID):一般会用这个构造函数创建主键类的实例,然后用Home接口的findByPrimaryKey方法创建相应的本地接口方法。

l            equals:如果两个主键一致,返回true。

l            hashCode:返回主键类的hashCode值。

下面是以AccountKey为例的代码。

package com.sample.cmp.account;

/**

* Key class for Entity Bean: Account

*/

public class AccountKey implements java.io.Serializable {

        static final long serialVersionUID = 3206093459760846163L;

        /**

         * Implementation field for persistent attribute: accountID

         */

        public java.lang.Integer accountID;

        /**

         * Implementation field for persistent attribute: userID

         */

        public java.lang.Integer userID;

        /**

         * Creates an empty key for Entity Bean: Account

         */

        public AccountKey() {

        }

        /**

         * Creates a key for Entity Bean: Account

         */

        public AccountKey(java.lang.Integer accountID,

                             java.lang.Integer userID) {

            this.accountID = accountID;

            this.userID = userID;

        }

        /**

         * Returns true if both keys are equal.

         *

         */

        public boolean equals(java.lang.Object otherKey) {

            if (otherKey instanceof com.sample.cmp.account.AccountKey) {

                 com.sample.cmp.account.AccountKey o =

                  (com.sample.cmp.account.AccountKey) otherKey;

                 return ((this.accountID.equals(o.accountID)) &&

                           (this.userID.equals(o.userID)));

            }

            return false;

        }

        /**

         * Returns the hash code for the key.

         *

         */

        public int hashCode() {

            return (accountID.hashCode() + userID.hashCode());

        }

}

7.7    在RAD中建立CMP与数据库表之间的映射关系

每一个CMP实际上对应一个数据库表,所以需要建立CMP和数据库表之间的映射(Mapping)。CMP的本质就是要通过EJB容器来实现数据库层的操作,所以CMP和数据库表之间的映射是CMP中最核心的环节。

7.7.1    在RAD中创建meet-In-the-Middle的Mapping关系

为了要在CMP和数据库表之间建立映射关系,需要把数据库表结构和数据库字段导入到EJB Project项目之中,其过程如下。

在“EJB Projects”项目下的“ejbProject(项目名)”上单击鼠标右键,在弹出的快捷菜单中选择【EJB to RDB Mapping】→【Generate Map】命令,如图7-16所示。

图7-16    在RAD中选择Generate Map

进入“EJB to RDB Mapping”对话框,如图7-17所示,选择“Create a new backend folder”选项,将产生一个后台的目录,它将用来保存所要导入的数据库结构和字段,以及CMP和数据库表之间的映射关系等。

图7-17    选择“Create a new backend folder”

选择“Create a new backend folder”选项后,RAD转入“Create new EJB/RDB Mapping”对话框,如图7-18所示,创建一个新的EJB和关系数据库之间的映射关系,有3种映射方式可供选择。

l           Bottom-Up:通过数据库表直接生成相应的CMP。

l           Top-Down:通过已有的Entity Bean生成相应的数据库表。

l           Meet-In-the-Middle:在已有的Entity Bean和已有的数据库表中进行Mapping映射,这是实际工作中最复杂的情况,这里将予以介绍。

图7-18    选择“Meet-In-The-Middle”

单击【Next】按钮,转入数据库JDBC连接对话框,如图7-19所示,在对话框中创建一个数据库的JDBC连接,其目的是要通过这个连接将数据库表导入到EJB的项目中来,以便实现通过图形界面的方法直接创建CMP和数据库表之间的映射关系。

图7-19    创建数据库JDBC连接

需要输入的信息如下。

l           Connection name:数据库的连接名。

l           Database:数据库。

l           User ID:数据库用户名。

l           Password:数据库用户密码。

l           Database vendor type:数据库厂商类别。

l           JDBC driver:JDBC的驱动程序。

l           Host:数据库服务器IP。

l           Port number:数据库服务器的端口号。

l           JDBC driver class:JDBC驱动类。

l           Class location:类所在的路径。

单击【Next】按钮,转入“Selective Database Import”对话框,如图7-20所示,用来选择所要导入的数据库表。

图7-20    选择数据库表

单击【Next】按钮,进入“Create New EJB/RDB Mapping”对话框,如图7-21所示,在“Select Meet-in-the-Middle Mapping Options”目录下选择CMP和数据库表的如下自动映射方式。

l           None:事先不要在CMP和数据库表之间进行映射。

l           Match by Name:通过名字进行映射。

l           Match By Name, and Type: 通过名字和数据类型进行映射。

本例选None,即不通过RAD进行自动映射,因为下面将要手动来建立CMP和数据库表的映射关系。

图7-21    选择“None”

7.7.2    在CMP和数据库表间建立映射关系

下面将CMP和导入的数据库表建立映射关系。左边是CMP,右边是数据库表,下面以User的CMP为例来说明如何建立映射关系。

通过鼠标将“Enterprise Beans”目录下面的“ejbProject”→“User”(CMP)选项指向“Tables”目录下面的“bookstdb”(数据库)→“USER”(数据库表),建立CMP和数据库表之间的映射关系。

通过鼠标将“Enterprise Beans”目录下面的“ejbProject”→“User”(CMP)→“userID”(CMP主键字段)选项指向“Tables”目录下面的 “bookstdb”(数据库)→“USER”(数据库表)→“USERID”(数据库表主键字段),建立CMP主键字段和数据库表主键字段之间的映射关 系。

同理,可以建立CMP的其他字段和数据库表其他字段的映射关系。所建立的User(CMP)和数据库表的映射如图7-22所示。

图7-22    建立User(CMP)和数据库表的映射关系

7.8   创建新的CMP的ejbCreate方法

在RAD创建CMP时,会自动生成以主键为输入参数的ejbCreate方法,这个自动生成的ejbCreate方法只有主键字段的插入,没有其他字段的插入,所以一般需要创建新ejbCreate方法。

此外,在创建ejbCreate方法的时候,在数据 库表字段比较多的情况下,如果把所有的字段都作为create方法的输入参数的话,一方面,这样的ejbCreate方法会很长,不容易读;另一方面,如 果以后数据库表的字段出现增加和删除的情况,那么ejbCreate方法需要修改,因而笔者建议将创建输入参数的DTO数据类作为ejbCreate方法 的输入参数,这样易于程序的开发和维护,事实上,这也是在实际项目中经常用到的。

7.8.1   创建新的CMP的ejbCreate方法

ejbCreate方法主要目的是将数据插入数据库表,只要定义好了输入参数,然后调用setter方法将输入参数一一加入CMP中即可,参见如下代码。

package com.sample.cmp.user;

import com.sample.model.service.dto.UserAccountDTO;

/**

* Bean implementation class for Enterprise Bean: User

*/

public abstract class UserBean implements javax.ejb.EntityBean {

 

        /**

         * ejbCreate主要将用户数据插入User数据库表

         */

        public java.lang.Integer ejbCreate(Integer userID,

          UserAccountDTO userAccountDTO) throws

          javax.ejb.CreateException {

          // EJB 2.0 spec says return null for CMP ejbCreate methods.

          //设置所有Entity Bean CMP的字段

          setUserID(userID);

          setLoginName(userAccountDTO.getLoginName());

          setName(userAccountDTO.getName());

          setPassword(userAccountDTO.getPassword());

          setEmail(userAccountDTO.getEmail());

          setPhone(userAccountDTO.getPhone());

          return null;   //返回null 是必须的

          // end-user-code

        }

       /**

        * 和ejbCreate方法的接口一致

        * @param userID

        * @param userAccountDTO

        * @throws javax.ejb.CreateException

        */

        public void ejbPostCreate(Integer userID,

              UserAccountDTO userAccountDTO) throws

              javax.ejb.CreateException {

          // begin-user-code

          // end-user-code

        }

 

}

7.8.2   创建ejbCreate方法输入参数的DTO类

上面已经在ejbCreate方法中加入了输入参数 UserAccountDTO类,这里将创建UserAccountDTO类,如图7-23所示。UserAccountDTO用来存储和用户User有 关的信息。单击ejbCreate方法中的userAccountDTO,输入相应的UserAccountDTO类的信息,就创建了一个空的 UserAccountDTO类,接着加入相应的字段和相应的setter和getter方法即可。

当然,开发人员也可以在RAD上先创建DTO类,再将它作为输入参数加入ejbCreate方法。

图7-23   创建ejbCreate方法的输入参数DTO类

7.8.3   将ejbCreate方法提升到本地Home接口

在CMP中创建了ejbCreate方法后,需要将 其提升到本地Home接口以被调用,如图7-24所示,在“ejbCreate”上单击鼠标右键,在弹出的快捷菜单中选择【Enterprise Bean】→【Promote to Local Home Interface】命令。

图7-24   将ejbCreate方法提升到本地Home接口

在相应的本地Home接口中将生成新的create方法,UserLocalHome.java参见如下代码。

package com.sample.cmp.user;

import com.sample.model.service.dto.UserAccountDTO;

/**

* Local Home interface for Enterprise Bean: User

*/

public interface UserLocalHome extends javax.ejb.EJBLocalHome {

      /**

       *   RAD自动生成的以主键为输入参数的create方法

       * Creates an instance from a key for Entity Bean: User

       */

      public com.sample.cmp.user.UserLocal create(java.lang.Integer userID)

          throws javax.ejb.CreateException;

      /**

       * RAD自动生成的findByPrimaryKey方法,通过主键查询返回本地接口

       * Finds an instance using a key for Entity Bean: User

       */

      public com.sample.cmp.user.UserLocal findByPrimaryKey(

          com.sample.cmp.user.UserKey primaryKey)

          throws javax.ejb.FinderException;

      /**

       * 通过对将ejbCreate方法提升到本地Home接口所生成的create方法

       * @param userID

       * @param userAccountDTO

       * @return

       * @throws javax.ejb.CreateException

       */

      public com.sample.cmp.user.UserLocal create(

          Integer userID,

          UserAccountDTO userAccountDTO) throws

               javax.ejb.CreateException;

}

 

7.9    创建新的CMP的finder方法

RAD会自动创建findByPrimaryKey 的方法,它将根据主键查询返回一条数据库表的记录。在实际项目中经常遇到根据某些条件进行数据查询的业务需求,其实现本质即是通过某些参数找到对应于数据 库表的多条相应的数据,以便输出报表显示,或者修改,或者删除。所以需要创建新的CMP的finder方法。创建新的CMP的finder方法过程如下。

(1)在CMP中加入新的finder,如图7-25所示,在“EJB Deployment Descriptor”对话框中单击“Queries”目录下面的【Add】按钮。

图7-25    在CMP中加入新的finder

(2)进入finder方法创建对话框,如图7-26所示。

图7-26    输入相应的finder方法内容

(3)输入相应的finder方法的名字和参数如图7-27所示,在文本框“Name”中输入finder方 法名“findByUserID”;单击【Add】按钮,在弹出的“Add Method Parameter”对话框中的“Name”文本框中输入参数名称“userID”,在“Type”下拉列表中选择参数类型 “java.lang.String”,单击【OK】按钮将相应的参数加入到finder方法中。

图7-27    输入相应的finder方法的名字和参数

(4)输入相应的finder方法的返回类型,如图7-28所示,在“Return type”下拉列表中选择相应的类型选项,如“java.util.Collection”,表示将返回一个本地接口对象的集合,单击【Next】按钮。

图7-28    选择相应的finder方法的返回类型

(5)在“Query statement”目录下输入相应的SQL,注意这个SQL是基于CMP的对象名和字段名的,而不是基于数据库的表名和字段名的,单击【Finish】按钮,如图7-29所示。

图7-29    输入相应的SQL

一旦完成了上述过程,相应的Home Interface中也会生成相应的接口以被调用,如下面代码所示。

package com.sample.cmp.user;

/**

* Local Home interface for Enterprise Bean: User

*/

public interface UserLocalHome extends javax.ejb.EJBLocalHome {

       /**

        *    RAD自动生成的以主键为输入参数的create方法

        * Creates an instance from a key for Entity Bean: User

        */

       public com.sample.cmp.user.UserLocal

           create(java.lang.Integer userID)

           throws javax.ejb.CreateException;

       /**

        *    RAD自动生成的findByPrimaryKey方法,通过主键查询,返回本地接口

        *    Finds an instance using a key for Entity Bean: User

        */

       public com.sample.cmp.user.UserLocal findByPrimaryKey(

           com.sample.cmp.user.UserKey primaryKey)

           throws javax.ejb.FinderException;

 

/**

    * 新生成的findByLoginName,通过输入参数loginName,返回相应的数据库表的记录

    */

       public java.util.Collection findByLoginName(

          java.lang.String loginName) throws

          javax.ejb.FinderException;

}

 

7.12    在RAD中加入应用服务器Server

EJB容器一定需要应用服务器运行,在RAD上所开 发的Web应用和EJB应用也需要发布到应用服务器上,因而需要在RAD中加入服务器(Server),实现RAD和应用服务器的集成。RAD上自带 Websphere的各种版本服务器,本章的例子将加入Websphere 6.0服务器。下面显示了具体过程。

同创建CMP的过程一样,选择“EJB Projects”→“ejbProject”→“New”→“Other”选项,弹出“Server”列表,如图7-38所示。

图7-38    选择服务器Server

选择“Server”目录下面的“Server”选项,单击【Next】按钮,弹出“New Server”编辑对话框,如图7-39所示,所要输入的Server信息如下。

图7-39    选择Websphere v6.0 Server

(1)Host name:选择下拉列表中的应用服务器的IP地址。

(2)Select the server type:RAD提供了如下4种Server类型可供选择。

l           Websphere v5 Server Attach

l           Websphere v5.0 Server

l           Websphere v5.1 Server

l           Websphere v6.0 Server

本例将选择Websphere v6.0 Server,因为下面章节的IBM服务总线产品SIBus只有Websphere v6.0 Server才提供。

单击【Next】按钮,就可以完成对服务器的设置。

7.12.1    将Enterprise Application Project加入Server

J2EE项目需要布置到服务器上才能运行。所有的 Web应用项目、EJB应用项目和Web Service项目都会加入到RAD的Enterprise Applications项目中。然后将Enterprise Applications项目加入到服务器中去,如图7-40所示,在左边列表中选中所要发布到服务器的Enterprise Applications项目,如本例的“ejbProjectEAR”,然后单击【Add】按钮,这样可以将所选中的ear项目加入到应用服务器中。最 后单击【Finish】按钮即可完成加入过程。

图7-40    将Enterprise Project加入到Server

7.12.2    运行服务器 Server和打开Admin Console

将EJB项目加入服务器后,就可以运行服务器,过程如图7-41所示,在RAD右下框,单击加入的应用服务器,在弹出的快捷菜单中选择【Start】命令即可。

图7-41    运行服务器Server

运行服务器后,可以通过Websphere提供的 Administrative Console来对服务器进行配置和监控。在应用服务器完全启动后,单击应用服务器,在弹出的快捷菜单中选择【Run administrative console】命令,如图7-42所示。

图7-42    运行Admin Console

在弹出的“欢迎,请输入您的信息”界面的“用户标识”文本框中输入任意一个名字,不需要输入密码,单击【登录】按钮即可进入Admin Console界面,如图7-43所示。

图7-43    登录Admin Console

7.13   创建数据源和在CMP中配置数据源

Entity Bean CMP对数据库的调用是通过数据源来实现的,CMP只需要通过JNDI调用相应的数据源即可,由数据源指向数据库实现JDBC的连接。

7.13.1   创建安全机制

Websphere有一套特殊的方法来处理用户名和 密码,那就是安全机制,它将用户名和密码存入到一套安全机制对象中。需要输入用户名和密码的地方,如建立数据库连接,直接选择相应的安全机制即可,而不是 将用户名和密码硬写在数据库的连接中。这样,如果以后的用户名和密码变化的话,只需要对安全机制进行修改即可,而不需要直接去修改数据库连接。所以如果创 建数据源,首先需要创建数据库的用户名和密码的安全机制。下面是创建过程。

在“Admin Console”左边列表中选择“安全性“全局安全性”选项,如图7-44所示。

图7-44   选择“全局安全性”

在右边列表中的“认证”目录下面选择“JAAS 配置J2C 认证数据选项,弹出“J2EE连接器体系结构(J2C)认证数据条目”对话框,如图7-45所示。

图7-45   “J2EE连接器体系结构(J2C)认证数据条目”对话框

单击【新建】按钮,在弹出的如图7-46所示的对话框中输入相应的用户名和密码信息。

l          别名:可以任意取一个名字。

l          用户标识:这里输入数据库用户名。

l          密码:输入数据库用户的密码。

l          描述:可以输入任意的特定描述,以区别于其他的用户名和密码。

图7-46   创建J2C认证数据

单击【应用】按钮,就创建了相应的J2C认证数据,如图7-47所示。

图7-47   所创建的J2C认证数据

7.13.2   创建JDBC

JDBC是Java访问数据库的接口,它通过驱动程序(Driver)的方式来实现,保证了Java程序对不同类型数据库调用时用的是同一接口,创建JDBC的过程如下:

在“Admin Console”界面中的左边列表中选择“资源”→“JDBC提供者”选项,打开“JDBC提供者”对话框,如图7-48所示。

单击【新建】按钮,弹出“JDBC提供者>新建”对话框,如图7-49所示。选择下列参数。

l          选择数据库类型:本例用DB2,也可以使用其他的数据库,关键是要有JDBC的支持。

l          选择提供者类型:对应于DB2,本例选择“DB2 Universal JDBC Driver Provider”选项。

l          选择实现类型:选择“连接池数据源”选项。

图7-48   “JDBC提供者”对话框

图7-49   选择数据库类型

单击【下一步】按钮,弹出JDBC的Driver编辑对话框,如图7-50所示。上面的数据库不管是不是 DB2,关键是要在下面建立JDBC的Driver的类路径classpath。这样,在Websphere服务器运行时,就会找到相应的Driver的 classpath,建立正确的数据库连接,否则,是无法连接到数据库的。因为本实例是以DB2作为数据库的,所以实例路径是DB2的Driver的类路 径classpath。

图7-50   自动生成的JDBC路径

7.13.3   创建JDBC驱动程序Driver的路径变量

实例的类路径是Websphere服务器为DB2数据库的JDBC Driver所创建的类路径,其中的环境变量需要另外单独定义。只有定义这些环境变量后,Websphere应用服务器才能找到相应的JDBC驱动程序 Driver。图7-50所对应的如下的类路径需要定义:

${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc_license_cisuz.jar

下面将介绍如何创建环境变量“DB2UNIVERSAL_JDBC_DRIVER_PATH”来指向正确的JDBC Driver的类路径。

在“Admin Console”界面中的左边列表中选择“环境”→“Websphere变量”选项,显示界面如图7-51所示。

图7-51   创建路径(path)变量

单击“名称”目录下面的“DB2UNIVERSAL_JDBC_DRIVER_PATH”选项,在弹出的对话框中输入变量名和路径,如图7-52所示。

l          名称:所要编辑的变量名。

l          值:输入相应路径,本例为“E:/Program Files/IBM/SQLLIB/java”,对应于笔者机器DB2的安装路径,开发人员需要根据自己所装载的DB2的路径来定义。

图7-52   创建DB2UNIVERSAL_JDBC_DRIVER_PATH变量

单击【应用】按钮即可创建相应的环境变量。

7.13.4   创建数据源

Websphere通过创建数据源来指向相应的数据库地址,创建数据源的过程如下。

打开上面的所创建的JDBC的链接,弹出所创建的“JDBC提供者”对话框,如图7-53所示。  

图7-53   “JDBC提供者”对话框

在“其他属性”目录下,单击“数据源”选项进入“数据源”对话框,如图7-54所示。注意,如果应用程序使用 EJB1.1或者Servlet 2.2,则必须使用“数据源(V4)”。

图7-54   新建数据源

单击【新建】按钮,进入创建数据源界面,如图7-55所示,创建数据源时需要输入下面信息。

图7-55   输入创建JDBC所需数据库信息

l          作用域:和服务器名称有关,开发人员不能修改。

l          名称:定义一个数据源的名字。

l          JNDI 名称:输入一个唯一的JNDI的名字,如“jdbc/bkstore”,同时选取“将此数据源用于容器管理持久性(CMP)”选项,CMP将会用这个JNDI名建立数据库连接。

l          描述:输入一些描述该数据源的文字。

l          选择数据存储helper类:选取该选项,它将扩展JDBC驱动程序实现类的能力以执行数据库特定的功能;选中“DB2通用数据存储helper”。

l          组件管理的认证别名:选择有关用户名和密码的安全机制。

l          数据库名称:选择所创建的数据库。

l          驱动程序类型:默认4。

l          服务器名:数据库的服务器地址。

l          端口号:数据库服务器的端口号。

单击【应用】按钮,将会创建相应的数据源。注意,在“Admin Console”中完成任何修改后,一定要选择系统提示的“保存”选项。

7.13.5   测试数据源连接

上面的步骤已经完成了所有的数据源配置工作,下面介 绍如何检查配置是否正确,包括JAAS的安全机制、JDBC、JDBC驱动Driver的路径变量、数据库名、地址和端口等的配置检查,这些检查可以通过 测试数据源的连接来完成,直接单击【测试连接】按钮即可。本例可以看到连接成功的信息输出,如图7-56所示。

图7-56   测试数据源连接

7.13.6   配置CMP指向数据源的JNDI名

上面已经完成了CMP的创建和数据源的创建,现在进一步配置将CMP指向数据源的JNDI名,就可以完成CMP和数据库之间的关联,这是CMP连接数据库的关键。在RAD中的配置过程如下。

在RAD的“Project Explorer”对话框中选择【EJB Projects】→【ejbProject】→“Deployment Descriptor:ejbProject”选项;在弹出的对话框的“JNDI name”文本框中输入数据源的JNDI名称即可,本例为jdbc/bkstore,如图7-57所示。

图7-57   在CMP中建立数据库的连接

 

 

7.14    在RAD上创建基于Session Bean的Web Service

EJB2.1规定了无状态会话 Bean(Stateless Session Bean)对Web Service的支持,所以现在可以直接用各个厂商的IDE工具将无状态会话Bean发布为Web Service,实现远程调用。本节将介绍如何用RAD将Stateless Session Bean发布为Web Service,开发人员就不需要再编写Web Service的服务器端程序了。

在服务器端实现Web Service有两种方法:一种是直接通过Java Bean来创建Web Service;另一种是通过无状态会话Bean创建Web Service。因为无状态会话Bean有事物管理等功能,另外,为了保持本书的连贯性,这里介绍创建基于Session Bean的Web Service方法(在RAD上创建基于Java Bean的Web Service见本书附录C)。因为第5章已经在RAD上创建了Session Bean和CMP,这里进一步将第5章的Session Bean发布成Web Service,包括两个基本步骤。

(1)启动应用服务器。

(2)创建Web Service。

在RAD上发布Web Service时,首先需要启动应用服务器,否则在发布Web Service的过程中将会出现错误。启动服务器后,下面介绍在RAD上创建基于Session Bean的Web Service的具体过程。

1.创建Web Service

在RAD上创建基于Session Bean的Web Service不需要写任何程序,所有的过程都通过RAD来创建,其过程如下。

在RAD主界面选择【File】→【New】→【Other】命令,弹出“Select a wizard”对话框如图7-58所示。

图7-58    “Select a wizard”对话框

选中“Web Service”选项,单击【Next】按钮,转入“Web Service”对话框,如图7-59所示。在对话框的“Web service type”下拉列表中选择“EJB Web Service”选项,表示将会通过无状态会话Bean来创建Web Service。其他的选项采用默认设置即可。

图7-59    “Web Service”对话框

单击【Next】按钮,RAD将会自动从EJB Project中找到相应的无状态会话Bean,本例将会显示无状态会话Bean——UserAccountMgr,如图7-60所示。

图7-60    选择EJB Session Bean

单击【Next】按钮,转入“Service Deployment Configuration”对话框,如图7-61所示,在对话框的“Service project”下拉列表中选择上面创建的EJB项目“ejbProject”;在“EAR project”下拉列表中选择上面创建的EAR项目“ejbProjectEAR”。

图7-61    选择相应的选项

单击【Next】按钮,在弹出对话框的文本框 “Select Router Project”中输入“sampleRouterProject”的名称,决定Web Service的发布路径。选取“Select transports”目录下面的“SOAP over HTTP”选项,表示此Web Service将会采用SOAP和HTTP的传输协议,如图7-62所示。

图7-62    输入sampleRouterProject的名称

单击【Next】按钮,运行一段时间,将会出现包含创建的Web Service各种信息的对话框,选择要发布的Session Bean方法,如图7-63所示。

l           Web service URI:Web Service的地址。

l           WSDL Folder:WSDL所在目录。

l           WSDL File:描述Web Service的文件名wsdl。

l           Methods:可以选择将哪些方法发布成Web Service。

单击【Next】按钮,将会进入Web Service的发布对话框,如图7-64所示,主要让用户确认是否想把该Web Service注册到UDDI,以便外界能够查询到。本例不选择发布到UDDI,因为Web Service有它自己的地址。

图7-63    选择所要发布的Session Bean方法

图7-64    Web Service创建成功

单击【Finish】按钮,完成整个Web Service的创建工作。

2.在RAD上测试Web Service的功能

RAD提供了强大的Web Service的测试功能,开发人员不需要写任何程序,就能进行Web Service的测试。在“Project Explorer”对话框中的“Web Services”→“Services”→“UserAccountMgrService”上单击鼠标右键,在弹出的快捷菜单中选择【Test with Web Services Explorer】命令,如图7-65所示。

图7-65    用Web Services Explorer测试Web Service

在弹出对话框的左边列表中选择所要测试的服务接口方 法,如“getUserList”,单击右边列表中的【执行】按钮,从右下框可以看到相应的结果,测试非常方便。此Web Service会自动去调用Session Bean和CMP相应的方法,给出相应的结果,如图7-66所示。

图7-66    调用Web Service的方法

7.15   RAD生成的WSDL

经过上面的过程,将会产生UserAccountMgr.wsdl,如图7-67所示。WSDL文件的内容包括Web Service所提供的服务的传输方式、服务方法接口、接口参数、服务地址和服务绑定等。

图7-67   RAD自动生成的WSDL文件

WSDL的图形关系如图7-68所示。Services定义服务地址URI、Bindings定义传输协议、Port Types定义服务接口和Messages定义服务消息。

图7-68   RAD所显示的WSDL

下面是RAD自动生成的UserAccountMgr.wsdl的源码。 WSDL文档出现的初衷是要让使用者根据这个文档编写相应的SOAP消息来调用Web Service。然而,Axis包已经可以自动根据WSDL生成相应的Java调用程序,所以开发人员不是很需要理解这个文档了。

UserAccountMgr.wsdl的内容如下 面代码所示。开始部分说明此WSDL文件采用 XML 1.0 版本,语言集为UTF-8,并说明了一些WSDL的定义类型;接着用<wsdl:types>定义了此WSDL所包含的元素,如定义了 getUserListResponse的元素nillable为true,表示可以为空,返回数据类型为 ArrayOf_tns2_UserAccountDTO。

l          定义接口方法checkUserLogin,输入参数及类型,以及输入参数是否可以为空。

l          定义传输类参数UserAccountDTO,以及它所包含的字段名、类型、是否可以为空。

l          定义异常类ApplicationException,以及它所包含的字段名、类型、是否可以为空。

<?xml version="1.0" encoding="UTF-8"?>

<wsdl:definitions targetNamespace=http://sessionbean.ejb.sample.com

   xmlns:impl="http://sessionbean.ejb.sample.com"

   xmlns:intf=http://sessionbean.ejb.sample.com

   xmlns:tns2="http://dto.service.model.sample.com"

   xmlns:tns3=http://exception.sample.com

   xmlns:wsdl="http://schemas.xmlSOAP.org/wsdl/"

   xmlns:wsdlSOAP=http://schemas.xmlSOAP.org/wsdl/SOAP/

   xmlns:wsi="http://ws-i.org/profiles/basic/1.1/xsd"

   xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<wsdl:types>

   <schema targetNamespace=http://sessionbean.ejb.sample.com

   xmlns="http://www.w3.org/2001/XMLSchema"

   xmlns:impl=http://sessionbean.ejb.sample.com

   xmlns:intf="http://sessionbean.ejb.sample.com"

   xmlns:tns2=http://dto.service.model.sample.com

   xmlns:wsdl="http://schemas.xmlSOAP.org/wsdl/"

   xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <import namespace="http://dto.service.model.sample.com"/>

 

     <element name="getUserListResponse">

     <complexType>

      <sequence>

       <element name="getUserListReturn" nillable="true"

                  type="impl:ArrayOf_tns2_UserAccountDTO"/>

      </sequence>

     </complexType>

    </element>

    <element name="checkUserLogin">

     <complexType>

      <sequence>

      <element name="loginName" nillable="true" type="xsd:string"/>

      <element name="password" nillable="true" type="xsd:string"/>

      </sequence>

     </complexType>

   </element>

   <schema targetNamespace=http://dto.service.model.sample.com

   xmlns="http://www.w3.org/2001/XMLSchema"

   xmlns:impl=http://sessionbean.ejb.sample.com

   xmlns:intf="http://sessionbean.ejb.sample.com"

   xmlns:wsdl=http://schemas.xmlSOAP.org/wsdl/

   xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <complexType name="UserAccountDTO">

     <sequence>

      <element name="email" nillable="true" type="xsd:string"/>

      <element name="loginName" nillable="true" type="xsd:string"/>

      <element name="name" nillable="true" type="xsd:string"/>

      <element name="password" nillable="true" type="xsd:string"/>

      <element name="phone" nillable="true" type="xsd:string"/>

      <element name="registrationFee" nillable="true"

                  type="xsd:decimal"/>

      <element name="registrationTime" nillable="true" type="xsd:long"/>

      <element name="userAccountID" nillable="true" type="xsd:int"/>

     </sequence>

    </complexType>

   </schema>

   <schema targetNamespace="http://exception.sample.com"

   xmlns=http://www.w3.org/2001/XMLSchema

   xmlns:impl="http://sessionbean.ejb.sample.com"

   xmlns:intf=http://sessionbean.ejb.sample.com

   xmlns:wsdl="http://schemas.xmlSOAP.org/wsdl/"

   xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <complexType name="ApplicationException">

     <sequence>

      <element name="message" nillable="true" type="xsd:string"/>

     </sequence>

    </complexType>

    <element name="ApplicationException" nillable="true"

                 type="tns3:ApplicationException"/>

   </schema>

</wsdl:types>

下面定义SOAP的请求消息:getUserListRequest和saveUserInfoRequest等;定义 SOAP的返回消息:getUserListResponse和saveUserInfoResponse;定义异常类消息 ApplicationException。

<wsdl:message name="getUserListRequest">

       <wsdl:part element="impl:getUserList" name="parameters"/>

    </wsdl:message>

    <wsdl:message name="saveUserInfoRequest">

       <wsdl:part element="impl:saveUserInfo" name="parameters"/>

    </wsdl:message>

  <!--定义SOAP的返回消息-->

    <wsdl:message name="getUserListResponse">

       <wsdl:part element="impl:getUserListResponse" name="parameters"/>

    </wsdl:message>

    <wsdl:message name="checkUserLoginRequest">

       <wsdl:part element="impl:checkUserLogin" name="parameters"/>

    </wsdl:message>

    <wsdl:message name="saveUserInfoResponse">

       <wsdl:part element="impl:saveUserInfoResponse"

                      name="parameters"/>

    </wsdl:message>

    <wsdl:message name="checkUserLoginResponse">

       <wsdl:part element="impl:checkUserLoginResponse"

                      name="parameters"/>

    </wsdl:message>

    <wsdl:message name="ApplicationException">

       <wsdl:part name="fault" type="tns3:ApplicationException"/>

    </wsdl:message>

下面通过<wsdl:portType>定义服务接口UserAccountMgr,通 过<wsdl:operation>来绑定服务接口方法getUserList和checkUserLogin等,通 过<wsdl:input>来绑定请求消息getUserListRequest和checkUserLoginRequest,通 过<wsdl:output>来绑定返回消息getUserListResponse和checkUserLoginResponse,通 过<wsdl:fault>来绑定异常类消息ApplicationException,如下所示。

    <wsdl:portType name="UserAccountMgr">

       <wsdl:operation name="getUserList">

          <wsdl:input message="impl:getUserListRequest"

                   name="getUserListRequest"/>

          <wsdl:output message="impl:getUserListResponse"

                   name="getUserListResponse"/>

       </wsdl:operation>

       <wsdl:operation name="checkUserLogin">

          <wsdl:input message="impl:checkUserLoginRequest"

                   name="checkUserLoginRequest"/>

          <wsdl:output message="impl:checkUserLoginResponse"

                   name="checkUserLoginResponse"/>

          <wsdl:fault message="impl:ApplicationException"

                   name="ApplicationException"/>

       </wsdl:operation>

       <wsdl:operation name="saveUserInfo">

          <wsdl:input message="impl:saveUserInfoRequest"

                   name="saveUserInfoRequest"/>

          <wsdl:output message="impl:saveUserInfoResponse"

                   name="saveUserInfoResponse"/>

       </wsdl:operation>

    </wsdl:portType>

下面通过<wsdl:binding>将服务接口和传输协议进行绑定,首先创建一个绑定名,这里为 UserAccountMgrSOAPBinding,通过type属性定义所要绑定的服务接口UserAccountMgr,通过 wsdlSOAP:binding 元素的transport属性定义传输协议。

通过wsdl:service来定义Web Service的发布地址,wsdlSOAP:address元素的location属性定义了Web Service的地址,如下所示。

    <wsdl:binding name="UserAccountMgrSOAPBinding"

                   type="impl:UserAccountMgr">

       <wsdlSOAP:binding style="document"

                  transport="http://schemas.xmlSOAP.org/SOAP/http"/>

       <wsdl:operation name="getUserList">

          <wsdlSOAP:operation SOAPAction=""/>

          <wsdl:input name="getUserListRequest">

             <wsdlSOAP:body use="literal"/>

          </wsdl:input>

          <wsdl:output name="getUserListResponse">

             <wsdlSOAP:body use="literal"/>

          </wsdl:output>

       </wsdl:operation>

       <wsdl:operation name="checkUserLogin">

          <wsdlSOAP:operation SOAPAction=""/>

          <wsdl:input name="checkUserLoginRequest">

             <wsdlSOAP:body use="literal"/>

          </wsdl:input>

          <wsdl:output name="checkUserLoginResponse">

             <wsdlSOAP:body use="literal"/>

          </wsdl:output>

          <wsdl:fault name="ApplicationException">

             <wsdlSOAP:fault name="ApplicationException" use="literal"/>

          </wsdl:fault>

       </wsdl:operation>

       <wsdl:operation name="saveUserInfo">

          <wsdlSOAP:operation SOAPAction=""/>

          <wsdl:input name="saveUserInfoRequest">

             <wsdlSOAP:body use="literal"/>

          </wsdl:input>

          <wsdl:output name="saveUserInfoResponse">

             <wsdlSOAP:body use="literal"/>

          </wsdl:output>

       </wsdl:operation>

    </wsdl:binding>

    <wsdl:service name="UserAccountMgrService">

       <wsdl:port binding="impl:UserAccountMgrSOAPBinding"

                   name="UserAccountMgr">

          <wsdlSOAP:address location="http://localhost:9080

                         /routerProject/services/UserAccountMgr"/>

       </wsdl:port>

    </wsdl:service>

</wsdl:definitions>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值