您的位置:寻梦网首页编程乐园Java天地小龙亭之JSP实践之旅
 

EJB系列


_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
_/
_/ EJB系列 I
_/ -------前序                      作者:创
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

EJB系列,从今天开始将陆续和同大家见面了,

是认真的认知之后,
是刻苦和痛苦之后,
是求知和求实之后,
向大家奉献的又一力作,
希望能唤起我们已经沉寂已久的数字热情.

遥想当年,
我们摆弄DOS,截获中断,跟踪地址,
折腾WINDOW32,狂解IMG,
我们第一次看到HTML的神奇世界,
第一次在14寸中享受VCD的哪些热情岁月,
多么让人激动和怀念.

我们都已经更成熟,更稳重,
我们学会了压抑和掩饰内心深处的激情躁动,
真的就这样把那些激情岁月珍藏起来吗?

不!
我们应该将这股对计算机的强烈的爱,
转换成对她深刻的理解和审视,
做她最忠实的朋友和情人,
我们需要不断发掘她新的优点和潜力,
就象EJB,
这个我们在她身上寻找到的一块新的闪光点...

爱计算机,做弄潮儿,敢于做梦吧,只是不要失去热情...


_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
_/
_/ EJB系列 II
_/ ------- 一种比日本OL小姐更有魅力的东西
_/ 著者 创
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/


关于令我激动不已,废寝忘食的她,我不想再多说什么了,
就让我们进入她的世界,一览她神秘面纱后面的神奇吧,

她的名字就EJB.
早在她诞生与SUN的摇篮里时,她还是一只不被人注意的
丑小鸭,那时她有个不太响亮的名字,叫1.0.

当J2EE携着迅雷不及的声势让我们不知所措时,我们惊奇
的发现了她的身影,她美丽的容颜在J2EE的家族中是那么
夺目,象一朵绚丽的玫瑰让全世界无数的程序员拜倒在她
的石榴裙下,甘心甘愿的为她苦为她醉.

为什么,为什么她的美丽四射呢?

这还是要从WEB的成长史说起,早些年,当TCP/IP的驱动下
的INTERNET出现时,我们着实激动了许久,在浏览器中游历
了整个世界,我们是当代的马可波罗.然而,我们都知道
那只是一个HTML画面的重复和拷贝.我们渴望能与之交流.
这种动态的HTTP梦想后来被一个叫CGI的人给实现了,我们
欢呼雀跃,但是每一次呈现给我们色彩斑斓的代价是在服务器
上阵痛般生出一个新的进程.

这是这昂贵的代价终于给微软以可趁之机,适时推出了他
功能强大的ASP,利用服务器上的ASP解释引擎,疯狂的产生着
无数的美丽的梦.更有ISAPI捆绑在IIS上,让我们领略他的
风弛和电掣.这个机器从开始运转的那一天,就开始把我们兜
里大把的钞票公然的掠走了...

直到那一天,JAVA的身影出现了,虽然,对新事物天生的恐惧感,
让我们迟迟不感接受她,虽然,Applet仍然慢如牛的在网络
上拱着.但她的WEB端同仁Servlet却吓了我们一跳,良好的
响应速度,优良的运行性能和惊人的可移植性都给我们耳目
一新的感觉,JAVA的兼容性更让他上可入天,下可如地,在
各个操作系统上一展身手,他的孪生兄弟JSP更给我们提供
了无限的想象,发挥的余地.

到此为止,我始终以为应该告一段落了,至少是有个短暂的
停歇了.但SUN,这个善于制造惊奇的梦幻工厂又抛给我们
一个重磅炸弹----J2EE.

这个为企业量身定做的JAVA版本,带给我们更多的挑战,
我们的眼界也豁然开朗,我们发现原来确实有那么多地方
是可以做的更好的,更快的,更完美的.

这其中最耀眼的明星就是我们千呼万唤始出来的EJB,
到这里,你已经等的很不耐烦了吧?
好,那就请在无比焦急的期待中,
等待她的登场吧,当然,
这是下次的事情了,
哈哈哈哈~~~~~~~~~~~~~!
下次再见;)


_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
_/
_/ EJB系列 III
_/ -------无废话EJB
_/ 著者 创
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

EJB,
是企业JAVA BEAN的缩写,关于她,我已经贫够了,这里,
想跟大家谈谈一些实质的问题,不再浮于表面的说套话了.

================
为什么要使用EJB?
================

EJB最大的诱人之处是她把应用程序和服务器分开了,
我们再也不用和那些服务器上的复杂的资源打交道了,
什么数据库,什么进程,线程,什么安全权限,什么套接字,
都见鬼去吧,我们只需要专著于我们的商业逻辑的实现了.

==========
EJB的实质?
==========

EJB实际上是SUN的J2EE中的一套规范,并且规定了一系列的
API用来实现把EJB概念转换成EJB产品.
EJB是BEANS,BEANS是什么概念,那就是得有一个容纳她,
让她可劲造腾的地方,就是得有容器.EJB必须生存在EJB容器中.
这个容器可是功能强大之极!她首先要包装你BEAN,
EJB的客户程序实际上从来就不和你编写的EJB直接打交道,
他们之间是通过HOME/REMOTE接口来发生关系的.
它负责你的BEAN的所有的吃喝拉萨睡,
比如BEAN的持续化,安全性,事务管理...

=============
EJB服务器产品
=============

各个WEB服务器开发商基本上都在他们WEB服务器中
新捆绑了EJB容器,或者叫EJB服务器.
其中最简单也是最根本的是J2EE开发环境带的J2EE的EJB容器,
它很好的和J2EE的HTTP服务器和Servlet引擎一起构筑了
一个很好的运行环境,由于配置简单,功能强大,因此成为我的最爱.
另外象BEA的Weblogical是值得推荐的一个产品,它的WEB服务器
功能相当强大,是当今很多网站构筑的理想WEB服务器,
它也已经加入了EJB的行列,在EJB方面有着不俗的表现.
Inprise的IAS更是一个功能强大的WEB服务器,同样,也嵌入了
EJB容器,加之与本公司的JBuilder的无接缝结合,更使它人气攀升.
还有象IBM的WebSphere也不错,
不过Apache是否已经搭载了EJB容器,我不太清楚.
另外,推荐一个EJBoss,是一个完全免费的EJB服务器,而且是原代码公开的.
还有,据说深圳的一个国产计算机超超高高手已经独自开发出一个EJB服务器,
啊,太酷了,鸭真他妈是个天才,天才,天才啊!啊!啊!

========================
EJB容器如何包装你的BEAN.
========================

这年头没有天上掉馅饼的好事情,EJB也不例外,
你想让EJB容器替你管理你编写的EJB的吃喝拉萨睡,凭什么?!
凭XML描述子,你通过一个XML文件告诉EJB容器BEAN的相关配置信息,
比如我的EJB的HOME接口和REMOTE接口是哪一个类,
比如我的EJB的别名(实际上是JNDI名称)叫什么,
比如我的EJB是否是实体类型的EJB还是对话类型的EJB,
比如告诉容器替我管理我的实体EJB中哪些自段,
......
总之,你得跟咱们的EJB大总管----EJB容器把所有都交代清楚.
这样,剩下的,就看EJB容器的了!!!
你是不是总共写过3个文件,BEAN定义,HOME接口定义,ROMOTE接口定义,
当你DEPLOY他们时,容器会
(1).首先根据HOME和REMOTE接口生成他们的实现代码,
我们不妨叫做HOME_IMPL和REMOTE_IMPL,
(2).然后,利用RMIC产生HOME_IMPL和REMOTE_IMPL的
STUB和SKELETON文件,2X2一共生成4个文件.
(STUB和SKELETON请参见RMI的相关概念)
如此这般,最后,在服务器上,一共有
BEAN
HOME_IMPL
REMOTE_IMPL
HOME_STUB
HOME_SKELETON
REMOTE_STUB
REMOTE_SKELETON
7文件,才能让EJB工作起来.
(3).生成实体EJB对应的数据库的库表
(4).注册你的EJB到JNDI服务

===============================================================
为什么除了写BEAN,还得写接口文件,而且干嘛要HOME和REMOTE两个接口.
===============================================================

我搅着吧,这两个接口完全是可以合并成一个接口的,
其实他们的作用都只是一个接口,为了让
那人家SUN干吗还拆成两个呢?
我想,正如SUN所说的,为了将一些容器相关操作和客户商业方法分开,
什么意思?说开了吧,HOME用来规范容器相关的操作方法,
REMOTE负责专心致志的定制商业方法,
而我们的BEAN才是最终的逻辑实现者.
还是不明白?没关系,我在说的细些,
举例说明:
把我想象成一个BEAN,
HOME接口就是我们家人的命令,
REMOTE接口就是我们单位的领导的命令,
我们家人的命令决定了我如何吃喝拉萨睡,
领导的命令决定了我如何做一些真正的工作,
请注意这里我使用了"决定"这个字眼,
我并没有说我们家人,而是说了我们家人的命令,
这个命令的含义就是接口,不是类,
而我这个BEAN却是个类!
还有,BEAN类不实现REMOTE和HOME接口,
记住!记住!记住!记住!记住!记住!记住!记住!
如果说你不明白,我立刻扑上去扇你一个大嘴巴,
当你气急败坏的骂我时,我也只会指指上面的,
"我已经讲过了,自己再去看看吧!".

=========
EJB的分类
=========
EJB分为实体(Entity)EJB和对话(Session)EJB,

>>>>>>实体EJB:<<<<<<<

就是用来代表数据的EJB,他对应数据库中的一张库表,
他的的PUBLIC变量对应库表中的一个字段,他的一个实例对应
库表中的一行数据,我靠!激动了吧,多年来对象到数据库的影射
就这样被EJB实现了,oh,my GOD,我太爱EJB了!
哪?什么时候和如何来执行这些影射呢?
问的好,我就喜欢别人这么问我,
把我问死是我最大的享受,在回答问题这一点上我确实有些自虐倾向;)
什么时候?
不用你管,容器自己知道什么时候把你的类实例转化成数据库
中的一行数据,知道什么时候更新这行数据,当你的实例发生变化的时候,
而且,不仅如此,BEAN中还可以重载javax.ejb.EJBBean接口的一系列
方法,比如ejbCreate(),ejbLoad(),ejbRemove()方法来让EJB容器回调,
说白了就是提供这些实践响应函数让BEAN开发者可以参与BEAN管理.
如何来完成影射呢?
是由事先准备好的SQL语句来完成这个影射的,这就引出了实体EJB的
两种分类:
a.容器管理序列化
容器来完成执行SQL来完成EJB实例到数据库数据的影射,
当然这些SQL要在XML描述子中提前写好.
b.BEAN自管理序列化
在刚才说的诸如ejbCreate()一系列BEAN活动的事件响应中,
由BEAN开发者来完成SQL语句的执行,来完成EJB实例到数据库数据的影射
当然这些SQL要写在程序中.

>>>>>>>对话EJB<<<<<<<

对话EJB根本根本不和数据库打交道,为什么,因为他根本不用序列化!
他只负责来完成一些逻辑操作,比如算个帐什么的.
为了和实体EJB较劲,他也一口气生了两个儿子,
a.有状态(sessionful)对话EJB
他就跟servlet中的session对象似的,可以保存用户的session相关信息,
而且他仅仅被一个用户的一次session所使用,不和别人共享,
我管他叫对话,不过这"对话"翻出来
这是够难听的,还不如就叫他session呢!
b.无状态(sessionless)对话EJB
这个东东是最简单的EJB,他是可以被多个用户共享,
注意!我所说的共享是指实例的共享!


======================================
一个BEAN管理持续化的实体EJB(BMP)小例子
======================================

说了半天了,大家珍贵的脑资源恐怕被我消耗的差不多了,
好,让我们来剖析一个BEAN管理持续化的实体EJB(BMP)吧.

-----------------------看看REMOTE接口------------------------------
public interface Account extends EJBObject {//必须从EJBObject继承
//这些都是商业方法,而且这里写了的,必须在BEAN中都实现
public void deposit(double amt) throws RemoteException;
public double withdraw(double amt) throws AccountException, RemoteException;
public double getBalance() throws RemoteException;
public String getOwnerName() throws RemoteException;
public void setOwnerName(String name)throws RemoteException;
}

-------------------------看看HOME接口---------------------------------
public interface AccountHome extends EJBHome {
//这声明了create函数,由于是BMP,所以必须在BEAN中实现一个叫ejbCreate的对应函数
Account create(String accountID, String ownerName) throws CreateException, RemoteException;

//按主键查询
//由于是BMP,所以必须在BEAN中实现一个叫ejbFindByPrimaryKey的对应函数
public Account findByPrimaryKey(AccountPK key) throws FinderException, RemoteException;

//按其中的Name字段查询
//由于是BMP,所以必须在BEAN中实现一个叫ejbFindByOwnerName的对应函数
public Account findByOwnerName(String name) throws FinderException, RemoteException;
}

---------------------------看看BEAN-----------------------------------
public class AccountBean implements EntityBean {
//三个PUBLIC字段,他们将来对应库表的三个字段
public String accountID
public String ownerName;
public double balance;

//----HOME中声明的create方法的影射实现
//由于是BMP,所以必须自己来负责实例创建时实例到数据库的影射
public AccountPK ejbCreate(String accountID, String ownerName) throws CreateException, RemoteException {
PreparedStatement pstmt = null;
Connection conn = null;
try {
this.ownerName = ownerName;
this.balance = 0;
conn = getConnection();
pstmt = conn.prepareStatement("insert into accounts (id, ownerName, balance) values (?, ?, ?)");
pstmt.setString(1, accountID);
pstmt.setString(2, ownerName);
pstmt.setDouble(3, balance);
//看这里,看这里!插进去了... 
pstmt.executeUpdate();
return new AccountPK(accountID);
}catch (Exception e) {
throw new CreateException(e.toString());
}finally {
try {
pstmt.close();
conn.close();
}catch (Exception e) { }
}
}

//----HOME中声明的findByOwnerName方法的影射实现
//由于是BMP,所以必须自己来完成按照Name字段查找的工作
public AccountPK ejbFindByOwnerName(String name) throws FinderException, RemoteException {
PreparedStatement pstmt = null;
Connection conn = null;
try {
conn = getConnection();
pstmt = conn.prepareStatement("select id from accounts where ownerName = ?");
pstmt.setString(1, name);
//看看看!找上了,根据名称...
ResultSet rs = pstmt.executeQuery();
rs.next();
String id = rs.getString("id");
pstmt.close();
conn.close();
return new AccountPK(id);
}catch (Exception e) {
throw new FinderException(e.toString());
}finally {
try {
pstmt.close();
conn.close();
}catch (Exception e) { }
}
}

//----REMOTE中声明的一个方法的实现
//这是一个商业方法,来完成帐户的存款查询
public double getBalance() {
System.out.println("[AccountEJB-getBalance]getBalance() called.");
return balance;
}

.......其他的方法,由于篇幅问题就不一一列出了,请大家参阅原代码!
}

今天,敲了一夜,自己感觉终于把EJB跟大家交代清楚了,
挺难理解的是吧,抽象是吧,没关系!慢慢来!
我也是经过了一个多月的学习和理解才慢慢接收了这一切,
而且逐渐喜欢上了她的.
只要用心的全心全意的去热爱她,
她会给你带来无限的欢乐的!
相信我,没错的:)

于东京时间2000年0时34分伴随着电视里嘈杂的不知名的音乐声,完成...

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
_/
_/ EJB系列 VI
_/ ------- EJB的网上商店
_/ 著者 创
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/


========================================================
需求分析
========================================================
一个商店,一个网络上的商店如何运作的呢,首先让我们想象一下,
就拿我为例吧,首先,我要在银行有个帐号并且存入一定现金.
然后我便欣然前往网上商店了,

..注册画面
首先是登录界面,让我输入用户名和保密字,我没有啊!
只好先去注册主页注册一个商店的用户信息.
我输入用户名和保密字以及保密字确认和地址以及一些额外信息,
然后就提交了.

..登录画面
我使用我刚刚注册的用户名和保密字登录,成功.

..WEB商店主画面
我看到WEB商店的主画面,里面包含两个连接,
1.去货物架去看看 ; 2.看看购物车
当然购物车没什么好看的,什么都没有,
那好就去货物架去看看

..货物架画面
列出了所有的商品名和价格和"决定买"的字样,
###########货物名,价格,决定买###########
###########货物名,价格,决定买###########
###########货物名,价格,决定买###########
点击货物名就进入货物介绍画面
点击决定买就把货物加入了购物车

..货物介绍画面
货物的详细介绍,好包括一个"决定买"的字样,
点击它就会把货物加入购物车

..购物车画面
买啊买,买啊买,
突然决定去看看购物车了,
点击货物架画面中的购物车链接,
就来到购物车画面,
购物车包含了你的以下信息,
买的各个货物的名称,数量,价格,税,折扣,
下面还有一行还有总的付款额
最后,有几个按钮,
"更新数量",用来即时更新要买的货物的数量,可增加可减少.
"买",一按它就会完成买的整个过程,
然后切换到买完的画面

..买完的画面
告诉你已经从你的帐户中把钱拨到商店的帐户中了,
并且告诉你会按照你登录时填写的地址将货物发过去.

这时候,买的全过程结束,但你还可以不用登录而返回WEB商店,
但你的购物车已经空了.

========================================================
数据和逻辑设计
========================================================

###########
一.数据设计
###########

说明一点,由于采用了EJB的实体EJB类型,所有的数据都封装
到实体EJB中,因此数据设计就成了EJB的设计.
这里可以抽象出来以下数据实体即实体EJB:

数据(实体EJB)一览
-----------------
AccountEJB 帐户信息 
CustomerEJB 用户信息 
ProductEJB 产品信息 
OrderEJB 帐单信息 
OrderLineItem 代表帐单中的一种货物信息

###############
二.用户界面设计
###############

这里的用户界面实际上都是HTML的界面,
他们都是由servlet完成了,

M,modual,就是把用户的应用抽象化成各个模块,
V,view,就是用户界面
C,control,就是进行逻辑控制
这里,WEB商店的设计中很充分的体现了这一设计思想,
M,就是

画面(servlet)一览
-----------------
注册画面 RegistServlet
登录画面 LoginServlet 
WEB商店主画面 WebStorefrontServlet
货物架画面 CatalogServlet
货物介绍画面 ProductDetailServlet.java
买完的画面 PurchaseServlet

###############
三.逻辑控制设计
###############

主要由对话EJB和链接来完成.
对话EJB(session EJB)主要完成一些逻辑处理,
例如使用TellerEJB来完成转帐功能,

对话EJB一览
-----------
PricerEJB 用来计算税呀,折扣什么的
QuoteEJB 代表购物车,用来完成购物过程
QuoteLineItem 代表购物车中的一种货物
TellerEJB 银行出纳员,完成转帐功能

当然各个Servlet中也包含一些逻辑控制跳转和处理,
但都比较简单,不值得一提了,请自己参阅原代码.

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
_/
_/ EJB系列 V
_/ ------- EJB的网上商店目录及文件说明
_/ 著者 创
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/

〈ws(web store)〉
|
|
|----〈deploy〉
| |
| |----Deploy信息
|
|----〈serlvet〉
| |
| |----AddAccount.java 为要购物的用户在银行开一个户头
| |----AddProductServlet.java 为WEB商店添加货物
| |----RegistServlet.java 注册WEB商店的用户
| |----LoginServlet.java 登录
| |----WebStorefrontServlet.java WEB商店的主画面
| |----CatalogServlet.java 商品一览,货架
| |----ProductDetailServlet.java 商品详细信息
| |----ShowQuoteServlet.java 购物车一览
| |----PurchaseServlet.java 买
|
|----〈ejb〉 *代表实体EJB
| |
| |----〈Account*〉 帐户EJB
| | |
| | |----Account.java Remote接口定义
| | |----AccountBean.java Bean的实现
| | |----AccountHome.java HOME接口定义
| | |----AccountPK.java 实体EJB使用的主键类
| | |----AccountException.java 异常类
| | 
| |----〈Customer*〉 客户EJB
| | |
| | |---....基本上同上,只是类名不一样而已
| |
| |----〈Order*〉 定单EJB
| | |
| | |---....同上
| |
| |----〈OrderLineItem*〉 定单中的一种商品
| | |
| | |---....同上
| |
| |----〈Product*〉 商品EJB
| | |
| | |---....同上
| |
| |----〈Quote〉 购物车处理EJB
| | |
| | |---....同上
| |
| |----〈QuoteLineItem〉 购物车中的一种商品处理EJB
| | |
| | |---....同上
| |
| |----〈Teller〉 出纳员处理EJB
| |
| |---....同上