|
5.4 Bean管理持久性实体EJB
Bean管理持久性的EJB要求开发者维护EJB和数据库的映射关系,在Bean实现类的编写中,由开发者指定对数据库的操作。 示例文件包括:AccountHome.java,Account.java,AccountBean.java,ProcessingErrorException.java,Client.java,Servlet.java,ejb-jar.xml,weblogic-ejb-jar.xml。
5.4.1 编写源文件
1.编写主接口程序
编辑文件AccountHome.java并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:
//AccountHome.java //定义本接口在包examples.ejb.basic.beanManaged
中 package
examples.ejb.basic.beanManaged; //本类用到的其他类。javax.ejb.*是开发EJB应用需要的类库。javax.naming.*是实现JNDI服务需要的类库。 import
javax.ejb.CreateException; import javax.ejb.EJBHome; import
javax.ejb.FinderException; import
java.rmi.RemoteException; import java.util.Enumeration;
/** *
这是AccontBean的主接口定义,这个接口是被EJB容器产生的类AccontBeanC实现的。 *
在这里只需定义EJB创建的方法,这些方法要和EJBean中的"ejbCreate"方法对应。 */ //EJBean主接口必须继承javax.ejb.EJBHome接口 public
interface AccountHome extends EJBHome {
/** * 这个方法和"AccountBean.java"中定义的的Bean的"ejbCreate"方法相对应 *
这两个方法的参数应该相同。当客户端调用"TraderHome.create()"方法时,EJB容器 *
会找到EJBean的实例,并调用它的"ejbCreate()"方法。 * @参数 accountID String
账号ID * @参数 initialBalance double 初始化结算值 * @返回 Account
远程对象 * @异常 javax.ejb.CreateException * 创建bean错误时抛出的异常 * @异常
RemoteException 当系统通讯发生故障时抛出 * @参看
examples.ejb.basic.beanManaged.AccountBean */ public Account
create(String accountId, double initialBalance) throws
CreateException, RemoteException;
/** * 根据主键对象,返回账号对象 * * @参数 primaryKey 主键 * @返回
Account 账号 * @异常 javax.ejb.FinderException * 访问数据库错误抛出的异常 *
@异常 RemoteException 当系统通讯发生故障时抛出 * @参看
examples.ejb.basic.beanManaged.AccountBean */ public Account
findByPrimaryKey(String primaryKey) throws FinderException,
RemoteException;
/** * 找到所有结算值大于balanceGreaterThan的账号 * * @返回 Enumeration
所有账号枚举 * @参数 double balanceGreaterThan,给定的结算值 * @异常
javax.ejb.FinderException * 访问数据库错误抛出的异常 * @异常 RemoteException
当系统通讯发生故障时抛出 * @参看
examples.ejb.basic.beanManaged.AccountBean */ public
Enumeration findBigAccounts(double balanceGreaterThan) throws
FinderException, RemoteException; }
2.编写远程接口程序
编辑文件Account.java并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:
//Account.java //定义本接口在包examples.ejb.basic.beanManaged
中 package
examples.ejb.basic.beanManaged; //本接口用到的其他类 //javax.ejb.*中定义了实现EJBean的接口。 import
java.rmi.RemoteException; import javax.ejb.EJBObject;
/** *
这是AccontBean的远程接口定义。远程接口中定义了客户端能远程调用EJBean的方法。这些方法除了 *
要抛出异常java.rmi.RemoteException之外,和EJBean中的定义是一致的。但并不是EJBean来实 *
现这个接口,而是由容器自动产生的类AccontBeanE实现的。 */ //这个接口必须继承javax.ejb.EJBObject接口 public
interface Account extends EJBObject {
/** * 远程方法:存入一定数目的金额 * * @参数 amount 存入金额的数量 * @返回
double 操作实际结果 * @异常 RemoteException 当系统通讯发生故障时抛出 */ public
double deposit(double amount) throws RemoteException;
/** * 远程方法:提取一定数目的金额 * * @参数 amount 提取金额的数量 * @返回
double 操作实际结果 * @异常 RemoteException 当系统通讯发生故障时抛出 * @异常
ProcessingErrorException * 购买操作出错时抛出的异常 */ public double
withdraw(double amount) throws ProcessingErrorException,
RemoteException;
/** * 远程方法:结算 * @返回 double 结算值 * @异常 RemoteException
当系统通讯发生故障时抛出 */ public double balance() throws
RemoteException; }
3.编写实现类程序
编辑文件AccountBean.java并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:
//AccountBean.java //定义本接口在包examples.ejb.basic.beanManaged package
examples.ejb.basic.beanManaged; //本类用到的其他类。javax.ejb.*是开发EJB应用需要的类库。javax.naming.*是实现JNDI服务需要的类库 import
java.io.Serializable; import java.sql.Connection; import
java.sql.PreparedStatement; import java.sql.ResultSet; import
java.sql.SQLException; import java.util.Enumeration; import
java.util.Vector;
import javax.ejb.CreateException; import
javax.ejb.DuplicateKeyException; import
javax.ejb.EJBException; import javax.ejb.EntityBean; import
javax.ejb.EntityContext; import
javax.ejb.FinderException; import
javax.ejb.NoSuchEntityException; import
javax.ejb.ObjectNotFoundException; import
javax.naming.InitialContext; import
javax.naming.NamingException; import javax.sql.DataSource;
/** * AccountBean是实体EJB,它演示了: *
EJBean管理的JDBC持续性管理和事务管理; *
在这个文件中的代码直接访问数据库; */ //这个类是实体Bean,必须实现接口 EntityBean public
class AccountBean implements EntityBean { //设置是否打印控制台 final
static private boolean VERBOSE = true; //声明实体上下文变量 private
EntityContext ctx; private String accountId; // 这也是主键类 private
double balance; /** * 为EJBean设置实体EJB上下文 * * @参数 ctx
EntityContext */ public void setEntityContext(EntityContext
ctx) { log("setEntityContext called"); this.ctx =
ctx; }
/** * 取消实体上下文设置 * */ public void
unsetEntityContext() { log("unsetEntityContext (" + id() +
")"); this.ctx = null; } /** *
这是本类必须实现的方法,在本例中没有用到 * */ public void ejbActivate()
{ log("ejbActivate (" + id() + ")"); }
/** * 这是本类必须实现的方法,在本例中没有用到 * */ public void
ejbPassivate() { log("ejbPassivate (" + id() + ")"); }
/** * 从数据库中加载EJB * * @异常
javax.ejb.NoSuchEntityException * 如果在数据库中没有找到Bean * @异常
javax.ejb.EJBException * 通讯或系统错误 */ public void ejbLoad()
{ log("ejbLoad: (" + id() + ")"); //声明数据库连接对象 Connection
con = null; //声明SQL命令预处理对象 PreparedStatement ps =
null; //找到账号主键 accountId = (String) ctx.getPrimaryKey();
try { //获取数据库连接 con =
getConnection(); //设置SQL命令,读取记录 ps =
con.prepareStatement("select bal from ejbAccounts where id =
?"); //设置SQL命令 ps.setString(1,
accountId); //执行SQL ps.executeQuery(); //获取SQL结果 ResultSet
rs = ps.getResultSet(); if (rs.next()) { //取得数据 balance =
rs.getDouble(1); } else { String error = "ejbLoad: AccountBean
(" + accountId + ") not found"; log(error); throw new
NoSuchEntityException (error); } } catch (SQLException sqe)
{ //数据库异常处理 log("SQLException: " + sqe); throw new
EJBException(sqe); } finally { cleanup(con, ps); } }
/** * 数据库中存入EJBean * * @异常
javax.ejb.NoSuchEntityException * 如果在数据库中没有找到Bean * @异常
javax.ejb.EJBException * 通讯或系统错误 */ public void ejbStore()
{ log("ejbStore (" + id() + ")"); //声明数据库连接对象 Connection
con = null; //声明SQL命令预处理对象 PreparedStatement ps = null;
try { //获取数据库连接 con =
getConnection(); //设置SQL命令,更新数据库 ps =
con.prepareStatement("update ejbAccounts set bal = ? where id =
?"); //设置SQL命令 ps.setDouble(1, balance); ps.setString(2,
accountId); //执行SQL if (!(ps.executeUpdate() > 0))
{ String error = "ejbStore: AccountBean (" + accountId + ") not
updated"; log(error); throw new NoSuchEntityException
(error); } } catch(SQLException sqe)
{ ///数据库次操作异常处理 log("SQLException: " + sqe); throw new
EJBException (sqe); } finally { cleanup(con,
ps); } }
/** *
这个方法和"AccountBean.java"中定义的的Bean的"ejbCreate"方法相对应 *
这两个方法的参数应该相同。当客户端调用"TraderHome.create()"方法时,EJB容器 *
会找到EJBean的实例,并调用它的"ejbCreate()"方法。 *
对容器管理的ejb,ejbCreate方法返回为null,而bean管理的ejb,返回的是主键类。 * @参数 accountID
String 账号ID * @参数 initialBalance double 初始化结算值 * @参数 type
String 账号类型 * @异常 javax.ejb.CreateException *
创建bean错误时抛出的异常 */ public String ejbCreate(String accountId,
double initialBalance) throws CreateException { //日志信息
log("AccountBean.ejbCreate( id = accountId" + ", " + "initial
balance = $ " + initialBalance + ")"); this.accountId =
accountId; this.balance =
initialBalance; //声明数据库连接 Connection con =
null; PreparedStatement ps = null;
try { //获取数据库连接 con =
getConnection(); //执行sql语句,插入记录 ps =
con.prepareStatement("insert into ejbAccounts (id, bal) values (?,
?)"); ps.setString(1, accountId); ps.setDouble(2,
balance); if (ps.executeUpdate() != 1) { String error = "JDBC
did not create any row"; log(error); throw new CreateException
(error); }
return accountId; } catch (SQLException sqe)
{ //异常处理 try
{ //查找主键 ejbFindByPrimaryKey(accountId); }
catch(ObjectNotFoundException onfe) { String error =
"SQLException: " + sqe; log(error); throw new CreateException
(error); } String error = "An Account already exists in the
database with Primary Key " + accountId; log(error); throw new
DuplicateKeyException(error); } finally { cleanup(con,
ps); } }
/** * 这是本类必须实现的方法,在本例中没有用到 */ public void
ejbPostCreate(String accountId, double initialBalance)
{ log("ejbPostCreate (" + id() + ")"); }
/** * 从数据库中删除EJBean * * @异常
javax.ejb.NoSuchEntityException * 如果数据库中没找到这个ejb * @异常
javax.ejb.EJBException * 通信错误抛出的异常 */ public void
ejbRemove() { log("ejbRemove (" + id() +
")"); //声明数据库连接 Connection con = null; PreparedStatement ps
= null;
try { //获取连接 con = getConnection(); //获取主键 accountId
= (String) ctx.getPrimaryKey(); //执行SQL语句,删除记录 ps =
con.prepareStatement("delete from ejbAccounts where id =
?"); ps.setString(1, accountId); if (!(ps.executeUpdate() >
0)) { String error = "AccountBean (" + accountId + " not
found"; log(error); throw new NoSuchEntityException
(error); } } catch (SQLException sqe)
{ //异常处理 log("SQLException: " + sqe); throw new
EJBException (sqe); } finally { //清除 cleanup(con,
ps); } }
/** * 给定主键查找EJBean * * @参数 pk String 主键 * @返回 String
主键 * @异常 javax.ejb.ObjectNotFoundException *
EJBean没发现抛出的异常 * @异常 javax.ejb.EJBException * if there is a
communications or systems failure */ public String
ejbFindByPrimaryKey(String pk) throws
ObjectNotFoundException { log("ejbFindByPrimaryKey (" + pk +
")"); //声明数据库连接 Connection con = null; PreparedStatement ps
= null;
try { //获取连接 con = getConnection(); //查询主键对应的记录 ps =
con.prepareStatement("select bal from ejbAccounts where id =
?"); ps.setString(1,
pk); ps.executeQuery(); //获取结果集 ResultSet rs =
ps.getResultSet(); if (rs.next()) { balance =
rs.getDouble(1); } else { //没有发现这个主键值的ejb String error =
"ejbFindByPrimaryKey: AccountBean (" + pk + ") not
found"; log(error); //抛出异常 throw new
ObjectNotFoundException (error); } } catch (SQLException sqe)
{ //异常处理 log("SQLException: " + sqe); throw new
EJBException (sqe); } finally { //清除 cleanup(con,
ps); }
log("ejbFindByPrimaryKey (" + pk + ") found"); return
pk; }
/** * 查找所有结算大于给定值的EJBeans * 返回主键枚举 * * @参数
balanceGreaterThan double Test Amount * @返回 主键枚举 * @异常
javax.ejb.EJBException * 通信错误抛出的异常 */ public Enumeration
ejbFindBigAccounts(double balanceGreaterThan)
{ log("ejbFindBigAccounts (balance > " + balanceGreaterThan +
")"); //声明数据库连接 Connection con = null; PreparedStatement ps
= null;
try { //获取连接 con = getConnection(); ps =
con.prepareStatement("select id from ejbAccounts where bal >
?"); ps.setDouble(1,
balanceGreaterThan); ps.executeQuery(); //获取结果集 ResultSet
rs = ps.getResultSet(); Vector v = new Vector(); String
pk; while (rs.next()) { pk =
rs.getString(1); v.addElement(pk); } //返回枚举 return
v.elements(); } catch (SQLException sqe)
{ //异常处理 log("SQLException: " + sqe); throw new
EJBException (sqe); } finally { //清除 cleanup(con,
ps); } }
/** * 存入一定数量 * * @参数 amount double Amount * @返回
double 结算 */ public double deposit(double amount)
{ log("Depositing $" + amount + " into '" + accountId +
"'"); balance += amount; return balance; }
/** * 提取 * * @参数 amount double 数量 * @返回 double
结算 * @异常 ProcessingErrorException * 如果数量大于结算 */ public
double withdraw(double amount) throws
ProcessingErrorException { log("Withdrawing $" + amount + "
from '" + accountId + "'"); if (amount > balance) { String
error = "Request to withdraw $" + amount + " more than balance "
+ balance + " in account " + accountId; log(error); throw new
ProcessingErrorException(error); }
balance -= amount; return balance; }
/** * 返回当前结算值 * * @返回 double 结算 */ public double
balance() { return balance; }
/** * 从连接池中获取当前连接 * * @返回 连接 * @异常
javax.ejb.EJBException * 通信错误 */ private Connection
getConnection() throws SQLException { //声明初始化上下文
InitialContext initCtx = null; try { initCtx = new
InitialContext(); //查找数据源 DataSource ds =
(javax.sql.DataSource) initCtx.lookup("java:comp/env/jdbc/demoPool"); //返回数据源连接
return ds.getConnection(); } catch(NamingException ne)
{ //有异常 log("UNABLE to get a connection from
demoPool!"); log("Please make sure that you have setup the
connection pool properly"); throw new EJBException(ne); }
finally { try { if(initCtx != null) initCtx.close(); }
catch(NamingException ne) { log("Error closing context: " +
ne); throw new EJBException(ne); } } }
// 也可以使用WebLogic的日志服务 private void log(String s) { if
(VERBOSE) System.out.println(s); }
// 返回这个beans的id private String id() { return "PK = " +
(String) ctx.getPrimaryKey(); } //清除 private void
cleanup(Connection con, PreparedStatement ps) { try { if (ps
!= null) ps.close(); } catch (Exception e) { log("Error
closing PreparedStatement: "+e); throw new EJBException
(e); }
try { if (con != null) con.close(); } catch (Exception e)
{ log("Error closing Connection: " + e); throw new
EJBException (e);
} } }
4.编写处理异常程序
编辑文件ProcessingErrorException.java并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:
//ProcessingErrorException.java //定义本类在包examples.ejb.basic.beanManaged
中 package examples.ejb.basic.beanManaged;
/** * 这是用户定义的异常类 */ //用户定义的异常类必须继承Exception public
class ProcessingErrorException extends Exception {
/** * 获取没有字符串参数的异常 * */ public
ProcessingErrorException() {}
/** * 用特定的字符串构造异常 * * @参数 message Exception
消息 */ public ProcessingErrorException(String message)
{super(message);} }
5.编写客户端测试程序
编辑文件Client.java并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:
//Client.java //定义本类在包examples.ejb.basic.beanManaged
中 package examples.ejb.basic.beanManaged; //本类用到的其他类 import
java.rmi.RemoteException; import java.util.Enumeration; import
java.util.Properties; import
java.util.Vector; //本类用到的EJB类 import
javax.ejb.CreateException; import
javax.ejb.EJBException; import
javax.ejb.FinderException; import
javax.ejb.ObjectNotFoundException; import
javax.ejb.RemoveException; //本类用到的名称服务类 import
javax.naming.Context; import
javax.naming.InitialContext; import
javax.naming.NamingException; import
javax.rmi.PortableRemoteObject;
/** * 这个类演示了如何调用一个实体EJB,并进行如下操作: */
public class Client { //声明变量 private String
url;
private AccountHome home; //构造方法 public
Client(String url) throws NamingException {
this.url = url; //查找主接口,lookupHome是本例自定义方法。 home =
lookupHome(); }
/** * 在命令行运行这个实例: * java
examples.ejb.basic.beanManaged.Client "t3://localhost:7001" *
参数是可选的 * @参数 url URL such as "t3://localhost:7001" of
Server */ public static void main(String[] args) throws
NamingException { System.out.println("\nBeginning
beanManaged.Client...\n");
String url = "t3://localhost:7001";
// 解析命令行参数 if
(args.length != 1) { System.out.println("Usage: java
examples.ejb.basic.beanManaged.Client t3://hostname:port");
return; } else { url = args[0]; }
Client client = null;
try { //实例化本类 client = new Client(url); } catch
(NamingException ne) { //异常处理 log("Unable to look up the beans
home: " + ne.getMessage()); System.exit(1); }
try { //运行实例 client.example();
} catch (Exception e) { //异常处理 log("There was an exception
while creating and using the Accounts."); log("This indicates
that there was a problem communicating with the server: "+e); }
System.out.println("\nEnd
beanManaged.Client...\n"); } /** * 执行实例 * */
public void example() throws CreateException,
RemoteException, FinderException, RemoveException {
int numBeans = 20; //声明并创建账号数组 Account [] accounts = new
Account [numBeans];
// 创建20个账号 for (int i=0; i<numBeans; i++) { accounts [i]
= findOrCreateAccount("ID: "+i, i * 1000); }
// 打印账号结算 for (int i=0; i<numBeans; i++) { log("Account:
:"+accounts[i].getPrimaryKey()+ " has a balance of
"+accounts[i].balance()); }
// 查找所有结算大于5000的账号 findBigAccounts(5000.0);
// 清除所有账号
log("Removing beans..."); for (int i=0; i<numBeans; i++)
{ accounts[i].remove(); } }
/** * 列出所有结算大于给定值的账号 *
这个finder方法演示返回枚举账号 */ private void findBigAccounts(double
balanceGreaterThan) throws RemoteException,
FinderException { log("\nQuerying for accounts with a balance
greater than " + balanceGreaterThan +
"..."); //调用主接口创建账号方法findBigAccounts,返回账号枚举 Enumeration enum =
home.findBigAccounts(balanceGreaterThan);
if(! enum.hasMoreElements()) { log("No accounts were
found!"); }
while (enum.hasMoreElements()) { //创建远程对象 Account
bigAccount= (Account)
PortableRemoteObject.narrow(enum.nextElement(),
Account.class);
log("Account " + bigAccount.getPrimaryKey() + "; balance is
$" + bigAccount.balance()); } }
/** * 如果对应id的账号以存在,则返回这个id,否则创建它 */ private Account
findOrCreateAccount(String id, double balance) throws
CreateException, RemoteException, FinderException { try
{ log("Trying to find account with id: "+id); return (Account)
PortableRemoteObject.narrow(home.findByPrimaryKey(id), Account.class); }
catch (ObjectNotFoundException onfe) { // 账号不存在,创建它 return
(Account) PortableRemoteObject.narrow(home.create(id,
balance), Account.class); } }
/** * 给定id和结算创建一个新的账号 */ private Account
createAccount(String id, double balance) throws CreateException,
RemoteException { log("Creating account " + id + " with a
balance of " + balance + "..."); //创建远程账号对象 Account ac =
(Account) PortableRemoteObject.narrow(home.create(id,
balance), Account.class); log("Account " + id + " successfully
created");
return ac; }
/** * 使用JNDI查找bean的主接口 */ private AccountHome
lookupHome() throws NamingException { Context ctx =
getInitialContext();
try { //查找主接口 Object home =
ctx.lookup("beanManaged.AccountHome"); return (AccountHome)
PortableRemoteObject.narrow(home, AccountHome.class);
} catch (NamingException ne) { //异常处理 log("The client was
unable to lookup the EJBHome. Please make sure " + "that you have
deployed the ejb with the JNDI name " + "beanManaged.AccountHome
on the WebLogic server at "+url);
throw ne; } }
/** * 获取初始化上下文 */ private Context getInitialContext()
throws NamingException {
try { // 设置属性对象 Properties h =
new
Properties(); h.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); h.put(Context.PROVIDER_URL,
url); return new InitialContext(h); } catch (NamingException
ne) { //异常处理 log("We were unable to get a connection to the
WebLogic server at "+url); log("Please make sure that the server
is running."); throw ne; } } //控制台输出 private static
void log(String s) { System.out.println(s); } }
6.客户端程序
编辑文件Servlet.java并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:
//Servlet.java
//定义本接口在包examples.ejb.basic.beanManaged package
examples.ejb.basic.beanManaged; //本类用到的其他类。javax.ejb.*是开发EJB应用需要的类库。javax.naming.*是实现JNDI服务需要的类库 import
java.io.IOException; import java.io.OutputStream; import
java.rmi.RemoteException; import java.util.Enumeration; import
java.util.Properties; import java.util.Vector;
import javax.naming.Context; import
javax.naming.InitialContext; import
javax.servlet.http.HttpServlet; import
javax.servlet.http.HttpServletRequest; import
javax.servlet.http.HttpServletResponse;
import weblogic.html.BreakElement; import
weblogic.html.HeadingElement; import
weblogic.html.ServletPage; import
weblogic.html.StringElement;
/** * 这个servlet和Client类类似 * 这个servlet必须在web.xml文件中注册 *
使用url
http://localhost:7001/examplesWebApp/beanManaged调用这个servlet */ public
class Servlet extends HttpServlet {
static String accountId = "10020";
/** * 查找beanManaged主接口 * 创建beans并调用远程接口中定义的方法 * *
@参数 req HttpServletRequest * @参数 res HttpServletResponse * @异常
java.io.IOException * 如果IO错误 */ public void
service(HttpServletRequest req, HttpServletResponse res) throws
IOException { //设置文档类型
res.setContentType("text/html"); OutputStream out =
res.getOutputStream(); String title = "EJBean Bean-managed
Persistence Servlet"; //ServletPage实例 ServletPage sp = new
ServletPage(title); //编辑html元素 sp.getBody() .addElement(new
HeadingElement(title, 1)); printElement("", sp);
// 获取参数 //
"http://localhost:7001/beanManaged?user=foobar&password=FooBarNone" //用户名 String
user = req.getParameter("user"); //密码 String password =
req.getParameter("password");
if(user!=null &&
password!=null){ printElement("Using user <b>" + user +
"</b> and password <b> " + password + "</b>",
sp); printElement("", sp); } else { printElement("No user
and password credentials", sp); printElement("",
sp); }
double amount = 100; double balance =
3000; Vector v = new Vector();
try { // 获取上下文 Context ctx =
getInitialContext(); //查找主接口 AccountHome home = (AccountHome)
ctx.lookup("beanManaged.AccountHome");
// 查找Account或创建它 Account ac = null; try
{ printElement("Looking up account " + accountId + "...",
sp); ac = (Account) home.findByPrimaryKey(accountId); }
catch (Exception ee) { //异常处理 printElement("Did not find
" + accountId, sp); }
if (ac == null) { printElement("Account " + accountId + "
being created; opening balance is $" + balance,
sp); //创建远程对象 ac = home.create(accountId, balance); }
else { printElement("Account " + accountId + " found; balance
is $" + ac.balance(), sp); } printElement("", sp);
// A部分: 存入和提取大于当前结算的金额,会抛出用户定义的异常
printElement("Part A: Depositing $" + amount,
sp); //存入 balance =
ac.deposit(amount); printElement("Current balance is $" +
balance, sp); printElement("", sp);
amount = balance + 10; try { printElement("Withdrawing
amount greater than current balance. Expecting an exception...",
sp); //提取 balance =
ac.withdraw(amount); printElement("Error: expected an
exception.", sp); } catch (ProcessingErrorException pe)
{ //用户定义的异常 printElement("Received expected Processing
Error:<br>" + pe, sp); } printElement("", sp);
// B部分: 创建一些新的用户,并给定不同的初始结算 // 查找结算大于给定值的所有账号 //
最后,删除所有新的账号
int numAccounts = 5; printElement("Part B: Creating " +
numAccounts + " new accounts...", sp); long now =
System.currentTimeMillis(); for (int i = 0; i < numAccounts;
i++) { String id = "" + now + i; // 唯一的账号id balance = i*100;
// 初始结算 v.addElement(home.create(id, balance));
printElement("Created account: " + id + "; balance is $" +
balance, sp); } printElement("", sp);
if (v.size() == numAccounts) { printElement("" + numAccounts +
" accounts successfully created", sp); } else
{ printElement("Error: Only " + v.size() + " accounts were
created successfully", sp); } printElement("", sp);
double balanceGreaterThan = 200; printElement("Querying for
accounts with a balance greater than " + balanceGreaterThan +
"...", sp); //调用主接口的方法 Enumeration e =
home.findBigAccounts(balanceGreaterThan); if (e != null)
{ while (e.hasMoreElements()) { //每个账号 Account bigAccount=
(Account) e.nextElement(); //打印每个账号的主键 printElement("Account "
+ bigAccount.getPrimaryKey() + "; balance is $" +
bigAccount.balance(),
sp); Thread.sleep(1000); } } printElement("", sp);
printElement("Removing accounts just created...",
sp); //清除所有账号 for (int i = 0; i < numAccounts; i++)
{ String id = "" + now + i;
((Account)(v.elementAt(i))).remove(); printElement("Removed
account: " +id, sp); } printElement("", sp);
// 捕获异常 } catch (ProcessingErrorException pe)
{ printElement("Unexpected Processing Error: " + pe,
sp); } catch (Exception e)
{ //其它异常 printElement(":::::::::::::: Unexpected Error
:::::::::::::::::", sp); e.printStackTrace(); } finally
{ printElement("End beanManaged.Servlet...", sp); }
sp.output(out); out.flush(); }
/** *
基本的servlet信息 */ public String getServletInfo() { return
"EJBean Servlet"; }
/** * 打印一个bean的HTML信息 */ static private void
printAccount(Account account, ServletPage sp) throws
RemoteException, IOException { printElement("Account " +
account.getPrimaryKey() + "; balance is $" + account.balance(),
sp); }
/** * 打印消息给浏览器 */ static private void
printElement(String message, ServletPage sp) throws IOException
{ sp.getBody() .addElement(new
BreakElement()) .addElement(new StringElement(message)); }
/** * 获取当前用户、密码和url的初始化上下文。 * * @return 上下文 * @异常
java.lang.Exception if there is * an error in getting the
Context */ static public Context getInitialContext() throws
Exception { Properties p = new
Properties(); p.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); return
new InitialContext(p); } }
7.编写ejb描述文件
编辑文件ejb-jar.Xml并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:
<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD
Enterprise JavaBeans 1.1//EN'
'http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd'>
<ejb-jar> <enterprise-beans> <entity> <ejb-name>beanManaged</ejb-name> <home>examples.ejb.basic.beanManaged.AccountHome</home> <remote>examples.ejb.basic.beanManaged.Account</remote> <ejb-class>examples.ejb.basic.beanManaged.AccountBean</ejb-class> <persistence-type>Bean</persistence-type> <prim-key-class>java.lang.String</prim-key-class> <reentrant>False</reentrant>
<resource-ref> <res-ref-name>jdbc/demoPool</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>
</entity> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>beanManaged</ejb-name> <method-intf>Remote</method-intf> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar>
8.编写ejb部署文件
编辑文件weblogic-ejb-jar.xml并保存到C:\work\src\examples\ejb\basic\beanManaged目录下(或从附带光盘的src\examples\ejb\basic\beanManaged目录拷贝),其源文件如下:
<?xml version="1.0"?>
<!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD
WebLogic 5.1.0 EJB//EN'
'http://www.bea.com/servers/wls510/dtd/weblogic-ejb-jar.dtd'>
<weblogic-ejb-jar> <weblogic-enterprise-bean> <ejb-name>beanManaged</ejb-name> <caching-descriptor> <max-beans-in-cache>100</max-beans-in-cache> </caching-descriptor> <reference-descriptor>
<resource-description> <res-ref-name> jdbc/demoPool </res-ref-name> <jndi-name> examples-dataSource-demoPool </jndi-name> </resource-description>
</reference-descriptor>
<jndi-name>beanManaged.AccountHome</jndi-name> </weblogic-enterprise-bean> </weblogic-ejb-jar>
5.4.2 编译
(1)打开命令窗口,进入C:\work\src\examples\ejb\basic\beanManaged目录。 (2)运行设置环境变量命令脚本setEnv.cmd: c:\work\src\examples\ejb\basic\beanManaed>c:\work\setEnv setEnv.cmd在附带光盘的work目录下,可以直接把它拷贝到C:\work\目录。 (3)运行编译脚本build.cmd:
c:\work\src\examples\ejb\basic\beanManaed>bukld 其中build.cmd代码如下:
@REM Copyright (c) 2000 BEA Systems, Inc. All Rights
Reserved. @REM You must set your environment by running the
setExamplesEnv shell script @REM prior to executing this
script.
@REM Create the build directory, and copy the deployment
descriptors into it mkdir build build\META-INF copy *.xml
build\META-INF
@REM Compile EJB classes into the build directory (jar
preparation) javac -d build Account.java AccountHome.java
ProcessingErrorException.java AccountBean.java
@REM Make a EJB jar file, including XML deployment
descriptors cd build jar cv0f std_ejb_basic_beanManaged.jar
META-INF examples cd ..
@REM Run EJBC on jar file java -classpath
%WL_HOME%/lib/weblogic_sp.jar;%WL_HOME%/lib/weblogic.jar
weblogic.ejbc -compiler javac build\std_ejb_basic_beanManaged.jar
%WL_HOME%\config\%DOMAIN_NAME%\applications\ejb_basic_beanManaged.jar
@REM Compile servlets and EJB interfaces into WEB-INF/classes
directory of the Examples Web App @REM This ensures that the EJB
can be accessed by JSPs and servlets of the Examples Web
App javac -d %EX_WEBAPP_CLASSES% Servlet.java Account.java
AccountHome.java ProcessingErrorException.java
@REM Compile EJB interfaces & client app into the
clientclasses directory javac -d %CLIENT_CLASSES% Account.java
AccountHome.java ProcessingErrorException.java Client.java
5.4.3 定义数据源
本示例使用数据源examples-dataSource-demoPool和连接池demoPool。前面已经定义了连接池demoPool,本节演示如何通过系统管理工具Console定义连接池demoPool的数据源。 (1)启动WebLogic服务 (2)启动系统管理控制台程序console(在浏览器URL中输入http://127.0.0.1:7001/console/,回车)。 (3)点出console控制台左面板的Services/JDBC/Data
Sources,如图5-8所示。 (4)接下来是一个主要的步骤,点击控制台右面板的“Create a new JDBC
ConnectionPool...”,创建新的连接池。进入图5-9的操作界面。定义新数据源名称“Name:”为“examples-dataSource-demoPool”,定义连接池名称“Pool
Name:”为“demoPool”,然后点击“Create”创建。 (5)下面有一个重要的步骤,那就是创建完数据源后,还要把它部署到系统管理的服务器myserve中点击图5-9的Targets页,在Available栏中选中myserver,点击向右的箭头,点击“Apply”。如图6-10所示。
1.修改启动脚本
本示例使用WebLogic Server 6.0自带的小型关系数据库cloudscape。因此在WebLogic
Server启动的时候,要对启动脚本文件startWebLogic.cmd进行修改。如果还没有修改,则参见上一个实例。
2.配置Servlet
本示例客户端测试程序除了Client.java之外,还提供了一个Servlet程序,它和Client具有一样的功能,以Servlet应用的方式使用。使用Sevlet前要进行注册。Servlet程序的注册信息都放在web.xml文件中。 要注册Servlet首先要编辑C:\bea\wlserver6.0\config\mydomain\applications\DefaultWebApp_myserver\WEB-INF路径下的web.xml文件。
<?xml version="1.0" ?> <!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 1.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app> ... <!--chapter
6 -->
<servlet> <servlet-name>beanManaged</servlet-name> <servlet-class>examples.ejb.basic.beanManaged.Servlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>beanManaged</servlet-name> <url-pattern>/beanManaged*</url-pattern> </servlet-mapping> ... </web-app> 其中虚线表示在web.xml中注册的其它Servlets。 编辑完web.xml要重新启动服务器以使其生效。
3.运行测试
(1)测试Client 运行测试程序。继续使用前几个步骤使用的命令窗口,执行: C:\work\src\examples\ejb\basic\beanManaged>java examples.ejb.basic.beanManaged.Client
t3://127.0.0.1:7001/ 观察命令窗口的运行情况,如图5-11所示。
(2)测试Servlet
打开浏览器,在地址栏中输入http://127.0.0.1:7001/beanManage,回车。会出现如图5-12所示的页面。
|