关键词 数据库;J2EE; EJB;WebLogic
引 言
随着科学技术的不断提高,计算机网络的功能已为人们深刻认识,它已进入人类社会的各个领域并发挥着越来越重要的作用。同样各类学校的校园网也运行了多个年头,但还有不少学校的管理系统缺少统一规划,单机运行的信息孤岛还为数不少,所以有必要进一步研究在校园网环境下合理利用原有异构数据库建立相关部门的管理系统的方法。
在某高校中教务和教材仓库都已经有了各自独立的数据库管理系统,但教材选订等工作都是人工进行,工作人员的劳动量,效率很低。校园网环境下利用现有的资源建立教材综合管理系统之必要性是不言而喻的!本文介绍基于WebLogic应用服务器进行教材综合管理系统的设计和实现的过程。
系统结构
系统包含教材选取、查询、修改、订购子系统,系统所需的教务信息和教材库存信息来自网上原有数据库,如图1所示。其中,教研室通过B/S模式可以进行教材选取、查询、修改等工作,教材管理在教材委员会通过C/S模式本地完成,主要是教材订购及系统管理工作。
![](http://www.yesky.com/image20010518/175629.gif)
1、数据库设计
其中数据库系统中包含教务处数据库(旧)、仓库数据库(旧)和教材委员会数据库(新),充分利用了原有的资源达到共享数据的目的,用到的表有教务处的课程安排表、专业人数表,仓库的库存量表。
教务处专业人数表:
列名 | 数据类型 | 长度 | 允许为空 |
id | Bigint | 8 | 否 |
num | int | 4 | 是 |
教务处课程安排表:
列名 | 数据类型 | 长度 | 允许为空 |
id | Bigint | 8 | 否 |
cid | Int | 4 | 否 |
cname | Varchar | 50 | 是 |
teachunit | Varchar | 50 | 是 |
sname | Varchar | 50 | 是 |
仓库库存量表:
列名 | 数据类型 | 长度 | 允许为空 |
bid | Int | 4 | 否 |
bname | Varchar | 50 | 是 |
bnote | Varchar | 50 | 是 |
bauthor | Varchar | 50 | 是 |
bpublisher | Varchar | 50 | 是 |
bprice | Float | 8 | 是 |
bnum | Int | 4 | 是 |
教材委员会对教材的选定、订购进行统一管理,它拥有一个本地数据库即教材委员会数据库,在这个新进的数据库中有三张表,一张用于教材选定后的数据的存储,一张用于订单的内容的存储,第三张是教研室登陆密码的信息存储。
选教材表:
列名 | 数据类型 | 长度 | 允许为空 |
cid | Int | 4 | 否 |
bid | Int | 4 | 是 |
cname | Varchar | 50 | 是 |
bname | Varchar | 50 | 是 |
teachunit | Varchar | 50 | 是 |
订单表:
列名 | 数据类型 | 长度 | 允许为空 |
id | Bigint | 8 | 否 |
bname | Varchar | 50 | 是 |
numneed | Int | 4 | 是 |
密码表:
列名 | 数据类型 | 长度 | 允许为空 |
teachunit | Varchar | 50 | 否 |
pw | Char | 10 | 是 |
它们都是J2EE中的底层结构,WebLogic应用服务器层把底层数据库连接起来需要配置数据池和数据源。
2、数据池和数据源配置
由于数据库系统中有三个数据库,所以进行WebLogic连接池配置时需要配置三个连接池,这里进入WebLogic的控制台页面,以配置的第一个连接池,教务数据库连接池(如图2)为例。其中最为关键的是在URL和Driver中运用对应数据库类别的驱动,并填写要访问的数据库名称,数据库服务器的地址和端口。
![]() 图2 连接池配置 |
仓库数据库的URL为:“jdbc:oracle:CK:@localhost:1521”
Driver为:“oracle.jdbc.drive.OracleDriver”
教材委员会的URL为:“jdbc:weblogic:mssqlserver4:Teachingmanagement@10.10.11.81:1057”
Driver为:“weblogic.jdbc.mssqlserver4.Driver”
然后配置数据源,根据数据池名,定义数据源的JNDI名。这样就把分布在不同地域的三个数据库在WebLogic中连接起来,并成功屏蔽了数据库软件的类别、版本、地域等差别,其中教务处数据源配置如图3:
![]() 图3 数据源配置 |
3、建立实体EJB
系统要对三个异地数据库共六张表,进行操作,因此要逐个引进并建立相应的实体Bean,这里将三个数据库中本系统要用到的的表都引进到同一个EJB Module中。
在JBuilder中生成的实体Bean中会自动识别并生成对应表的名称,数据段的名称、属性,根据程序员设置的本地或远程的home接口文件,封装了操作数据库的基本动作,如通过主键查找记录的功能,在查找到的记录中得到和设置数据项的函数等,为了后面子系统的需要还要添加一些函数:
在课程安排表Entity Bean中添加两个Finder:
一个finder名为findall,功能是得到教务数据库课程安排表的所有信息。将要在往选教材表中写入所有课程信息时使用。
另一个名为findbycid,功能是根据输入的课程信息找到选了这些课程的专业。
在选教材表中添加两个Finder:
一个名为findall,为了得到所有的选教材表的信息。
另一个名为findbybid,功能是得到输入教材号所对应的专业好。
在Baobiao中添加一个Finder为 findall,得到所有订单表里的信息。
这样就完成了本系统实体bean的建立。
4、建立会话EJB
使用会话bean 可对某一客户的处理或控制对象建模,对工作流、任务和管理活动等建模,协调多个实体bean,控制实体bean之间的交互将业务应用逻辑从客户端转移到服务器端,本系统考虑到数据不是特别庞大。仅用了具有远程接口的一个无状态会话EJB(connectEJBs)完成所有与实体EJB打交道的任务。
为了系统功能的需要,在其中添加了6个私有变量,6个公有变量,初始化后用以访问六张表对应的实体EJB。初始化代码为:
try{ Context context=new InitialContext(); Object ref=context.lookup("java:/comp/env/Coursearrangement"); crthome=(CoursearrangementHome) ref; ref=context.lookup("java:/comp/env/Xk"); xkhome=(XkHome) ref; ref=context.lookup("java:/comp/env/Tp"); tphome=(TpHome) ref; ref=context.lookup("java:/comp/env/Number"); numberhome=(NumberHome) ref; ref=context.lookup("java:/comp/env/Ck"); ckhome=(CkHome) ref; ref=context.lookup("java:/comp/env/Baobiao"); baobiaohome=(BaobiaoHome) ref; }catch(Exception e){e.printStackTrace();} |
这样就能通过会话EJB的远程接口访问实体EJB里自动生成的和自己添加的方法或函数了,前提是这个方法或函数包含在实体EJB的home接口里。
还添加了一些本地公有函数和多个远程公有函数,用来修改或访问实体EJB并作初步的处理。增加的函数必须在JBuilder中先右击代表会话Bean的图形添加方法(add method),设置各项参数后方可右击会话Bean选择View Bean Sourse菜单,进入代码区编辑方法主体,否则工程将产生编译错误。这里提供了整个系统所需的与数据库打交道的函数,这些接口在后文中都有用到。
3个本地公有函数:为了解决不能连续在同一个函数里多次写入信息而独立出来的函数
①public void writecidcname(Integer cid, String cname, String teachunit)
这是往选教材表写课程信息。
②public void writebook(Integer bid, String bname)
这时保教材信息写入订单表。
③public void writealltp(String unit, String pw)
同理,为了往密码表里写入密码信息而编写。
远程公有函数:以下的函数是订单子系统要用到的接口
⑴public java.util.Collection couinfo()
这个函数是负责从教务处得到开设课程的信息。返回值是Collection对象。
⑵public boolean writexk(java.util.Collection rst)
这个函数在运行订单子系统自动调用。它负责在初始化系统时将从教务处得到的课程信息写进选教材表中,保证既使新增了新的教研室也能实时地获得。它的参数就是函数zhuanyi()的返回值,在程序主体调用了本地函数①。
⑶public java.util.Collection selectunit()
这个函数是为了从选教材表中得到所有开设了课程的教研室的名称。既为了在B/S的登录界面上得到教研室名下拉框的需要,又为了在密码表中得到教研室名而编写。注意这里有重复信息,需要再调用它的函数中过滤掉。
⑷public boolean writetp(Collection rst, String pw)
这是为了建立教研室密码表而编写,在函数⑵后调用,当表中没有教研室或是有了新的教研室的时候,它会自动加到密码表中并分配原始密码。是教员能登陆再现的教材录入子系统。
⑸public boolean reflushbaobiao()
这是C/S界面用户刷新订单信息时,将选教材表中的已经选了的教材信息写进订单表中。它在获得相应教材应定的数量之前调用。
●这以下是为了获得订单中所需要订购的书的数目而写的函数,因为不能在一个函数中操作多个数据库,所以用了下面多个函数以实现。
得到订单表里所有的教材号:
public Collection readbaobiaoforgetnum() |
从选教材表中得到已经选好的课本对应的课程号:
public Integer readxkforgetnum(Integer bid) |
再从教务处课程安排表中得到开了这个课程号所代表的课程的专业,可能不止一个:
public Collection readcouforgetnum(Integer cid) |
然后从教务处人数表中查到这些专业的人数:
public Integer readnumforgetnum(Long id) |
再找出仓库里这本书的库存量,如果所需数量大于库存量,就要在订单中显示出定购量:
public Integer readckforgetnum(Integer bid, int numall) |
○●○此以下的函数为教员在线教材选取和相关单位查询要用到的函数。
⑴public String login(String unit)
这在用户登陆时系统检查密码是否匹配时使用,就是根据用户名查询到相应的密码并返回。在用户修改密码时验证是否为登陆用户也用到了它。
⑵public String login(String unit)
这个函数从名字得知,是用户登陆时系统检查密码是否匹配时使用的,就是根据用户名查询到相应的密码并返回。在用户修改密码时验证是否为登陆用户也用到了它。
⑶public boolean writein(Integer cid, Integer bid, String name)
这个函数是用户填写了课程信息后将这些信息写入到相应的数据库记录中。
⑷public boolean setpw(String unit, String pw)
此函数在用户修改密码时使用的。
⑸public boolean isbooksame(Integer bid)
此函数是用户填写教材信息是否重复输入,或是输入了别的课程已经选取的教材时判断用的,防止数据库主键重复插入。
⑹public Object getbidname(Integer cid)
这是为了教研室查询已选教材准备的接口,为选取教材提供参考。
5、订单子系统
为了实现教材委员会对整个教材选取系统的控制,得到教材订单报表,本系统在 C/S端达到上述目的。它是不发布的,是教材委员会的本地客户端,其中的订单界面如图4。
![]() 图4 订单子系统中的订单界面 |
系统启动时,将自动从教务处数据库取得将要开设的课程信息,添入教材委员会数据库的选教材表中,空出与之对应的教材信息等待教研室教员理用B/S端加进去。核心代码:
conhome= (connectEJBsHome) PortableRemoteObject.narrow(ref, connectEJBsHome.class); try { con=conhome.create(); if(con.writexk(con.zhuanyi())) { System.err.print("你已成功转移了数据!"); } }catch(Exception ex) { ex.printStackTrace(); System.err.print("数据转移失败!"); } |
它得到会话Bean的home接口,将会话Bean的方法couinfo()得到的课程信息再调用writexk()写入到选教材表中,等待教研室选取教材,然后为教研室分配原始密码888888。核心代码:
try { con=conhome.create(); if(con.writetp(con.zhuanyi(),”888888”) { System.err.print("密码分配成功!"); } }catch(Exception ex) { ex.printStackTrace(); System.err.print("密码分配失败!"); } |
当按下“刷新订单”按钮之后,下面的列表框将呈现需要订购的教材的信息,包括书名和书的ISBN号和订购数量。实现代码为:
conhome= (connectEJBsHome) PortableRemoteObject.narrow(ref, connectEJBsHome.class); try { con=conhome.create(); if(con.writebaobiao()) { System.err.print("得到报表数据!"); if(this.getnum()) { System.err.print("取到了书的数目!"); } } } catch(Exception ex) { ex.printStackTrace(); System.err.print("生成报表失败!"); } |
其中writebaobiao()将用到会话EJB中的专门为得到订购书本数目而写的一系列函数,这里不赘述。
6、教材选取系统
教材选取是一个在线系统。核心部分全部用JSP制作,借助Dreamweavre4开发JSP将会十分便利。本系统没选择applet做界面是考虑到安全性需要,applet需要将程序下再到客户端执行,它实际上是一种可用网页打开的C/S,破坏了三层结构瘦客户端的优点,但在实现不涉及安全性的部分可以考虑使用。本系统的选取界面如图5所示。
![]() 图5教材选取系统的选取界面 |
这里共有五张JSP页面是在线教材选取系统的主要部分。一些jsp页面直接使用同一个JavaBean,增强了代码的复用性,如登陆页面与密码修改页面同用pwbean的Javaean。为了使大多数逻辑在会话EJB中实现,JavaBean作为JSP的一部分要短小精干。login.jsp为登录界面,可自动获得教务处所有教研室名称,通过教材委员会分配的密码登陆select.jsp,选择教材。到了select.jsp后,网页自动获得登陆教研室所负责的课程,这里给了两个文本框,让教员输入他认为合适的书本的统一编号和名称,当然这里是以编号为唯一标识的,成功后会出现成功页面success.jsp。在这里还有教研室可以修改密码的导航按钮, 转换到修改密码的界面pwchange.jsp,这里需要输入原来的登陆密码,输入两次新密码才能真正修改密码。修改成功后会出现成功界面。密码在教材委员会数据库里,在这里完完全全体现了JSP的安全性。
至此,核心功能已实现,其他单位的查询浏览等功能略去。
利用JBuilder开发系统的好处是许多功能由系统自动完成。上述工作完成后,只需工程部分打包成EAR(Enterprise Archive)。在JBuilder中将Tools->Enterprise Deploy配置好服务器地址、端口,用户名密码,系统自动将web应用部署信息写进部署描述文件web.xml中,要做的只是右击工程发布即可。
try{ Context context=new InitialContext(); Object ref=context.lookup("java:/comp/env/Coursearrangement"); crthome=(CoursearrangementHome) ref; ref=context.lookup("java:/comp/env/Xk"); xkhome=(XkHome) ref; ref=context.lookup("java:/comp/env/Tp"); tphome=(TpHome) ref; ref=context.lookup("java:/comp/env/Number"); numberhome=(NumberHome) ref; ref=context.lookup("java:/comp/env/Ck"); ckhome=(CkHome) ref; ref=context.lookup("java:/comp/env/Baobiao"); baobiaohome=(BaobiaoHome) ref; }catch(Exception e){e.printStackTrace();} |
这样就能通过会话EJB的远程接口访问实体EJB里自动生成的和自己添加的方法或函数了,前提是这个方法或函数包含在实体EJB的home接口里。
还添加了一些本地公有函数和多个远程公有函数,用来修改或访问实体EJB并作初步的处理。增加的函数必须在JBuilder中先右击代表会话Bean的图形添加方法(add method),设置各项参数后方可右击会话Bean选择View Bean Sourse菜单,进入代码区编辑方法主体,否则工程将产生编译错误。这里提供了整个系统所需的与数据库打交道的函数,这些接口在后文中都有用到。
3个本地公有函数:为了解决不能连续在同一个函数里多次写入信息而独立出来的函数
①public void writecidcname(Integer cid, String cname, String teachunit)
这是往选教材表写课程信息。
②public void writebook(Integer bid, String bname)
这时保教材信息写入订单表。
③public void writealltp(String unit, String pw)
同理,为了往密码表里写入密码信息而编写。
远程公有函数:以下的函数是订单子系统要用到的接口
⑴public java.util.Collection couinfo()
这个函数是负责从教务处得到开设课程的信息。返回值是Collection对象。
⑵public boolean writexk(java.util.Collection rst)
这个函数在运行订单子系统自动调用。它负责在初始化系统时将从教务处得到的课程信息写进选教材表中,保证既使新增了新的教研室也能实时地获得。它的参数就是函数zhuanyi()的返回值,在程序主体调用了本地函数①。
⑶public java.util.Collection selectunit()
这个函数是为了从选教材表中得到所有开设了课程的教研室的名称。既为了在B/S的登录界面上得到教研室名下拉框的需要,又为了在密码表中得到教研室名而编写。注意这里有重复信息,需要再调用它的函数中过滤掉。
⑷public boolean writetp(Collection rst, String pw)
这是为了建立教研室密码表而编写,在函数⑵后调用,当表中没有教研室或是有了新的教研室的时候,它会自动加到密码表中并分配原始密码。是教员能登陆再现的教材录入子系统。
⑸public boolean reflushbaobiao()
这是C/S界面用户刷新订单信息时,将选教材表中的已经选了的教材信息写进订单表中。它在获得相应教材应定的数量之前调用。
●这以下是为了获得订单中所需要订购的书的数目而写的函数,因为不能在一个函数中操作多个数据库,所以用了下面多个函数以实现。
得到订单表里所有的教材号:
public Collection readbaobiaoforgetnum() |
从选教材表中得到已经选好的课本对应的课程号:
public Integer readxkforgetnum(Integer bid) |
再从教务处课程安排表中得到开了这个课程号所代表的课程的专业,可能不止一个:
public Collection readcouforgetnum(Integer cid) |
然后从教务处人数表中查到这些专业的人数:
public Integer readnumforgetnum(Long id) |
再找出仓库里这本书的库存量,如果所需数量大于库存量,就要在订单中显示出定购量:
public Integer readckforgetnum(Integer bid, int numall) |
○●○此以下的函数为教员在线教材选取和相关单位查询要用到的函数。
⑴public String login(String unit)
这在用户登陆时系统检查密码是否匹配时使用,就是根据用户名查询到相应的密码并返回。在用户修改密码时验证是否为登陆用户也用到了它。
⑵public String login(String unit)
这个函数从名字得知,是用户登陆时系统检查密码是否匹配时使用的,就是根据用户名查询到相应的密码并返回。在用户修改密码时验证是否为登陆用户也用到了它。
⑶public boolean writein(Integer cid, Integer bid, String name)
这个函数是用户填写了课程信息后将这些信息写入到相应的数据库记录中。
⑷public boolean setpw(String unit, String pw)
此函数在用户修改密码时使用的。
⑸public boolean isbooksame(Integer bid)
此函数是用户填写教材信息是否重复输入,或是输入了别的课程已经选取的教材时判断用的,防止数据库主键重复插入。
⑹public Object getbidname(Integer cid)
这是为了教研室查询已选教材准备的接口,为选取教材提供参考。
5、订单子系统
为了实现教材委员会对整个教材选取系统的控制,得到教材订单报表,本系统在 C/S端达到上述目的。它是不发布的,是教材委员会的本地客户端,其中的订单界面如图4。
![]() 图4 订单子系统中的订单界面 |
系统启动时,将自动从教务处数据库取得将要开设的课程信息,添入教材委员会数据库的选教材表中,空出与之对应的教材信息等待教研室教员理用B/S端加进去。核心代码:
conhome= (connectEJBsHome) PortableRemoteObject.narrow(ref, connectEJBsHome.class); try { con=conhome.create(); if(con.writexk(con.zhuanyi())) { System.err.print("你已成功转移了数据!"); } }catch(Exception ex) { ex.printStackTrace(); System.err.print("数据转移失败!"); } |
它得到会话Bean的home接口,将会话Bean的方法couinfo()得到的课程信息再调用writexk()写入到选教材表中,等待教研室选取教材,然后为教研室分配原始密码888888。核心代码:
try { con=conhome.create(); if(con.writetp(con.zhuanyi(),”888888”) { System.err.print("密码分配成功!"); } }catch(Exception ex) { ex.printStackTrace(); System.err.print("密码分配失败!"); } |
当按下“刷新订单”按钮之后,下面的列表框将呈现需要订购的教材的信息,包括书名和书的ISBN号和订购数量。实现代码为:
conhome= (connectEJBsHome) PortableRemoteObject.narrow(ref, connectEJBsHome.class); try { con=conhome.create(); if(con.writebaobiao()) { System.err.print("得到报表数据!"); if(this.getnum()) { System.err.print("取到了书的数目!"); } } } catch(Exception ex) { ex.printStackTrace(); System.err.print("生成报表失败!"); } |
其中writebaobiao()将用到会话EJB中的专门为得到订购书本数目而写的一系列函数,这里不赘述。
6、教材选取系统
教材选取是一个在线系统。核心部分全部用JSP制作,借助Dreamweavre4开发JSP将会十分便利。本系统没选择applet做界面是考虑到安全性需要,applet需要将程序下再到客户端执行,它实际上是一种可用网页打开的C/S,破坏了三层结构瘦客户端的优点,但在实现不涉及安全性的部分可以考虑使用。本系统的选取界面如图5所示。
![]() 图5教材选取系统的选取界面 |
这里共有五张JSP页面是在线教材选取系统的主要部分。一些jsp页面直接使用同一个JavaBean,增强了代码的复用性,如登陆页面与密码修改页面同用pwbean的Javaean。为了使大多数逻辑在会话EJB中实现,JavaBean作为JSP的一部分要短小精干。login.jsp为登录界面,可自动获得教务处所有教研室名称,通过教材委员会分配的密码登陆select.jsp,选择教材。到了select.jsp后,网页自动获得登陆教研室所负责的课程,这里给了两个文本框,让教员输入他认为合适的书本的统一编号和名称,当然这里是以编号为唯一标识的,成功后会出现成功页面success.jsp。在这里还有教研室可以修改密码的导航按钮, 转换到修改密码的界面pwchange.jsp,这里需要输入原来的登陆密码,输入两次新密码才能真正修改密码。修改成功后会出现成功界面。密码在教材委员会数据库里,在这里完完全全体现了JSP的安全性。
至此,核心功能已实现,其他单位的查询浏览等功能略去。
利用JBuilder开发系统的好处是许多功能由系统自动完成。上述工作完成后,只需工程部分打包成EAR(Enterprise Archive)。在JBuilder中将Tools->Enterprise Deploy配置好服务器地址、端口,用户名密码,系统自动将web应用部署信息写进部署描述文件web.xml中,要做的只是右击工程发布即可。