互动出版网 专业图书网上第一专营店 独家提供样章 第5章 共享知识:DWk,基于 DWR的Wki 我 还记得之前看过的《呆伯特( Dilbert)》连环漫画,这里我先给你讲述一下。由于完 全是根据记忆,因此可能不一定准确,不过希望不会影响我的讲述 它讲的是一名咨询师正在试图向一位秃头老板推销一些在线协作工具。此刻,这个老板很有 洞察力地对咨询师说,“这些工具不会仅仅帮助那些无知的员工更加有效地共享他们的愚昧吧?” 就在这个时候,咨询师疯狂地鼓吹老板去签约! 你会问重点是什么?难道说《呆伯特》不像一本连环漫画,更像美国公司IT部门的纪实?不, 这是因为在本章我们将构建一个在线协作工具!现在,无论使用它共享无知还是有用的知识,我 们可以简洁地说这不是本书的范畴。 在本章中,将构建一个Wiki,这是在整个Web20运动中比较有用的产品之一。我们当然会 使用DWR为它增加Aax特性(这也正是Wik急需的),从而也为我们提供一个便利的小应用程序, 用于共享知识(或者无知,这取决于秃头老板决策的正确与否)。不再拖延了,让我们开始吧。 (不过,如果你想花几分钟浏览一下呆伯特的漫画,我并不介意。) 51应用程序的需求和目标 那么,确切地说,wiki到底是什么呢?简言之,它是一个Web应用程序,可供用户相互合作 创建一个Web站点。换言之,用户可以创建多个页面(这个页面通常被称作文章),然后将它们 链接在一起。这个链接的过程通常是自动完成的,无须实际编写HIML代码:通常在Wiki上工作 都不会要求使用HTML。在大多数情况下,仅有已注册的用户方可修改和创建文章,因为这里需 要用户承担一定的责任。这个Wiki程序必须处理两个用户同时编辑同一篇文章时可能出现的并发 问题(一般可以通过一个用户在编辑的时候“锁定”文章来解决这个问题)。 当然,Wk通常还有许多其他的特性,这里我们将完成其中的一些特性。我们继续讨论,下 ①如果不熟悉《呆伯特》,强烈建议你放下手中的工作,浏览www.dilbert.com网站。《呆伯特》是美国的一部连环漫画, 里面有许多极搞笑的角色,这些角色来自一家公司的∏部门(是的,好像是I部门,不过我并不能确认里面是否以 某种方式提过 怎样,如果你本身在IT部门工作,而且又在阅读本书,猜想你将会从作者 Scott Adam的漫画创 作中感受到更多的乐趣
共享知识:DWiki,基于 DWR的Wiki 还记得之前看过的《呆伯特①(Dilbert)》连环漫画,这里我先给你讲述一下。由于完 我 全是根据记忆,因此可能不一定准确,不过希望不会影响我的讲述。 它讲的是一名咨询师正在试图向一位秃头老板推销一些在线协作工具。此刻,这个老板很有 洞察力地对咨询师说,“这些工具不会仅仅帮助那些无知的员工更加有效地共享他们的愚昧吧?” 就在这个时候,咨询师疯狂地鼓吹老板去签约! 你会问重点是什么?难道说《呆伯特》不像一本连环漫画,更像美国公司IT部门的纪实?不, 这是因为在本章我们将构建一个在线协作工具!现在,无论使用它共享无知还是有用的知识,我 们可以简洁地说这不是本书的范畴。 在本章中,将构建一个Wiki,这是在整个Web 2.0运动中比较有用的产品之一。我们当然会 使用DWR为它增加Ajax特性(这也正是Wiki急需的),从而也为我们提供一个便利的小应用程序, 用于共享知识(或者无知,这取决于秃头老板决策的正确与否)。不再拖延了,让我们开始吧。 (不过,如果你想花几分钟浏览一下呆伯特的漫画,我并不介意。) 5.1 应用程序的需求和目标 那么,确切地说,Wiki到底是什么呢?简言之,它是一个Web应用程序,可供用户相互合作 创建一个Web站点。换言之,用户可以创建多个页面(这个页面通常被称作文章),然后将它们 链接在一起。这个链接的过程通常是自动完成的,无须实际编写HTML代码;通常在Wiki上工作 都不会要求使用HTML。在大多数情况下,仅有已注册的用户方可修改和创建文章,因为这里需 要用户承担一定的责任。这个Wiki程序必须处理两个用户同时编辑同一篇文章时可能出现的并发 问题(一般可以通过一个用户在编辑的时候“锁定”文章来解决这个问题)。 当然,Wiki通常还有许多其他的特性,这里我们将完成其中的一些特性。我们继续讨论,下 ① 如果不熟悉《呆伯特》,强烈建议你放下手中的工作,浏览www.dilbert.com网站。《呆伯特》是美国的一部连环漫画, 里面有许多极搞笑的角色,这些角色来自一家公司的IT部门(是的,好像是IT部门,不过我并不能确认里面是否以 某种方式提过)。不论怎样,如果你本身在IT部门工作,而且又在阅读本书,猜想你将会从作者Scott Adam的漫画创 作中感受到更多的乐趣。 第5章
互动出版网 China-Pub. com 专业图书网上第一专营店 独家提供样章 5.1应用程序的需求和目标80 面列出 WIki将要提供的特性和功能。 口前面提到过,仅有已注册用户能够添加或删除文章(或者给文章加评论)。 口给文章加评论是允许用户讨论某个文章,而无须实际地编辑该文章。所有的用户都能够 阅读这个评论,但只有已注册用户可以加评论。 口实施容器管理的安全,通过DWR与EE安全的集成,封闭适当的远程方法。 口当对文章进行编辑时,需要保持相关历史信息,以便人们能够看到是谁做了什么样的改 动。为简单起见,只记录编辑前后文章的文本(并不是太复杂,比较容易实现)。 提供一个帮助页面,辅助用户理解如何使用 WIki。 口虽然写文章时不要求使用HTML,但使用它可以在文章中包含丰富的内容,而不必创建自 己的完整Wiki语言。 口希望 WIki尽可能得灵活,这样用户就可以尽可能多地编辑可见界面。把尽可能多的界面 当做文章,和其他的一样。其中会存在一些例外情况,为了解决这些例外,将使用一个 名为 FreeMarker的比较灵活的模板系统,并创建一个通用的DWR扩展来使用它,这个扩 展以后也可重用。 口任何以大写字母开头的单词将会被解释成到文章的一个链接。单击这个单词,将会跳到 对应的文章或者占位符,如果文章不存在,用户可以在此创建文章。很显然,并不是所 有以大写字母开头的单词都应该是文章的链接,因此还需要采用某种方法来覆盖这个链 接(这并不需要什么非常复杂的算法,但是必须是有效的)。 口使用数据库来存储Wiki的内容,具体而言就是 Apache Derby。另外,可以采用 Spring库的 JDBC支持来尽量避免自己编写较低层的JDBC代码 口DWik将支持“锁定”文章以便编辑,这个锁持续的时间由配置决定, 般情况下,使用DWR把用户界面连到后台,并且你会发现这样必须撰写的代码量远小于 其他方式。 在真正开始剖析该应用程序的代码之前,先讨论即将使用的几个关键技术,包括 FreeMarke 模板库、 Apache Derby数据库以及 Spring库的JDBC支持 5.1.1 FreeMarker 正是由于我喜欢不时来点新意,因此先讨论 Free Marker。另外,只要可能,我总是会选择偷 懒(我当然崇拜霍默·辛普森的人生原则),因此想借用 FreeMarker主页内容简单讲解 FreeMarker 是什么(如果理解成直接引用,也可以) FreeMarker是一个“模板引擎”,这个通用工具可根据模板生成文本输出(从HML到自动生成 的源码等)。这是一个Java包,为Java开发人员提供了一个类库。这个应用程序本身并不服务终 端用户,不过编程人员可能会将它嵌入到自己的产品中, FreeMarker的设计目的是生成 HTML Web页面,特别是用于基于 servlet的应用程序中,而这些应
5.1 应用程序的需求和目标 80 面列出DWiki将要提供的特性和功能。 前面提到过,仅有已注册用户能够添加或删除文章(或者给文章加评论)。 给文章加评论是允许用户讨论某个文章,而无须实际地编辑该文章。所有的用户都能够 阅读这个评论,但只有已注册用户可以加评论。 实施容器管理的安全,通过DWR与J2EE安全的集成,封闭适当的远程方法。 当对文章进行编辑时,需要保持相关历史信息,以便人们能够看到是谁做了什么样的改 动。为简单起见,只记录编辑前后文章的文本(并不是太复杂,比较容易实现)。 提供一个帮助页面,辅助用户理解如何使用DWiki。 虽然写文章时不要求使用HTML,但使用它可以在文章中包含丰富的内容,而不必创建自 己的完整Wiki语言。 希望DWiki尽可能得灵活,这样用户就可以尽可能多地编辑可见界面。把尽可能多的界面 当做文章,和其他的一样。其中会存在一些例外情况,为了解决这些例外,将使用一个 名为FreeMarker的比较灵活的模板系统,并创建一个通用的DWR扩展来使用它,这个扩 展以后也可重用。 任何以大写字母开头的单词将会被解释成到文章的一个链接。单击这个单词,将会跳到 对应的文章或者占位符,如果文章不存在,用户可以在此创建文章。很显然,并不是所 有以大写字母开头的单词都应该是文章的链接,因此还需要采用某种方法来覆盖这个链 接(这并不需要什么非常复杂的算法,但是必须是有效的)。 使用数据库来存储Wiki的内容,具体而言就是Apache Derby。另外,可以采用Spring库的 JDBC支持来尽量避免自己编写较低层的JDBC代码。 DWiki将支持“锁定”文章以便编辑,这个锁持续的时间由配置决定。 一般情况下,使用DWR把用户界面连到后台,并且你会发现这样必须撰写的代码量远小于 其他方式。 在真正开始剖析该应用程序的代码之前,先讨论即将使用的几个关键技术,包括FreeMarker 模板库、Apache Derby数据库以及Spring库的JDBC支持。 5.1.1 FreeMarker 正是由于我喜欢不时来点新意,因此先讨论FreeMarker。另外,只要可能,我总是会选择偷 懒(我当然崇拜霍默·辛普森的人生原则),因此想借用FreeMarker主页内容简单讲解FreeMarker 是什么(如果理解成直接引用,也可以)。 FreeMarker是一个“模板引擎”,这个通用工具可根据模板生成文本输出(从HTML到自动生成 的源码等)。这是一个Java包,为Java开发人员提供了一个类库。这个应用程序本身并不服务终 端用户,不过编程人员可能会将它嵌入到自己的产品中。 FreeMarker的设计目的是生成HTML Web页面,特别是用于基于servlet的应用程序中,而这些应
互动出版网 China-Pub. com 专业图书网上第一专营店 独家提供样章 5.1应用程序的需求和目标81 用程序往往会遵循MvC( Model view Controller,模型-视图-控制器)模式。在MVC模式中使用 动态Web页面就是为了将设计人员(HIML创作者)与编程人员分开。每人都做自己擅长的事情。 计人员可以修改页面的外观,而不必要求编程人员修改或者重新编译代码,因为应用程序逻辑 (Java程序)与页面设计( Free Marker模板)是分离的。模板不会受到复杂的程序片段的千扰。即 便在项目中,编程人员和HIML页面创作者是同一个人,这种分离也是非常有用的,因为这样做 可以保持应用程序逻辑清晰,并且便于维护 虽然 Free Marker具有某些编程功能,但是,它并不像PHP那样成熟。准确地说,Java程序负责准 备需要显示的数据(比如发起SQL查询),而 FreeMarker仅负责使用模板生成文本页面,显示这 些数据。 到底什么是模板引擎 简而言之,模板引擎有时候又被称作模板处理程序,它是一套软件或者用于构建软件的组 件,它以模板作为输入。模板类似于一张套用信函,有很多空白嚅要填写。模板引擎负责将模 板与数据模型(即组织成具有一定格式的数据集合)结合起来,从而生成某种类型的文档输出 如果是普通文本,则可能生成PDF、Excl电子表或者你希望的某种格式。 FreeMarker当然就是 这样一种模板,相信你还熟悉另外一种模板JSP!虽然有些人并没有认识到JSP是一种模板技术 但实际上它确实是。 上面的内容对 FreeMarker做了全面的解释!是的,很全面。我想现在你一定很想看一下 FreeMarker实际上是什么样,对吧?下面的命令将满足你的愿望,代码清单5-1列出一个非常简单 FreeMarker模板。 代码清单5-1 Free Marker模板的 Hello World小例子 Hello, $name), from a Freemarker template These are a few of my favorite things t favoriteThings as thing siting, name) 现在,你可能已经注意到上面引用的 remArker描述中的最后一段,“……Java程序负责准备需要 显示的数据…”这实际上意味着你需要构建一个Map,并填充数据。Map中的数据用于替换模板中的 记号,例如s{name}。在代码清单5-2中,可以看到一个为代码清单5-中的模板创建数据Map的简单例 代码清单5-2使用 FreeMarker的非常简单的例子
5.1 应用程序的需求和目标 81 用程序往往会遵循MVC(Model View Controller,模型-视图-控制器)模式。在MVC模式中使用 动态Web页面就是为了将设计人员(HTML创作者)与编程人员分开。每人都做自己擅长的事情。 设计人员可以修改页面的外观,而不必要求编程人员修改或者重新编译代码,因为应用程序逻辑 (Java程序)与页面设计(FreeMarker模板)是分离的。模板不会受到复杂的程序片段的干扰。即 便在项目中,编程人员和HTML页面创作者是同一个人,这种分离也是非常有用的,因为这样做 可以保持应用程序逻辑清晰,并且便于维护。 虽然FreeMarker具有某些编程功能,但是,它并不像PHP那样成熟。准确地说,Java程序负责准 备需要显示的数据(比如发起SQL查询),而FreeMarker仅负责使用模板生成文本页面,显示这 些数据。 到底什么是模板引擎 简而言之,模板引擎有时候又被称作模板处理程序,它是一套软件或者用于构建软件的组 件,它以模板作为输入。模板类似于一张套用信函,有很多空白需要填写。模板引擎负责将模 板与数据模型(即组织成具有一定格式的数据集合)结合起来,从而生成某种类型的文档输出, 如果是普通文本,则可能生成PDF、Excel电子表或者你希望的某种格式。FreeMarker当然就是 这样一种模板,相信你还熟悉另外一种模板JSP!虽然有些人并没有认识到JSP是一种模板技术, 但实际上它确实是。 上面的内容对FreeMarker做了全面的解释!是的,很全面。我想现在你一定很想看一下 FreeMarker实际上是什么样,对吧?下面的命令将满足你的愿望,代码清单5-1列出一个非常简单 的FreeMarker模板。 代码清单5-1 FreeMarker模板的Hello World小例子 现在,你可能已经注意到上面引用的FreeMarker描述中的最后一段,“……Java程序负责准备需要 显示的数据……”这实际上意味着你需要构建一个Map,并填充数据。Map中的数据用于替换模板中的 记号,例如${name}。在代码清单5-2中,可以看到一个为代码清单5-1中的模板创建数据Map的简单例 子。 代码清单5-2 使用FreeMarker的非常简单的例子
互动出版网 China-Pub. com 专业图书网上第一专营店 独家提供样章 5.1应用程序的需求和目标8 import freemarker cache. ClassTemplateLoader import freemarker template Configuration import freemarker template. Defaultobjectwrapper import freemarker template Template import java. io Stringwriter; ort java.io.writer import java. util. Array import java. util. HashMa public class Freemarker Test t public static void main(String[] args)i try i Cuntiguralion tConfig new Configuration); fmConfig. setobjectwrapper(new Defaultobjectwrappero)) onfig. setTemplateLoader (new ClassTemplateLoader( new Freemarker(.getClassO,"/")); HashMap data new HashMap ( data put("name","MY HAVURIIE READER ); ArrayList favoriteThings- new ArrayList; Hash Map tll new HasMMapo ft1 put ("na favoriteThings. add( ft1) HashMap +t2=new HashMap (; favoriteThings. add(ft?) HashMap [- new HashMap() ft3.put ("name","Jericho"); data put(" favoriteThings", favoriteThings) template= fmConfig getTemplate("hello. ft1"); Writer out= new Stringwriter( template process(data, out System. out. println(out toString()) 3 catch(Exception e)i e printStackTrace() 这是一个百分之百可以正常工作的例子,可以在本书的源代码下载包中找到它。经过编译和 行之后,可以看到输出结果如图5-1所示(还可以在命令行中看到编译和执行的过程)
5.1 应用程序的需求和目标 82 这是一个百分之百可以正常工作的例子,可以在本书的源代码下载包中找到它。经过编译和 运行之后,可以看到输出结果如图5-1所示(还可以在命令行中看到编译和执行的过程)
互动出版网 China-Pub. com 专业图书网上第一专营店 独家提供样章 51应用程序的需求和目标83 arker. jar FreemarkerTest Java 图5-1 FreeMarker运行结果 我觉得,这段代码具有一定的自我解释特性。 Free Marker的初始创建阶段,主要创建 Configuration对象并告诉它如何查看数据模型(它是一个对象包装器,不过这是一个更高级 的主题,暂时先跳过),以及告诉 Free Marker如何查找模板(在这个例子中,它是一个相对于使 用 FreeMarker的类的相对路径,因此这个模板必须位于伴随该类的默认包中)。一旦这个阶段完 成,则开始使用典型的方式填充Map,最后实例化这个模板(更特殊的情况是,告诉 Configuration对象你需要的模板,并由该对象来实例化模板),并借助数据Map来处理模板 输出到控制台,就是这样。非常简单! Free Marker提供一个很好的类似编程语言的选择结构,可以使用它们来组成循环、构建分支, 以及定义变量。不过, FreeMarker自己的描述中也讲到,它还不足以构成一个完整的编程语言。 请尽量保持模板简单而又普通,这样才是明智的。 WIki应用程序中的模板不会比这第一个例子 复杂,因此我们不会深入讨论 Free Marker的使用细节。不过,我想你会认同我的观点, FreeMarker 是一个方便使用的小工具,留在身边不会有错! 在这本书中,我们并没有太深入地讨论 Free Marker,不过它的功能远不止这里所介绍的 FreeMarker被应用到许多知名的应用程序和框架中, Struts2就是一个突出的例子,因而它的起 源非常好。我建议你花一些时间浏览 Free Marker网站htp!/ /freemarker sourceforge. net, FreeMarker 的好处之一是,它的文档非常棒,而且 FreeMarker团队会花时间讲解一些很好的例子。我相信它 会增长你的见识。就个人经验而言,我仅在几个月前才看到有 FreeMarke这个项目,但是从那以 后,我发现我会经常使用它,且很容易就可以把它加到我正在编码的环境中。它是我最近几年 来遇到的最有用的库之一,因此花些时间研究一下,我想你会和我一样发现它很有用 5.1.2 Apache Derby 接下来的难题是如何以及在哪里存储用户在DWk中创建的内容。当然,我们有多种选择。 可以将内容存储在文件系统中,实际上我最初也是这样计划的。不过这个方案有不少的问题,最 重要的是在一些环境中并不能在Web应用程序中操作文件系统。我希望DWik至少对读者有用 因此不能假设你必须在不允许写入文件系统的环境中运行DWki 另一个方案是数据库,这是我最后确定的方案,也是引入 Derby的原因 Derby最初是 Cloudscape公司的一个名为JBMS的产品。首次发布时间是1997年。没过多久,准
5.1 应用程序的需求和目标 83 图5-1 FreeMarker运行结果 我觉得,这段代码具有一定的自我解释特性。FreeMarker的初始创建阶段,主要创建 Configuration对象并告诉它如何查看数据模型(它是一个对象包装器,不过这是一个更高级 的主题,暂时先跳过),以及告诉FreeMarker如何查找模板(在这个例子中,它是一个相对于使 用FreeMarker的类的相对路径,因此这个模板必须位于伴随该类的默认包中)。一旦这个阶段完 成,则开始使用典型的方式填充Map,最后实例化这个模板(更特殊的情况是,告诉 Configuration对象你需要的模板,并由该对象来实例化模板),并借助数据Map来处理模板。 输出到控制台,就是这样。非常简单! FreeMarker提供一个很好的类似编程语言的选择结构,可以使用它们来组成循环、构建分支, 以及定义变量。不过,FreeMarker自己的描述中也讲到,它还不足以构成一个完整的编程语言。 请尽量保持模板简单而又普通,这样才是明智的。DWiki应用程序中的模板不会比这第一个例子 复杂,因此我们不会深入讨论FreeMarker的使用细节。不过,我想你会认同我的观点,FreeMarker 是一个方便使用的小工具,留在身边不会有错! 在这本书中,我们并没有太深入地讨论FreeMarker,不过它的功能远不止这里所介绍的。 FreeMarker被应用到许多知名的应用程序和框架中,Struts 2就是一个突出的例子,因而它的起 源非常好。我建议你花一些时间浏览FreeMarker网站http://freemarker.sourceforge.net。FreeMarker 的好处之一是,它的文档非常棒,而且FreeMarker团队会花时间讲解一些很好的例子。我相信它 会增长你的见识。就个人经验而言,我仅在几个月前才看到有FreeMarker这个项目,但是从那以 后,我发现我会经常使用它,且很容易就可以把它加到我正在编码的环境中。它是我最近几年 来遇到的最有用的库之一,因此花些时间研究一下,我想你会和我一样发现它很有用。 5.1.2 Apache Derby 接下来的难题是如何以及在哪里存储用户在DWiki中创建的内容。当然,我们有多种选择。 可以将内容存储在文件系统中,实际上我最初也是这样计划的。不过这个方案有不少的问题,最 重要的是在一些环境中并不能在Web应用程序中操作文件系统。我希望DWiki至少对读者有用, 因此不能假设你必须在不允许写入文件系统的环境中运行DWiki。 另一个方案是数据库,这是我最后确定的方案,也是引入Derby的原因。 Derby最初是Cloudscape公司的一个名为JBMS的产品。首次发布时间是1997年。没过多久,准
互动出版网 China-Pub. com 专业图书网上第一专营店 独家提供样章 5.1应用程序的需求和目标84 确地说应该是199年,Inomⅸx公司收购了 Cloudscape公司,JBMS产品作为其中一部分被收购了 公司并购的势头延续了下去,在2001年,IBM公司购买了 fornix公司的资产,其中包括JBMS。随 后,IM公司将它重新命名为 BM Cloudscape,并向公众发布。最后,也就是2004年8月,IBM公 司把 Cloudscape捐献给了 Apache基金会。之后,它被更名为 Apache Derby,此后的一切则不必说了。 不管如何,对今天来说这是一个历史教训。现在, Derby到底是什么呢?其实比较简单, Derby 是一个完全基于Java的关系数据库。 Derby的代码体积较小,而且是可嵌入的,对今天要实现的目 标来说非常重要。可嵌入意味着可以方便地把它作为应用程序的一个组件,这个特性得益于它有 个内联的JDBC驱动。 Derby还可以用于更加传统的客户机-服务器模式,如果你需要这样的话 Derby最大的优点是安装和使用非常容易! 为安装 Derby,你需要做的仅是将 derby.jar文件加入到自己的项目中,然后就可以开始了 除此之外, Derby的用法与其他你熟悉的 RDBMS基本一致。因此,要开始的话,可以像下面这样 加载 Derby的JDBC驱动 Class forName ( "org. apache derby. jdbC. EmbeddedDriver").newInstance( 只要Deby的JAR文件在类路径中,就可以很好地工作了。在驱动加载完毕之后,可以继续 建立到数据库的连接。 Properties props s new Properties( props. put("user","user1 ) props, put("password","uscr1") Connection conn DriverManager getConnection ("jdbc: derby: testDB; create=true", props); Derby的一项很不错的功能是,当数据库不存在的时候,它可以即时地创建一个数据库。这 就是连接URI中 create=true部分的意思。这样,在开发了一个应用程序之后,你可以立即开始 运行,既快又简单 在获取数据库连接之后,可以继续进行标准的JDBC编程,这与其他的JBC编程并无两样。 当然,如果你喜欢的话,还可以使用 Hibernate或BATS这样的应用程序(假设它们都支持 Derby, Hibernate是肯定支持的, IBATIS好像也是支持的)。还可以使用 Spring框架的JDBC支持。在 WIki 应用程序中,我们就是采用这种技术,接下来,我们会讲到它。 很明显,这里只是简单地介绍 Derby。在讲解DWk代码的过程中会介绍更多功能,但是 Derby提供的功能远不止在本章中看到的这些,因此建议你自己找时间研究它。你会发现,这种 嵌入式工作模式特別方便应用程序的开发。例如,我所在的公司就是使用 Oracle来提供所有的数 据库功能。不过,我们平时会遇到许多情形需要创建或者以后修改数据库,这时候,可以使用 Derby的嵌入式工作模式来开发基本的数据库模式,并让应用程序大致运行起来。当部署应用程 序时,才开始安装 Oracle,并用 Oracle来运行应用程序。除此之外,可嵌入意味着你可以发布一 个使用数据库的应用程序,具体是什么应用,我不知道。比如说,一本书中的Wk应用程序 使用这个应用程序的(或者阅读此书的)人并不需要关心数据库安装,除非他或她想自己安装 数据库。因而,我猜你会需要它的网址,是吧?去访问这个地址吧:htp;∥/db. apache.org/ /derby
5.1 应用程序的需求和目标 84 确地说应该是1999年,Informix公司收购了Cloudscape公司,JBMS产品作为其中一部分被收购了。 公司并购的势头延续了下去,在2001年,IBM公司购买了Informix公司的资产,其中包括JBMS。随 后,IBM公司将它重新命名为IBM Cloudscape,并向公众发布。最后,也就是2004年8月,IBM公 司把Cloudscape捐献给了Apache基金会。之后,它被更名为Apache Derby,此后的一切则不必说了。 不管如何,对今天来说这是一个历史教训。现在,Derby到底是什么呢?其实比较简单,Derby 是一个完全基于Java的关系数据库。Derby的代码体积较小,而且是可嵌入的,对今天要实现的目 标来说非常重要。可嵌入意味着可以方便地把它作为应用程序的一个组件,这个特性得益于它有一 个内联的JDBC驱动。Derby还可以用于更加传统的客户机—服务器模式,如果你需要这样的话。 Derby最大的优点是安装和使用非常容易! 为安装Derby,你需要做的仅是将derby.jar文件加入到自己的项目中,然后就可以开始了! 除此之外,Derby的用法与其他你熟悉的RDBMS基本一致。因此,要开始的话,可以像下面这样 加载Derby的JDBC驱动。 只要Derby的JAR文件在类路径中,就可以很好地工作了。在驱动加载完毕之后,可以继续 建立到数据库的连接。 Derby的一项很不错的功能是,当数据库不存在的时候,它可以即时地创建一个数据库。这 就是连接URI中create=true部分的意思。这样,在开发了一个应用程序之后,你可以立即开始 运行,既快又简单。 在获取数据库连接之后,可以继续进行标准的JDBC编程,这与其他的JDBC编程并无两样。 当然,如果你喜欢的话,还可以使用Hibernate或iBATIS这样的应用程序(假设它们都支持Derby, Hibernate是肯定支持的,iBATIS好像也是支持的)。还可以使用Spring框架的JDBC支持。在DWiki 应用程序中,我们就是采用这种技术,接下来,我们会讲到它。 很明显,这里只是简单地介绍Derby。在讲解DWiki代码的过程中会介绍更多功能,但是 Derby提供的功能远不止在本章中看到的这些,因此建议你自己找时间研究它。你会发现,这种 嵌入式工作模式特别方便应用程序的开发。例如,我所在的公司就是使用Oracle来提供所有的数 据库功能。不过,我们平时会遇到许多情形需要创建或者以后修改数据库,这时候,可以使用 Derby的嵌入式工作模式来开发基本的数据库模式,并让应用程序大致运行起来。当部署应用程 序时,才开始安装Oracle,并用Oracle来运行应用程序。除此之外,可嵌入意味着你可以发布一 个使用数据库的应用程序,具体是什么应用,我不知道。比如说,一本书中的Wiki应用程序, 使用这个应用程序的(或者阅读此书的)人并不需要关心数据库安装,除非他或她想自己安装 数据库。因而,我猜你会需要它的网址,是吧?去访问这个地址吧:http://db.apache.org/derby
互动出版网 China-Pub. com 专业图书网上第一专营店 独家提供样章 51应用程序的需求和目标85 5.1.3 Spring JDBC 除非在过去的两年中一直孤陋寡闻,否则你一定听说过 Spring框架,而且很可能最早在依赖 注入或者loC场合听到过这个概念,它们也是 Spring框架中两个知名的概念。不过,我们将会看到, Spring框架的内容可不止这些,至少在某种程度上是这样。 Spring是一个被称作全栈( full-stack)的框架,这意味着它几乎覆盖了JEE开发人员可能需 要的所有基础构件。它采用了分层的架构,即每个“模块”的功能或多或少都可以独立使用,可 以仅加入自己需要的功能。 Spring涉及方方面面的内容,从之前提到的依赖注入到Web的MVC 再到诸如字符串操作、ORM( Object- Relational Mapping,对象-关系映射)以及JDBC等各种通用 目的的工具函数。 JDBC实际上是DWik需要的功能单元。 Spring JDBC包包含一些方便使用JDBC的类,更重要 的是,使用它不容易出错。使用JDBC编程的问题之一是,开发人员有时非常容易健忘,当他们 操作完数据库之后,会忘记做类似释放数据库连接之类的操作。不幸的是,无论什么样的规则都 不能解决这个问题。这会导致资源泄露,并最终导致应用程序崩溃或者更糟,让整个服务器宕机。 有了 Spring jDBC,这种类型的错误实际上就不可能发生。 使用 Spring JDBC,数据库访问基本上可以简化为两步。第一步,获取工作的数据源;第二 步,执行相关的SQL语句。在第一步中,会使用下面的代码 DriverManagerData Source dataSource- new DriverManagerDataSource O); dataSource. setDriverClassName( Config. getDatabaseDriver(); dataSource. sctUrl(Config. gctDatabascURIO) data Source. setUsername( Config. getDatabaseUsername o) data Source. setPassword( Config. getDatabasePassword() Config类(后面会进一步介绍)包含DWk会用到的许多配置参数,包括连接数据库的细节, 例如,使用的数据库驱动程序、URL、用户名以及密码等。当有了数据源之后,第二步可以通过 下面的代码完成 JdbcTemplate jt new JdbcTemplate(data Source); List rows jt queryForList("SELECT FROM my Table "); JdbcTemplate类是实现 Spring JDBC的关键。你会看到,它提供了一个 query ForDist()方法, 返回一个表示结果集的工ist对象。这里并不需要繁杂的代码来获取 Resultset对象。当然也提 供了一些其他的方法,比如 query ForMap(),用于从数据库中检索单个记录,并返回一个Map对 象,从而使得对记录字段的访问变得非常简单。请注意,此处并没有显示任何连接处理的代码, 也没有显示清除这个类的代码。这是因为数据库和模板能够为我们处理这一切。不用担心关闭数 据库或者处理语句等典型的JDBC工作, 为什么 Spring会迅速流行起来呢 Spring能够快速发展起来在很大程度上归因于原创者 Rod Johnson构建此项目时所坚持的 核心理念。他认为,J2EE世界中的编程过于复杂,可以利用说明规范来简化这个过程。这听 起来可能会有些争议(虽然这几乎是对Rod本人原话的逐字引用),但是我想他真正的意思是
5.1 应用程序的需求和目标 85 5.1.3 Spring JDBC 除非在过去的两年中一直孤陋寡闻,否则你一定听说过Spring框架,而且很可能最早在依赖 注入或者IoC场合听到过这个概念,它们也是Spring框架中两个知名的概念。不过,我们将会看到, Spring框架的内容可不止这些,至少在某种程度上是这样。 Spring是一个被称作全栈(full-stack)的框架,这意味着它几乎覆盖了J2EE开发人员可能需 要的所有基础构件。它采用了分层的架构,即每个“模块”的功能或多或少都可以独立使用,可 以仅加入自己需要的功能。Spring涉及方方面面的内容,从之前提到的依赖注入到Web的MVC, 再到诸如字符串操作、ORM(Object-Relational Mapping,对象-关系映射)以及JDBC等各种通用 目的的工具函数。 JDBC实际上是DWiki需要的功能单元。Spring JDBC包包含一些方便使用JDBC的类,更重要 的是,使用它不容易出错。使用JDBC编程的问题之一是,开发人员有时非常容易健忘,当他们 操作完数据库之后,会忘记做类似释放数据库连接之类的操作。不幸的是,无论什么样的规则都 不能解决这个问题。这会导致资源泄露,并最终导致应用程序崩溃或者更糟,让整个服务器宕机。 有了Spring JDBC,这种类型的错误实际上就不可能发生。 使用Spring JDBC,数据库访问基本上可以简化为两步。第一步,获取工作的数据源;第二 步,执行相关的SQL语句。在第一步中,会使用下面的代码: Config类(后面会进一步介绍)包含DWiki会用到的许多配置参数,包括连接数据库的细节, 例如,使用的数据库驱动程序、URL、用户名以及密码等。当有了数据源之后,第二步可以通过 下面的代码完成: JdbcTemplate类是实现Spring JDBC的关键。你会看到,它提供了一个queryForList()方法, 返回一个表示结果集的List对象。这里并不需要繁杂的代码来获取ResultSet对象。当然也提 供了一些其他的方法,比如queryForMap(),用于从数据库中检索单个记录,并返回一个Map对 象,从而使得对记录字段的访问变得非常简单。请注意,此处并没有显示任何连接处理的代码, 也没有显示清除这个类的代码。这是因为数据库和模板能够为我们处理这一切。不用担心关闭数 据库或者处理语句等典型的JDBC工作。 为什么Spring会迅速流行起来呢 Spring能够快速发展起来在很大程度上归因于原创者Rod Johnson构建此项目时所坚持的 核心理念。他认为,J2EE世界中的编程过于复杂,可以利用说明规范来简化这个过程。这听 起来可能会有些争议(虽然这几乎是对Rod本人原话的逐字引用),但是我想他真正的意思是
互动出版网 China-Pub. com 专业图书网上第一专营店 独家提供样章 52剖析 WIki8 使用说明规范可以很容易地构建应用。一个重要的例子是,在EJB3.0出来之前,企业 JavaBean 直非常复杂,不易于新入门的开发人员学习。对大多数人来讲,它也是复杂的。通过引入POJO 的思想,即在需要的类中注入POJO, Spring框架既能够提供EB承诺的所有优势,又能够简化 EB的代码编写。这就是 Spring能够流行起来的根本原因 有趣的是,现在有的人说 Spring本身至少也和说明规范一样膨胀起来,变得非常复杂了 它应该首先被简化!我把这个留给你(知识丰富的读者)来判断! 关于 Spring JDBC,最后要讨论的一件事情是,它把 SQLException包装在定制的异常类中, 这样你的代码完全可以从标准JDBC类中抽象出来。例如,如果数据库表存在阻止重复记录的约 束,那么当插入相同的记录时 JdbcTemplate类会抛出 DataIntegrityviolationException 对象,你可以捕捉它,并做适当的处理。 Spring JDBC提供的异常层次结构比JDBC的异常机制更 加直观,更加有用,因此使用它们肯定是个好事 Spring JDBC使得我们不必关心JDBC编程的细节,同时也使得JDBC在进程中更加安全。如 果不想(或无需)迁移到目前流行的 Hibernate等ORM工具,或者EJB30,或者类似的东西上,我 极力推荐使用 Spring JDBC,而不要直接进行JDBC编程。它本身非常有用,更不要说它可以节省 大量的调试时间! JDBC包仅是 Spring的一小部分,有大量的相关信息可帮助你更快更好地开发应用程序。花 些时间浏览一下Spring提供的功能,我想你会喜欢在www.springframework.org上发现的东西。 52剖析DWki 好吧,现在开始讲解 WIki应用程序。首先,看一下它的目录结构和文件。在图5-2中,可以 看到它的目录结构。我并没有把img目录展开,由于该目录下存放着用户界面的所有图片,所以 展开它之后抓屏会比较困难!
5.2 剖析 DWiki 86 使用说明规范可以很容易地构建应用。一个重要的例子是,在EJB 3.0出来之前,企业JavaBean 一直非常复杂,不易于新入门的开发人员学习。对大多数人来讲,它也是复杂的。通过引入POJO 的思想,即在需要的类中注入POJO,Spring框架既能够提供EJB承诺的所有优势,又能够简化 EJB的代码编写。这就是Spring能够流行起来的根本原因。 有趣的是,现在有的人说Spring本身至少也和说明规范一样膨胀起来,变得非常复杂了, 它应该首先被简化!我把这个留给你(知识丰富的读者)来判断! 关于Spring JDBC,最后要讨论的一件事情是,它把SQLException包装在定制的异常类中, 这样你的代码完全可以从标准JDBC类中抽象出来。例如,如果数据库表存在阻止重复记录的约 束,那么当插入相同的记录时JdbcTemplate类会抛出DataIntegrityViolationException 对象,你可以捕捉它,并做适当的处理。Spring JDBC提供的异常层次结构比JDBC的异常机制更 加直观,更加有用,因此使用它们肯定是个好事。 Spring JDBC使得我们不必关心JDBC编程的细节,同时也使得JDBC在进程中更加安全。如 果不想(或无需)迁移到目前流行的Hibernate等ORM工具,或者EJB3.0,或者类似的东西上,我 极力推荐使用Spring JDBC,而不要直接进行JDBC编程。它本身非常有用,更不要说它可以节省 大量的调试时间! JDBC包仅是Spring的一小部分。有大量的相关信息可帮助你更快更好地开发应用程序。花 些时间浏览一下Spring提供的功能,我想你会喜欢在www.springframework.org上发现的东西。 5.2 剖析 DWiki 好吧,现在开始讲解DWiki应用程序。首先,看一下它的目录结构和文件。在图5-2中,可以 看到它的目录结构。我并没有把img目录展开,由于该目录下存放着用户界面的所有图片,所以 展开它之后抓屏会比较困难!
互动出版网 China-Pub. com 专业图书网上第一专营店 独家提供样章 52剖析 WIki87 a styles.as o darroch 图5-2DWik应用程序的目录结构 在根目录中,可以看到三个文件: index.jsp、 login.jsp以及 loginok.jsp。第一个文 件是这个应用程序的主要标记页面,后两个文件用于处理用户登录。 头到尾浏览这里的每个目录,你会发现,css目录中只有一个文件 styles.css,它是应 用程序的样式表。跳过imng目录,看下一个目录js,它包含两个文件 DWikiclass.js和 Rol1 overs- Class.js。前者是这个应用程序的主要 JavaScript文件,后者负责处理菜单项的图 片翻转 接下来是 templates目录,它包含这个应用程序所使用的所有 FreeMarker模板。在此不再 一列出,稍后会仔细讲解它们。 templates目录下面是标准的WEB-INF目录,在这个目录里面你可以看到两个文件:一个是 web.xm1,这个当然是 Java Web应用程序的标准描述器,另一个文件dwr.xm1是DWk应用程序的 DWR配置文件。 在WEB-INF目录中,我可以看到有个c1 asses目录。该目录除包含编译后的DWik谈类外,还 包含另外三个文件。第一个是 wiki. properties,它是该应用程序的配置文件。另外两个分别 是 commons-1 ogging. properties和 simple1 og properties,它们是 Jakarta通用日志的配置 文件。 commons-1 ogging. properties文件用于日志包自身的配置, simplelog properties 用于配置 Simplelog日志工具,而 Simplelogt仅仅把日志信息输出到 sysout。日志的配置本身也
5.2 剖析 DWiki 87 图5-2 DWiki应用程序的目录结构 在根目录中,可以看到三个文件:index.jsp、login.jsp以及loginOk.jsp。第一个文 件是这个应用程序的主要标记页面,后两个文件用于处理用户登录。 从头到尾浏览这里的每个目录,你会发现,css目录中只有一个文件styles.css,它是应 用程序的样式表。跳过img目录,看下一个目录js,它包含两个文件DWikiClass.js和 Rollovers- Class.js。前者是这个应用程序的主要JavaScript文件,后者负责处理菜单项的图 片翻转。 接下来是templates目录,它包含这个应用程序所使用的所有FreeMarker模板。在此不再一 一列出,稍后会仔细讲解它们。 templates目录下面是标准的WEB-INF目录,在这个目录里面你可以看到两个文件:一个是 web.xml,这个当然是Java Web应用程序的标准描述器,另一个文件dwr.xml是DWiki应用程序的 DWR配置文件。 在WEB-INF目录中,我可以看到有个classes目录。该目录除包含编译后的DWiki类外,还 包含另外三个文件。第一个是dwiki.properties,它是该应用程序的配置文件。另外两个分别 是commons-logging.properties和simplelog.properties,它们是Jakarta通用日志的配置 文件。commons-logging.properties文件用于日志包自身的配置,simplelog.properties 用于配置SimpleLog日志工具,而SimpleLog仅仅把日志信息输出到sysout。日志的配置本身也
互动出版网 China-Pub. com 专业图书网上第一专营店 独家提供样章 52剖析 WIki88 是一个完整的主题,我不打算用一节的内容来专门讲述它,但是为了不忽略任何一个部分,我将 在这里快速地介绍一下。打开 commons- logging. properties文件,会发现 Simplelog被指定 为默认的日志工具。而在simp1e1og. properties中,则定义了 Simplelog的默认日志级别为 错误级别,com. apress. dwrprojects. wiki包中类的日志级别为调试级别。这意味着,除 了跟踪消息外,可以看到 WIkis中类的所有消息,并且只能看到其他类(例如 Tomcat)的错误或 致命消息。开发类似的应用程序时,按照这种方式设置日志的级别是合适的。 c1 asses目录之后是1b目录,它包含该应用程序所需的所有JAR包。为节省篇幅,在此不详细 介绍这个目录,只简单说明其中包含的包。 commons- logging.jar是 Jakarta通用日志包。 commons-1ang.jar是 Jakarta的通用语言包,包含一组非常有用的“语言扩展”,这是对Java本 身而言的。 derby.jar是 Apache Derby数据库的JAR包。dwr.jar是个什么包,我想你应该知道! freemarker.jar是 FreeMarker模板引擎。之后是四个名为 spring*.jar的包,这里的星号分别 代表 beans、core、jdbc以及tx。在 Spring框架中使用JDBC包至少要包含这四个包 接下来是src目录,其中包含一个bui1d.xm1文件,它是应用程序的Ant生成脚本,还包含 build libs目录,其中包含编译时而不是运行时需要的JAR包〔运行时的包由 servlet容器在运行 时提供),一个是 servlet apl的JAR包,另一个是 USPAPI的JAR包 最后,看看com目录,其中包含 WIki的源代码树和文件。当然,我们会简单介绍它们,这 里就不列出来了。 下面开始详细讲解组成这个应用程序每部分的实际代码,先从配置文件开始。 考虑到本章内容可能会很长,为了节省篇幅,我删去了所有代码列表中的注释(特别是单 独占用多行的注释)以及一些空行。不过,我保诬,会保留适当的注释和空行以组织好代码, 从而方便读者阅读代码 521配置文件 DWkj配置总共用到四个配置文件,其中没有特别复杂的。 Piers morgan说过,如果没有对 它们一一做解释,则是我的失职 1.容器管理的安全配置 在这个应用程序中,我们有一些安全需求。也就是,一个没有在Wik上注册的用户不能创建 或修改文章,甚至不能给文章写评论(不过,可以阅读已有的评论)。为了做到这点,我决定使 用容器管理的安全,也就是J2EE安全。 使用DWR,实现这个目标非常简单,不过首先要配置容器,在这个例子中就是配置 Tomcat (假设你是运行在推荐的环境配置下)。这个配置实际上就是列出可以访问受保护资源的用户。回 Piers morgan是NBC电视台才艺真人秀《美国天才》( America' s Got talent)的评委。许多人都说他和 Simon cowell 样。( Simon是《美国偶像》( American idol)的评委,虽然尖酸刻薄,不过好像总是正确的。)是的,我承认,拿 这样一种流行文化做比方是有点扯远了
5.2 剖析 DWiki 88 是一个完整的主题,我不打算用一节的内容来专门讲述它,但是为了不忽略任何一个部分,我将 在这里快速地介绍一下。打开commons-logging.properties文件,会发现SimpleLog被指定 为默认的日志工具。而在simplelog.properties中,则定义了SimpleLog的默认日志级别为 错误级别,com.apress. dwrprojects.dwiki包中类的日志级别为调试级别。这意味着,除 了跟踪消息外,可以看到DWiki中类的所有消息,并且只能看到其他类(例如Tomcat)的错误或 致命消息。开发类似的应用程序时,按照这种方式设置日志的级别是合适的。 classes目录之后是lib目录,它包含该应用程序所需的所有JAR包。为节省篇幅,在此不详细 介绍这个目录,只简单说明其中包含的包。commons-logging.jar是Jakarta通用日志包。 commons- lang.jar是Jakarta的通用语言包,包含一组非常有用的“语言扩展”,这是对Java本 身而言的。derby.jar是Apache Derby数据库的JAR包。dwr.jar是个什么包,我想你应该知道! freemarker.jar是FreeMarker模板引擎。之后是四个名为spring*.jar的包,这里的星号分别 代表beans、core、jdbc以及tx。在Spring框架中使用JDBC包至少要包含这四个包。 接下来是src目录,其中包含一个build.xml文件,它是应用程序的Ant生成脚本,还包含 build_libs目录,其中包含编译时而不是运行时需要的JAR包(运行时的包由servlet容器在运行 时提供),一个是servlet API的JAR包,另一个是JSP API的JAR包。 最后,看看com目录,其中包含DWiki的源代码树和文件。当然,我们会简单介绍它们,这 里就不列出来了。 下面开始详细讲解组成这个应用程序每部分的实际代码,先从配置文件开始。 考虑到本章内容可能会很长,为了节省篇幅,我删去了所有代码列表中的注释(特别是单 独占用多行的注释)以及一些空行。不过,我保证,会保留适当的注释和空行以组织好代码, 从而方便读者阅读代码。 5.2.1 配置文件 DWiki配置总共用到四个配置文件,其中没有特别复杂的。Piers Morgan①说过,如果没有对 它们一一做解释,则是我的失职。 1. 容器管理的安全配置 在这个应用程序中,我们有一些安全需求。也就是,一个没有在Wiki上注册的用户不能创建 或修改文章,甚至不能给文章写评论(不过,可以阅读已有的评论)。为了做到这点,我决定使 用容器管理的安全,也就是J2EE安全。 使用DWR,实现这个目标非常简单,不过首先要配置容器,在这个例子中就是配置Tomcat (假设你是运行在推荐的环境配置下)。这个配置实际上就是列出可以访问受保护资源的用户。回 ① Piers Morgan是NBC电视台才艺真人秀《美国天才》(America’s Got Talent)的评委。许多人都说他和Simon Cowell 一样。(Simon是《美国偶像》(American Idol)的评委,虽然尖酸刻薄,不过好像总是正确的。)是的,我承认,拿 这样一种流行文化做比方是有点扯远了