第 3 章 EJB 技术进阶
3.3 EJB 开发实例 封装数据源
第 3 章 EJB 技术进阶
// executeFindAll() method in this class.
} }
不知道读者发现没有 程序清单3.13 和程序清单 3.6 其实是一模一样的 这说明了一 个问题 那就是CMP EJB 的客户端与 BMP EJB 的客户端程序并没有实质上的区别 尽管 服务端的实现方法可能不一样 但是所对应的客户端程序却是一样的 这也是分布式处理 的好处之一 服务端可以改变服务实现的方法 但是只要提供服务的接口没有变化 客户 端的程序就不需要变化
3.2.8 运行和测试
下面我们按照3.1.8 小节的方法运行 Goods EJB(BMP 模式下)的服务端与客户端程序 客户端程序(GoodsTestClient.java)的输出结果如下所示
name:小楼一夜听春雨 type:兵器
id:22 price:3000.8 off:0.8
comment:小楼一夜听春雨 深巷明朝卖杏花 好优美的诗意啊 可惜它是一把弯刀 又名圆月弯刀 曾经是青青所用之物 后归丁鹏所有 和万水青山踏遍齐名
is session ejb:false
至于服务端的输出结果读者可以参照3.1.8 小节的结果
3.3 EJB 开发实例 封装数据源
在这一节中 我们将在3.2 节的基础上 对 Goods EJB 进行改写 实现动态查询的功 能 实际上 这就相当于完成了封装数据源的功能 因为在3.2 中 我们已经可以利用 Goods EJB 完成插入新纪录 更新行纪录 删除行纪录 返回特定行纪录的功能 现在再加上动 态查询的功能 那么一个数据源的功能也就全了 我们为什么不在 3.1 小节的基础上进行 再开发呢 这是因为 3.1 小节开发的是 CMP 模式的 Goods EJB 要扩充起来很困难 3.2 小节开发的是BMP 模式的 Goods EJB 扩展起来容易得多了
那么如何扩展BMP 模式的 Goods EJB 呢?
首先需要修改GoodsBeanBMP.java 程序 定义一个执行动态查询的方法 这个方法的 名字是ejbFindAll(String name) 它的主要作用是查询 goods Table 的 comment 字段 返回 所有符合条件的Goods EJB 对象的集合 ejbFindAll(String name)方法其实是从 ejbFindAll() 方法改写过来的 请看程序清单3.14(GoodsBeanBMP.java) 其中黑体部分就是我们在程序 清单3.10 的基础上加进去的代码
程序清单 3.14
//File Name:GoodsBeanBMP.java //Author:Fancy
//Date:2001.5
第一部分 JSP 技术与 J2EE 技术
//Note:the EJB Class
package jdbcbean;
import java.sql.*;
import javax.ejb.*;
import javax.sql.DataSource;
import java.util.*;
public class GoodsBeanBMP extends GoodsBean {
DataSource dataSource;
public int ejbCreate(String goodsname String goodstype String comment Double price Double priceoff int id) throws CreateException
{
super.ejbCreate(goodsname goodstype comment price priceoff id);
try {
//First see if the object already exists ejbFindByPrimaryKey(id);
//If so then we have to throw an exception
throw new DuplicateKeyException("Primary key already exists");
}
catch(ObjectNotFoundException e) {
//Otherwise we can go ahead and create it...
}
Connection connection = null;
PreparedStatement statement = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("INSERT INTO goods (goodsname goodstype comment price priceoff id) VALUES (? ? ? ? ? ?)");
statement.setString(1 goodsname);
statement.setString(2 goodstype);
statement.setString(3 comment);
statement.setDouble(4 price.doubleValue());
statement.setDouble(5 priceoff.doubleValue());
statement.setInt(6 id);
if (statement.executeUpdate() != 1) {
throw new CreateException("Error adding row");
(goodsname goodstype comment price priceoff id) VALUES
(? ? ? ? ? ?): " + e.toString());
public int ejbCreate(int id) throws CreateException {
return ejbCreate(null null null null null id);
}
public void ejbRemove() throws RemoveException {
statement = connection.prepareStatement("DELETE FROM goods WHERE id = ?");
id = ((Integer) entityContext.getPrimaryKey()).intValue();
Connection connection = null;
PreparedStatement statement = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT goodsname goodstype comment price priceoff FROM goods WHERE id = ?");
statement.setInt(1 id); goodstype comment price priceoff FROM goods WHERE id = ?: "
+e.toString());
statement = connection.prepareStatement("UPDATE goods SET goodsname
= ? goodstype = ? comment = ? price = ? priceoff = ?
public int ejbFindByPrimaryKey(int key) throws ObjectNotFoundException {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT id FROM goods WHERE id = ?");
throw new ObjectNotFoundException("Primary key does not exist");
}
public Collection ejbFindAll() {
statement = connection.prepareStatement("SELECT id FROM goods");
ResultSet resultSet = statement.executeQuery();
public void setEntityContext(EntityContext entityContext) {
super.setEntityContext(entityContext);
try {
javax.naming.Context context = new javax.naming.InitialContext();
dataSource = (DataSource)
public Collection ejbFindAll(String name) {
statement = connection.prepareStatement("SELECT id FROM goods where comment like ?");
statement.setBytes(1 name.getBytes("GBK"));
ResultSet resultSet = statement.executeQuery();
Vector keys = new Vector();
goods: " + e.toString());
}
ejbFindAll(String name)方法的实现逻辑很简单 关键之处在于构造 SQL 语句 以及根 据方法参数(name)设定 SQL 语句的输入参数 还需要注意数据库的中文问题 此外就没有 什么特别的了
下 面 我 们 需 要 修 改 Goods EJB 的 Home Interface 在 Home Interface 中 声 明 ejbFindAll(String name)方法 修改过的 Home Interface 的源代码如程序清单 3.15 所示 其 中黑体部分是我们添加上的代码
程序清单 3.15 package jdbcbean;
import java.rmi.*;
import javax.ejb.*;
第一部分 JSP 技术与 J2EE 技术
import java.util.*;
public interface GoodsHome extends EJBHome {
public GoodsRemote create(String goodsname String goodstype String comment Double price Double priceoff int id) throws RemoteException CreateException;
public GoodsRemote create(int id) throws RemoteException CreateException;
public GoodsRemote findByPrimaryKey(int primaryKey) throws RemoteException FinderException;
public Collection findAll() throws RemoteException FinderException;
public Collection findAll(String name) throws RemoteException FinderException;
}
我们把整个Project 再编译一遍 就可以运行 Goods EJB 的服务端了 下面我们应该编 写新的Goods EJB 的客户端了 这是基于 Java Application 的客户端 基于 JSP 的 EJB 客户 端我们就不介绍了 读者可以把前者改写一下就行了 请看程序清单 3.16 其中黑体部分 是我们在JBuilder4 自动产生的代码的基础上添加的代码
程序清单 3.16 package jdbcbean;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import java.util.Collection;
import java.util.Iterator;
public class GoodsTestClient {
private static final int MAX_OUTPUT_LINE_LENGTH = 50;
private GoodsHome goodsHome = null;
/**Construct the EJB test client*/
public GoodsTestClient() {
try {
//get naming context
Context ctx = new InitialContext();
//look up jndi name
Object ref = ctx.lookup("Goods");
//cast to Home interface goodsHome = (GoodsHome)
PortableRemoteObject.narrow(ref GoodsHome.class);
第 3 章 EJB 技术进阶
GoodsRemote gr=goodsHome.findByPrimaryKey(22);
System.out.println("name:"+gr.getGoodsname());
System.out.println("type:"+gr.getGoodstype());
System.out.println("id:"+gr.getId());
System.out.println("price:"+gr.getPrice());
System.out.println("off:"+gr.getPriceoff());
System.out.println("comment:"+gr.getComment());
System.out.println("is session ejb:"
System.out.println(collection.size());
while (iterator.hasNext()) {
Object object = iterator.next();
GoodsRemote goodsRemote = (GoodsRemote) PortableRemoteObject.narrow(object GoodsRemote.class);
System.out.println("name:"+goodsRemote.getGoodsname());
System.out.println("type:"+goodsRemote.getGoodstype());
System.out.println("id:"+goodsRemote.getId());
System.out.println("price:"+goodsRemote.getPrice());
System.out.println("off:"+goodsRemote.getPriceoff());
System.out.println("comment:"+goodsRemote.getComment());
} }
public void executeFindAll() {
if (message.length() > MAX_OUTPUT_LINE_LENGTH) {
System.out.println("-- "
+ message.substring(0 MAX_OUTPUT_LINE_LENGTH) + " ...");
}
GoodsTestClient client = new GoodsTestClient();
client.find();
// Use the getHome() method of the client object to call Home interface
第 3 章 EJB 技术进阶
// methods that will return a Remote interface reference. Then // use that Remote interface reference to access the EJB.
// For quick access to all available records you can use the // executeFindAll() method in this class.
} }
在程序清单3.16 中 我们仿照 executeFindAll()方法 定义了一个 find()方法 在 find() 方法体中 利用了Home Interface 调用 findAll()方法 然后再对返回的结果集进行处理 程序清单3.16 十分简单 我们就不多做解释了 程序清单 3.16 的运行输出如下所示
name:小楼一夜听春雨 type:兵器
id:22 price:3000.8 off:0.8
comment:小楼一夜听春雨 深巷明朝卖杏花 好优美的诗意啊 可惜它是一把弯刀 又名圆月弯刀 曾经是青青所用之物 后归丁鹏所有 和万水青山踏遍齐名
is session ejb:false 1
name:小楼一夜听春雨 type:兵器
id:22 price:3000.8 off:0.8
comment:小楼一夜听春雨 深巷明朝卖杏花 好优美的诗意啊 可惜它是一把弯刀 又名圆月弯刀 曾经是青青所用之物 后归丁鹏所有 和万水青山踏遍齐名
好了 关于Goods EJB 的开发我们就介绍到这里 至于如何分发 Goods EJB 到应用程 序服务器上 如何编写Entity EJB 的 JSP 客户端 请读者参考第 2 章的相关内容 限于篇 幅 我们就不多说了 说到这里 想必读者对于EJB 的强大功能及其开发方法已经有了一 定程度的了解 但是EJB 的技术体系博大精深 不是我们这两章书就能够概括的了的 读 者如果希望对EJB 技术有进一步的了解 关键之处在于多加练习 还需要多参考相关的英 文文档
3.4 本 章 小 结
本章主要介绍了两种Entity EJB 的开发方法 并比较了它们的异同 这两种 Entity EJB 分别是CMP 模式的 Entity EJB 与 BMP 模式的 Entity EJB 本章的第三节 改写了 Goods EJB 使得它封装了JDBC 数据源的功能
在第4 章中 我们将介绍 RMI CORBA JNDI 等技术在 JSP 程序中的应用