当前页面: 开发资料首页 → Java 专题 → JDO+JSP2.0开发Web应用向导 – 配置篇
摘要: JDO+JSP2.0开发Web应用向导 – 配置篇
本系统采用JDO + JSP 2.0 完成
您的浏览器类型是:${header['user-agent']}
您的IP地址是:${pageContext.request.remoteAddr}
然后将Resin启动,看看效果:
好!现在我们的第一个JSP页面就已经完成了。该页面代码中用到的
“${pageContext.request.serverName} ”、“${header['user-agent']}”和
“${pageContext.request.remoteAddr}”都是JSP2.0中定义的JSP EL表达式。
2.1.3 一个处理JDO资源的工具类:jdobbs.Sys
我们先来写一个非常关键的工具类:jdobbs.Sys,这个类负责处理一些基本的
JDO 存储管理器获取、资源释放、线程同步方面的事务。关于其中的每个细节,都
可以用一大篇文章来说明(详情见
{http://www.jdocentral.com/forums/index.php?
s=8bf08748ea2b95fe52e0d25c7a489732&act=SF&f=11}中的相关讨论),这里为了简
单起见,只简单地描述一下这个工具类的目标: 1. 保证每个JSP页面请求的服务
端线程中所有的业务逻辑方法共享同一个javax.jdo.PersistenceManager,除非在
处理过程中间显式地关闭当前的PersistenceManager。这将采用
java.lang.ThreadLocal接口实现
2. 保证每个页面请求结束后,处理请求过程中涉及的JDO资源全部被释放(即关闭
用到的PersistenceManager)。这将采用javax.servlet.Filter接口实现
我们来看看下面的Sys.java源码:
package jdobbs;
import javax.jdo.*;
import javax.servlet.*;
import java.io.*;
import java.util.*;
public class Sys extends ThreadLocal implements Filter {
/** 获取PersistenceManagerFactory */
public static PersistenceManagerFactory pmf() {
if(pmf == null) {
Properties p = new Properties();
InputStream is = Sys.class.getResourceAsStream("/jdobbs.jdogenie");
try {
p.load(is);
} catch(IOException ex) {
throw new RuntimeException("初始化PersistenceManagerFactory时配置文件读
取失败!",ex);
}
pmf = JDOHelper.getPersistenceManagerFactory(p);
}
return pmf;
}
/** 获取PersistenceManager
* 通过使用ThreadLocal对象,使同一线程中每次调用本方法,都会返回同一PM对象。
*/
public static PersistenceManager pm() {
if(threadLocal == null) {
threadLocal = new Sys();
}
return (PersistenceManager)threadLocal.get();
}
/** 用于释放本次线程中使用到的JDO资源
* @return 是否有未完成的Transaction,便于后台日志区别记录
*/
public static boolean cleanupResource() {
return threadLocal != null && threadLocal.cleanup();
}
private static PersistenceManagerFactory pmf;
//============= 以下是ThreadLocal的相关方法==============
private static Sys threadLocal; //一个用于保证同一线程只访问同一PM对象的控制器
/**
* 获取一个与当前线程相关的PersistenceManager
* @return 一个PersistenceManager类型的对象,调用者需要强制转换一下类型。
*/
public Object get() {
PersistenceManager pm = (PersistenceManager)super.get();
if(pm == null || pm.isClosed()) {
pm = pmf().getPersistenceManager();
set(pm);
}
return pm;
}
/**
* 释放所有与本线程相关的JDO资源
* @return 是否有未完成的Transaction,便于后台日志区别记录
*/
public boolean cleanup(){
PersistenceManager pm = (PersistenceManager)super.get();
if(pm == null) return false;
if(pm.isClosed()) {
set(null); return false;
}
boolean tsActive = false;
try {
Transaction ts = pm.currentTransaction();
tsActive = ts.isActive();
if(tsActive) ts.rollback();
} finally {
set(null);
pm.close();
}
return tsActive;
}
//============= 以上是ThreadLocal的相关方法==============
//============= 以下是JSP Filter的相关方法==============
public void init(FilterConfig p0) throws ServletException {}
public void destroy() {}
/** JSP页面(Servlet)处理的过滤器方法,用于JSP执行完毕后检测并释放用到
的JDO资源 */
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain
fc) throws ServletException,IOException {
try {
fc.doFilter(req,res);
} finally {
cleanupResource();
}
}
//============= 以上是JSP Filter的相关方法==============
}
简单地说,这个类提供了一个静态的pm()方法,可以获取一个JDO的存储管理器
PersistenceManager,这个方法将是以后的代码中用到最多的方法。
其中的Sys. pmf()用于获取PersistenceManagerFactory,这个方法中用到了一
个配置文件:jdobbs.jdogenie,这个文件是我们下面将要生成的JDOGenie的配置文
件,也就是将在workbench中产生应用配置文件,其中包括数据库连接地址、用户、
密码信息,以及一些性能调节的设置。这个配置文件jdobbs.jdogenie将被放置在
bbs/WEB-INF/classes/目录下,以便程序读取。
这个Sys类使用了Servlet的过滤接口来保证每个JSP执行完毕后相关的JDO资源
得以释放。因此,编译这个类时,一定要将Servlet2.4的支持包包含在CLASSPATH中
,这个包即是“
的方便,我们编写一个Ant脚本作为执行各种批处理(包括编译)的工具。
2.1.4 配置JSP过滤器
为了让前面的JSP Filter生效,我们需要将其配置到我们的Web应用中去,准确
地说,就是创建(或更改)bbs/WEB-INF/web.xml文件,我们更改该文件后,看看它
的源代码:web.xml
这段内容保证了每个JSP页面请求处理完后,Sys.cleanup()方法将得到执行,
以检测并清除用到的JDO资源。
2.1.5 Ant脚本
按Ant的标准,我们编写一个名为“build.xml”的脚本,并且,为了配置上的
方便,我们将这个文件放到bbs/WEB-INF/目录下。
我们看看这个Ant脚本的源代码:build.xml
将这个文件放到bbs/WEB-INF/目录下后,我们开启一个DOS命令行窗口,并进入
该目录,运行一下:“ant compile”,将会看到如下结果:
D:\resin-3.0.4\webapps\bbs\WEB-INF>ant compile
Buildfile: build.xml
compile:
[javac] Compiling 1 source file to D:\resin-3.0.4\webapps\bbs\WEB-
INF\classes
BUILD SUCCESSFUL
Total time: 2 seconds
D:\resin-3.0.4\webapps\bbs\WEB-INF>
这个结果表示我们的Ant脚本已经成功运行了。如果你看到的结果是:
'ant' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
那就说明你的Ant没有配置好(比如你开了DOS窗口后才去更改系统的PATH环境
变量),这方面的问题参见前面的Ant安装与配置进行解决。
脚本的内容这里不一一解释了,请参考Ant的帮助。这里只说明一下:
“enhance”批处理中通过jdogenie.jar中的Ant任务定义,使用了一个“jdo-
enhance”任务,这个任务就是用来增强类代码的。
好了,进行了以上这些准备工作,为确信以上的工作都没有出现错误,我们再
次从浏览器访问一下首页,结果与最开始的首页完全一样,符合预期。
接下来,我们就可以开始进行真正的JDO分析和设计了。
2.2 功能需求
我们最初的需求很简单,就是让网友可以在这个系统中交流,以发贴、回复的
形式,简单地看,可以说这是一个留言本系统。我们要达到以下目标: 1. 网友进
入主页时,系统列出目前所有的主题,按时间顺序从近到远排列。
2. 网友可以在主页下方的发贴表单中发表新主题,包括标题和内容
3. 其它网友在主页的贴子列表中点击某个标题可以阅读这个主题的详细内容,包
括所有的回贴内容。所有回贴按照时间顺序排列在主题主贴后面
4. 可以在主题详细内容页面尾部的回贴表单中回复这个主题
5. 每个网友发表主题或贴子时,系统需要记录该贴子发表时的客户端IP地址
6. 系统提供一个高级搜索功能,让网友可以根据时间、主题标题、内容或回复内
容、IP搜索主题
2.3 分析、数据对象模型与JDO集成
通过对需求的分析,我们发现,系统中需要存储的信息就是网友提交的主题或
者回复。主题和回复都需要记录发贴的网友的IP地址,都有文字内容,但二者又稍
有不同,主题可以有一个标题,而回复不需要(目的是为了方便回贴),另外,一
个回复贴子一定是针对一个主题的。
从面向对象的角度出发,我们将以上的数据包装成为下列的对象模型:
(后面我们会看到这个图是如何弄出来的)
2.3.1 编写数据类源码
我们根据贴子的共性,编写一个基类:Post(贴子),代表所有的主题和回复
,具有贴子所具备的几个基本属性。而主题类我们用Topic来表示,它从Post继承;
回复类我们用Reply来表示,它有一个属性:topic,表示所回复的主题。主题和回
复之间具有一对多关系,体现在Topic.replies和Reply.topic属性上。为了JSP2.0
中的JSP EL的访问,我们给每个属性加上getter/setter(很多IDE工具都提供自动
添加getter/setter的功能)。
下面看看这三个文件的源代码(注意,都放在WEB-INF/classes/jdobbs/目录下):
贴子类Post.java:
package jdobbs;
import java.util.*;
/**
* 网友所发表的贴子,包括话题和回复
*/
public class Post {
/** 贴子内容 */
String content;
/** 贴子内容的长度 */
int length;
/** 发贴时客户机器的IP地址 */
String ip;
/** 发表本贴的时间 */
Date postTime;
public String getContent() {
return content;
}
public void setContent(String value) {
content = value;
}
public int getLength() {
return length;
}
public void setLength(int value) {
length = value;
}
public String getIp() {
return ip;
}
public void setIp(String value) {
ip = value;
}
public Date getPostTime() {
return postTime;
}
public void setPostTime(Date value) {
postTime = value;
}
}
主题类Topic.java:
package jdobbs;
import java.util.*;
/**
* 话题
*/
public class Topic extends Post {
/** 标题 */
String title;
/** 回复数 */
int replyCount;
/** 所有回复 */
List replies;
/** 最后更新,即最后被回复的时间 */
Date lastUpdate;
public String getTitle() {
return title;
}
public void setTitle(String value) {
title = value;
}
public int getReplyCount() {
return replyCount;
}
public void setReplyCount(int value) {
replyCount = value;
}
public List getReplies() {
return replies;
}
public void setReplies(List value) {
replies = value;
}
public Date getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(Date value) {
lastUpdate = value;
}
}
回复类Reply.java:
package jdobbs;
/**
* 回复
*/
public class Reply extends Post {
/** 所回复的话题 */
Topic topic;
public Topic getTopic() {
return topic;
}
public void setTopic(Topic value) {
topic = value;
}
}
为了在下面使用JDOGenie工具来配置JDO环境,我们先在build.xml所在目录中
运行一下编译任务:ant compile,编译这几个类。
2.3.2 配置JDOGenie,自动创建system.jdo元数据文件、自动建数据库,等等
接下来,我们用JDOGenie来实现这个对象模型。注意,接下来这几步很重要!
我们进入
口中,我们通过菜单“FileàNew Project…”新建一个JDOGenie项目(这个项目实
际上就是JDOGenie的配置文件),在出现的项目文件对话框中,我们选择
(也就是配置文件的名称):“jdobbs.jdogenie”,注意,请输入完整文件名。如图:
点击确定后,我们将看到一个项目配置设置的对话框。在这个配置对话框的左
边列出配置项,右边则每项的配置内容。注意,带目录图标的“Project”和
“Datastore”也是配置项。我们将在这个对话框中逐项地配置必须的信息:
1. 首先出现的是Project属性设置,即左边的Project项,在此项中,我们将“Non
-transactional read”检查框选中,这样可以不用声明事务就直接通过存储管理器
(PersistenceManager)访问数据库中的对象。如图:
2. 接下来是Ant的集成配置,目的是便于直接在工作台中调用Ant完成数据类的编译
和增强。我们需要输入ant.bat和build.xml所在的路径,以便调用。如图:
当然,我们也可以总是手工地在命令行调用Ant,这只需要将上图中的
“Disable Ant”选中即可。
3. CLASSPATH设置。这里需要加入数据类的根路径和MySQL的JDBC包,如图:
4. 指定Metadata文件。按照JDO规范的要求,必须用.jdo结尾的文件(也称元数据
或描述符)来描述需要存储的数据类。我们选择使用CLASSPATH根目录下的
system.jdo文件来描述本系统中所有需要存储的数据类。先选择配置对话框左边的
“JDO Meta Data Files”,出现如下对话框:
点击按钮“New”在WEB-INF/classes/下新建一个system.jdo文件,如图:
点击“保存”按钮,回到配置对话框:
5. 在“Project”部分的剩下几个配置项主要用于性能优化等方面的调节,我们暂
时不考虑。现在直接点击“Datastore”项,进入数据库连接信息配置项,如图:
点击“Choose”按钮,选择MySQL类型的数据库,然后在URL栏中输入到本机
MySQL数据库的连接:“jdbc:mysql://localhost/test?
useUnicode=true&characterEncoding=GBK”,该URL中的GBK设置保证MySQL处理中
文时不会乱码。配置好后,界面如下:
现在,我们可以点击下方的“Test”按钮来检测数据库是否能连通(在此之前
,请先检查一下MySQL是否已经运行)。如果不能连通,请检查前面的配置是否正确
(Classpath配置中是否加入了mysql.jar,URL是否输入正确)
到此为止,“Datastore”部分剩下的几项配置都可暂不理会,直接点击最下方
的“OK”按钮关闭配置对话框。这时出现的是一个空的界面,如图:
在这里,简单介绍一下JDOGenie的界面,左边是几个大按钮,代表各个方面的
功能(前面已经介绍过),从上到下依次是:类树、类图、类列表、数据库结构、
JDO查询、远程控制台。后面会介绍这些功能。
我们现在将前面编写的数据类添加到项目中,这个步骤将生成JDO规范中要求的
.jdo元数据文件。在上面的界面的上半部分的类列表中点击右键,在弹出菜单中选
择“Add Classes…”,这时系统会列出从CLASSPATH中找到的.class类文件,我们
选择其中的三个:Post、Topic、Reply:
确定后,系统提示放入哪个元数据文件中,并且列出了前面创建的
“system.jdo”文件。直接点击“OK”即可。我们将看到主窗口变成了下面的样子:
工具条上的第四个按钮“JDO Metadata Compile”变成了红色,表示
system.jdo中的信息中有歧义,点一下这个按钮看看详细原因:
原来是系统不知道Topic类中的replies列表(List)的元素类型,在主窗口中
选中Topic类,在界面下半部分的类属性列表中,在replies属性行上点击右键,选
择“Field Properties…”,进入replies属性设置的对话框,在对话框中,我们需
要设置两项:第一项,在“Element Type”中选择jdobbs.Reply类,表示replies列
表的元素是Reply对象;第二项,在“Inverse field”中选择“topic”,表示
Topic.replies与Reply.topic是一对双向关系,任何一边的改动都会影响到另一边。如图:
设置好后,点击这个对话框右上角的“”按钮关闭它,现在在主窗口中,工具
条上的第四个按钮已经变成绿色()了,表示元数据已经没有问题了。我们保存一
下项目:“File->Save”,现在就可以增强我们的数据类了。选择菜单
“BuildàCompile & Enhance”或者点击工具条上的第五个按钮“”,我们将看到成
功编译和增强的信息:
下面我们需要为我们的数据类建立相应的数据表,我们点击一下左边的大按钮
“ Database schema operations…”,系统会列出当前的数据类所需要的数据表结
构,这里我们只看到一个表,因为我们的三个类相互之间是继承关系,JDOGenie对
继承的类用同一个表来表示。我们选择菜单“BuildàRecreate Schema”,在数据库
中生成这个表结构(如果是以后改变了类,就不能再重建了,而需要在JDO查询区“
Queries”中用ALTER TABLE的SQL语句来解决,否则会丢失数据):
以上的一系列配置过程,就是我们集成JDO的过程,乍一看,好象配置非常复杂
,其实前面这一系列过程很快就可以完成,理解了JDO的原理后会觉得很简单。以后
,这个JDOGenie的工作台workbench.bat就是我们的工作环境了。我们进一步更改类
源码后,只需要在这里点击一下编译按钮“”,就可以将最新的源文件编译并增强
了。如果增加了更多的数据类,也只需要在这个工作台中将新的类加入到项目中(
即元数据中)即可。
最后,我们回想一下前面提到的数据类图,该图实际上也是在JDOGenie的工作
台中生成的。我们点击左边的大按钮“ Class and E/R diagrams”进入类图区,在
窗口中点右键,选择“Choose Classes…”,将所有的数据类都加入到图中,就会
看到包含Post、Topic、Reply三个类的类图,对位置稍加调整,就可以得到前面的
类图了,如图:
好了,以上所介绍的是JDOGenie的工作台图开操作界面的诸多细节,实际上,
我们还没有涉及JDO开发中的核心部分:API的使用。不过相信经过以上的介绍,读
者对作为一个JDO实现的JDOGenie也有了比较全面的认识了。然而,对于JDO开发来
说,不同的产品有不同的配置工具和配置操作,各有特色,比如KodoJDO的数据库是
可以配置为在运行时动态生成和动态与数据类模型同步的,这一点深受开发人员喜
爱。可喜的是,JDOGenie很快也将加进这一非常有利于快速开发和维护的特性。
在我们开始真正的JDO开发之旅之前,我们先休息一会儿,回顾一下前面提到过
的各个层次的服务器,包括数据库、JSP服务器、JDO产品等等。在本文的《开发篇
》中,将给读者揭开JDO的神秘面纱,让读者看清楚开发过程中的每一个细节……
本文的版权属于笔者本人,但欢迎转载,前提是注明出处和原作者。另外,欢
迎在我的专栏中查看我的另几篇文章,并提出宝贵意见!
作者相关文章:
JDO+JSP2.0开发Web应用向导 - 开发篇(原作)
JDO之前世今生(原作)
贺JDO2.0计划开始启动!(原作)
对该文的评论 人气:356
fkpwolf(2003-12-13 15:47:32)
写的如此详细,一个字,好!
sun2bin(2003-12-12 13:14:29)
EJB效率不足,配置、调试麻烦,适合数据重要但时间无所谓的大公司
Hibernate免费且用户多,功能也挺强,不过配置麻烦,开发也有些烦琐,而性能则
不知道如何
JDO使用开发简单,维护方便,不过目前状况是各家特点不一,产品差异还较大,标
准的JDO1.0功能有限。
jenny_cai(2003-12-8 13:51:59)
高手是怎样练成的,就是这样练成的。
希望能解释一下各种ORM的优点和不足。ENTITY EJB,HIBERNATION,JDO,随更好?
↑返回目录
前一篇: JDom 常用转换方法
后一篇: JDO vs实体Beans:一个善意的忠告