创建自己的基于 Java 的滚动横幅广告
站长注以前做过这个例子不过好象是mysql+tomcat 现在这两个软件都升级了而且我自己正准备在一个web应用中使用mysql +tomcat 把这个例子再调试一下还真发现了两个问题
要在webxml文件中命名BannerServlet如下所示
<?xml version= encoding=ISO?>
<!DOCTYPE webapp PUBLIC //Sun Microsystems Inc//DTD Web Application //EN app__dtd>
<webapp>
<servlet>
<servletname>BannerServlet</servletname>
<servletclass>imgBannerServlet</servletclass>
</servlet>
<servletmapping>
<servletname>BannerServlet</servletname>
<urlpattern>/BannerServlet</urlpattern>
</servletmapping>
</webapp>
BannerServletjava中有两处要改动
dbHandlersetQueryString(UPDATE ADS SET NUMBEROFIMPRESSIONS = [NUMBEROFIMPRESSIONS]+ WHERE IMAGEFILE = ?);
改为
dbHandlersetQueryString(UPDATE ADS SET NUMBEROFIMPRESSIONS = NUMBEROFIMPRESSIONS+ WHERE IMAGEFILE = ?);
dbHandlersetQueryString(UPDATE ADS SET NUMBEROFCLICKSREMAINING = [NUMBEROFCLICKSREMAINING] WHERE IMAGEFILE=?);
改为
dbHandlersetQueryString(UPDATE ADS SET NUMBEROFCLICKSREMAINING = NUMBEROFCLICKSREMAINING WHERE IMAGEFILE=?);
象 这样的公司依靠在 Web 上提供横幅广告服务已经赚了很多钱他们提供的服务很棒但为什么要为自己本来可以做的事情而付钱呢?在本文中企业 Java 顾问 Javid Jamae 和 Kulvir Bhogal 将演示如何使用全开放源码环境Apache TomcatMySQL 和 MySQL JDBC 驱动程序来创建滚动横幅广告首先他们将向您逐步介绍必需的 Tomcat 和 MySQL 安装然后向您演示如何安装 MySQL JDBC 驱动程序以允许运行在 Tomcat 中的 Java servlet 与 MySQL 进行通信
当因特网开始从教育和政府信息存储器转变成国际商业中心起横幅广告就已经出现了滚动横幅是 Web 页面上一块已分配的空间每次装入或重新装入 Web 页面时就用该空间内来显示广告 — 随机显示或基于某些业务逻辑来显示驱动滚动横幅广告的程序虽然相当简单但却是重要的广告工具正如它们的同类如半分钟广播和电视广告一样这些动态广告工具允许单个 Web 页面显示不同来源的广告并使不同公司针对相同的观众建立他们产品和服务的品牌效应
无论您怎么看待 Web 横幅广告(是的我们都发现它们有时令人讨厌)它们已成为因特网上的一种生活方式存在这样的事实Web 的观众由庞大的消费者群体所组成他们的金钱使电子商务的车轮得以转动在因特网市场营销的短暂历史中电子商务所有者已表现出他们愿意花大把的钱在热门站点上做横幅广告
有些公司(如 )已经通过担当应用程序服务供应商(ASP)提供诸如跟蹤对特定横幅广告的点击之类的服务从 Web 横幅现象中获利随后这些 ASP 告诉广告客户他们的 Web 广告活动的有效程度
当然象 这样的 ASP 是要收费的如果您和我们一样那么您不会愿意在能够免费得到服务时还要花钱稍等一会儿 — 您可能已经听过世上没有免费的午餐这句话不过别担心本文将花费的只是您的时间事实上我们将向您演示如何组成一个开放源码(即免费)环境来建立您自己的功能强大的 Web 横幅跟蹤系统为了完成这一任务我们挑选的武器是 TomcatMySQL一个 Java servlet 和几个助手类兴奋吗?那么让我们进行软件安装吧
安装 Tomcat 和 MySQL
在这一节中我们将逐步介绍 Tomcat 和 MySQL 的安装然后我们将向您介绍如何安装支持这两个应用程序相互通信所需的驱动程序
安装 Tomcat
下载并安装 Tomcat对于本文使用Tomcat Windows 版它有一个很好的安装软件包安装应该非常简单但如果您遇到麻烦请查阅 Tomcat 文档因为 Tomcat 非常流行所以在新闻组和 Web 上也可找到大量的帮助
安装了 Tomcat 之后还要完成几个步骤以设置我们的滚动横幅 Web 应用程序首先我们将在 [installdir]\webapps
目录下创建一个名为 banner
的子目录然后在 banner
子目录下创建标准的 Web 应用程序目录结构
[installdir]\webapps\banner[installdir]\webapps\banner\WEBINF[installdir]\webapps\banner\WEBINF\classes[installdir]\webapps\banner\WEBINF\lib
接下来我们将添加指向我们 Web 应用程序的 contextcontext 只是一个别名它告诉 Tomcat 在哪里可以访问 Web 应用程序我们的 context 路径将是 /banner
它将指向我们刚刚创建的 banner
子目录在用户输入 /localhost:8080/banner 后,将转至 webapps
下的顶级 banner 目录。tW.Wingwit.cOM如果他想运行我们的 BannerServlet
(将存在于 WEB-INF/classes
目录中),他可以使用 /localhost:8080/banner/BannerServlet。
要添加 /banner
context,首先,我们需要编辑 Tomcat conf
目录中的 server.xml 文件。 在<Host>和</host>之间加上
<!-- BannerAd Context --><Context path="/banner" docBase="banner" debug="0" reloadable="true" crossContext="true"/>
添加了 context 标记之后,重新启动 Tomcat 以使对 server.xml 文件所做的更改生效.
安装 MySQL
MySQL 因其价格(免费)而成为一种强有力的数据库,许多公司都使用 MySQL 来处理它们的数据。由于许多公司都想以较低的预算进入 Web 市场,所以使用 MySQL 的公司的数量每天都在增加。开放源码社区已张开双臂欢迎 MySQL。有关这个功能强大的数据库的文档十分丰富,而且同时有 Linux 和 Windows 版本。
下载并安装 MySQL(站长下载了mysq 5.0.28 )
使 MySQL 和 Tomcat 共同工作
使 MySQL 和 Tomcat 相互通信可能有些困难。然而,通过使用 JDBC API,我们将能够相对容易地从 Java 类使用 SQL 与 MySQL 数据库通信。
首先,要从这里下载驱动程序的合适的 JAR 文件。下载名为mysql-connector-java-5.0.0-beta.zip 的文件。接下来,将文件解压缩(unjar 或 unzip)至一个临时目录。最后,将包含驱动程序的文件从解压缩的目录结构复制到 WEBAPPS/BANNER/WEB-INF/lib
目录中,然后重新启动 Tomcat。在我们下载的驱动程序版本中,文件的名称是mysql-connector-java-5.0.0-beta-bin.jar
我们本可以使用 JDBC/ODBC 桥驱动程序与 MySQL 通信,但我们认为本机驱动程序在性能上有更大优势(尽管我们没有运行任何基准测试程序来证实我们的假设)。对于这个应用程序,在性能上它可能不会有很大区别,但我们决定演示如何使用本机 JDBC 驱动程序,以便您不必在设计较大的应用程序时才去了解它。
滚动横幅应用程序
既然我们已经安装了所有的软件,就让我们来看一下这个应用程序能够做什么以及我们是如何组织其架构和开发它的。
实质上,您可以使用我们的横幅 servlet 执行两个操作。首先,您可以用它查看 Web 页面上的随机横幅图像,每次装入包含横幅广告的 Web 页面时,该随机横幅图像就会出现。其次,您可以点击横幅图像,这将使您转至与装入的这个图像对应的链接。
按照 HTML,其代码类似于:
<a ><img src="...Random Image..."/></a>
如果希望装入随机图像,那么显然图像标记不能指向静态图像文件,因此我们将指示它运行 servlet,本例中将调用 BannerServlet。我们将使用 HTTP GET
方法参数来指示 servlet 为我们提供图像。因此,图像标记类似于:
<img src=//localhost:8080/banner/servlet/BannerServlet?type=image"/>
该标记调用 servlet 并传入参数键值对 type=image
。servlet 的 service()
方法会解释该请求,然后向浏览器返回随机图像。当然,servlet 必须以某种方式记住将哪个图像发送给了客户机,这样当客户机点击该图像时,它就知道应链接至何处。我们会把与发送的图像相关的元数据存储在客户机的会话上,这样,当用户点击图像时,将从他的会话装入元数据,并重新导向至适当的 URL。
链接标记看起来几乎与图像标记相同:
<a ><img src=//localhost:8080/banner/servlet/BannerServlet?type=image"/></a>
当用 type=link
键值对调用 servlet 时,servlet 抓取横幅的元数据并将用户重新路由至适当的 URL。
代码和 CLASSPATH 设置
为了使用与本文一起提供的代码,您必须首先解压缩这个 zip 文件,然后用命令行 javac
编译器或您喜欢的 IDE 编译这些.java
文件。要编译该代码,请设置 CLASSPATH
以包含这两个 JAR 文件(站长注:第二个就行了)。
mysql-connector-java-5.0.0-beta-bin.jar
servlet.jar
(如果它没有和您使用的 JDK 打包在一起)
将已编译的 .class
文件复制到先前创建的 [tomcat_installdir]\webapps\banner\WEB-INF\classes
目录中。必须将作为示例提供的图像文件和 < 文件放入 [tomcat_installdir]\webapps\banner
目录。
数据库设置
我们应用程序的数据库部分只是用来持久存储系统中每个横幅的元数据。换句话说,我们实际上并不在数据库中存储图像文件,而只是存储指向每个图像文件的引用。在我们的数据库中,我们将使用七个列来描述每个横幅广告。
表 1 中的描述说明了每条记录将包含的内容。我们实际上将在应用程序中只使用这七个数据库列中的五个。我们的版本中没有使用 CustomerName
和 NumberOfClicksPurchased
,但我们把它们作为占位符放置在这里以用于扩展。您可以很容易地扩展这个应用程序,并把它用于现实的商业应用程序,其中客户为每个横幅的点击次数付款。
表 1. 数据库字段 字段名称描述示例ImageFile对横幅图像物理位置的引用/images/sitea.gifURL站点用户点击横幅之后,应重新路由他们的目标 URLCustomerName购买横幅的客户名称John DoeNumberOfClicksPurchased用户购买的点击次数140NumberOfClicksRemaining客户剩余的点击次数139NumberOfImpressions横幅已被显示的次数23BannerWeight正在显示的这一横幅的权重10
当然,在现实环境中,您会有一个以上的站点横幅。根据您的横幅“赞助商”支付的金额与其他赞助商的比较,您可能希望较多地或较少地显示他的横幅。BannerWeight
字段将被用来实现这一功能。我们已经实现了一个非常简单的加权系统,每个要显示的横幅所具有的百分比概率为:
(BannerWeight / Sum of all BannerWeights) * 100
将刚才所说的内容转换成 SQL,您可以使用 MySQL Monitor 输入以下语句:
mysql> create database BANNER;
要连接到数据库,您可以输入:
mysql> use BANNER;
接下来,我们创建表:
mysql> create table ADS(IMAGEFILE VARCHAR(50) NOT NULL, URL VARCHAR(50) NOT NULL,CUSTOMERNAME VARCHAR(50),NUMBEROFCLICKSPURCHASED INT(4),NUMBEROFCLICKSREMAINING INT(4) NOT NULL,NUMBEROFIMPRESSIONS INT(4) NOT NULL,BANNERWEIGHT INT(4) NOT NULL);
ADS 表的“describe”操作类似于图 1 所示。
图 1. ADS 表
您需要用一些样本值来填充数据库以便确定所构建的数据库是否正确。该项目的 zip 文件中包括一些样本横幅(GIF 格式),可以使用它们以了解应用程序运行时的情况。当然,对于 Web 横幅 URL,需要声明您决定放置横幅文件的位置。可以按照下面的 SQL 语法将横幅“注册”到数据库中:
mysql> insert into ADS values('/sitea.gif','', 'John Doe',100,100,0,10);
使用这一语法将表 2 中显示的记录插入到数据库中。
表 2. 数据库记录 IMAGEFILEsitea.gifsiteb.gifsitec.gifsited.gifURL/
/
/
/
CUSTOMERNAMEJohn DoeAlbert EinsteinJane DoeMadonnaNUMBEROFCLICKSPURCHASED100203020NUMBEROFCLICKSREMAINING100203020NUMBEROFIMPRESSIONS0000BANNERWEIGHT10103010
注:Web 横幅 URL 位于本地主机,仅供测试之用。在生产环境中,URL 会指向 GIF 文件的实际位置。该 URL 实际上可以是因特网上的任何位置。
既然我们有了数据库,就需要使用刚刚填入其中的数据。我们将用 Java servlet 做到这一点。下面描述 Java servlet 代码,它将“推动”我们的努力。您或许希望花一些时间来通读该项目 zip 文件中的 BannerServlet.java 代码。如果您觉得困难,别担心;我们将花一些时间解释代码是如何工作的。
横幅体系结构
这个横幅广告 servlet 的体系结构十分简单。我们将使用四个类:
通用的 Logger
类,一个将日志消息写到文本文件的类。
名为 BannerServlet
的 servlet,每次显示横幅图像(即每次装入页面)和每次点击横幅图像时,将调用它。该 servlet 是我们应用程序的核心。
通用的 DBHandler
类,BannerServlet
将用它与 MySQL 数据库进行通信。
Banner
类,我们用它来创建对象,这些对象包含数据库中每个横幅所拥有的所有元数据。
该 BannerServlet
类和 Banner
类特定于我们的应用程序。它们相当简单,您可以方便地扩展它们来添加更复杂的特性。
DBHandler
和 Logger
类的好处在于:您可以在任何您实际编写的、需要与数据库通信或写入日志文件的应用程序中重用这两个类。
我们将更详细地讨论所有这四个类,这样您就可以理解 servlet 是如何工作的,以及它如何使用 DBHandler
与 MySQL 数据库通信。
Logger 类
Logger
类非常简单。它有单个字段,代表我们正在写入日志的 File
对象。您可以将对单个 Logger
对象的引用传递给几个类,让这些类都写入同一个日志文件。Logger
类允许您做以下事情。您可以:
创建日志记录器(logger)对象
向日志文件添加分隔符(“------”字符串)
通过传入调用方法的名称和日志消息添加一条日志项
添加方法启动的缺省消息
添加方法结束的缺省消息
删除日志文件
返回由日志记录器对象使用的 File
对象
我们将同时在 DBHandler
类和 BannerServlet
中使用 Logger
对象。
DBHandler 类
DBHandler
是非常多用途的类,可用来通过 JDBC 与几乎任何数据库进行相互操作。它需要一个具有 JDBC/ODBC 驱动程序(我们正用此驱动程序来连接到数据库)名称的字符串、一个具有数据库(我们为其设置了 DSN)名称的字符串和一个 Logger
参数。Logger
参数在 DBHandler
完成其“神奇”任务时告诉它在哪里打印输出消息。DBHandler
的构造器打开到数据库的连接。在使用 DBHandler
完成任务后,必须用 close()
方法关闭它。
在创建了 DBHandler
对象之后,必须创建查询来执行。使用 setQueryString()
方法传入包含查询的字符串,查询可以是 PreparedStatement
类的形式。
PreparedStatement
是 JDBC 的一个很好的功能。它允许您定义一个查询字符串,使用问号字符替代查询中的变量标准。随后可以使用 PreparedStatement
类的 setter 方法来设置查询中未知元素的值。幸运的是,DBHandler
类为我们处理所有这些事情。我们只需设置想要执行的查询,然后调用 DBHandler
的某个方法,如下所示:
public Banner getBannerByName(String name) { ... ... dbHandler.setQueryString("SELECT * FROM ADS WHERE NAME=?"); ResultSet rs = dbHandler.lookup(name); dbHandler.close(); ... ...}
可以使用 lookup()
方法来执行 SELECT
查询,使用 executeUpdate()
方法来执行 UPDATE
查询,以及使用 insert()
方法来执行 INSERT
查询。还有一个 execute()
方法,它不需要参数,可以执行任何没有 PrepareStatement
参数的查询。
Banner 类
Banner
类只是一组直接对应于 ADS 数据库表中各列的值的 setter
和 getter
方法。
BannerServlet 类
BannerServlet
是我们这个应用程序的核心。我们将把该类分成几个不同部分来向您讲解。通过浏览代码,您将对如何用 DBHandler
类连接到数据库更加熟悉。
字段
BannerServlet
使用五个字段:
String _databaseUrl:要访问数据库的名称(jdbc:odbc:\\localhost\BANNER
)。
String _driverName:用来与数据库通信的驱动程序的名称。正如上面所描述的那样,我们将使用 MM MySQL JDBC 驱动程序。该驱动程序的名称是 org.gjt.mm.mysql.Driver
。
Logger _logger:Logger
类的名称,用此类来记录我们应用程序中发生的所有事件。
HashMap _banners:所有 Banner
对象的 HashMap。用 servlet 的 init()
方法填充该 HashMap。将数据库表中的每一行转换成存储在 HashMap 中的一个 Banner
对象。我们过一会儿将详细说明这一点。
int _totalWeight:所有 Banner
权重之和。该值也是在 init()
方法中设置的;我们将很快讨论这一点。
init()
任何 servlet 的 init(ServletConfig)
方法都在容器首次装入该 servlet 时被调用。在这里,容器就是 Tomcat。Tomcat 生成并传入 ServletConfig
对象,该对象包含容器设置的缺省配置信息以及开发人员(您)在 servlet 的配置文件中可以进行设置的定制配置信息。对于我们的用途,不需要传入任何配置信息,但您有时可能需要扩展 servlet,并使用这一功能。
我们调用 super.init()
之后在 init()
中所做的第一件事是初始化 HashMap 变量 _banners
,并将 _totalWeight
设置为 0。然后,连接到数据库,以 ResultSet
的形式从 ADS 表获取所有行。我们使用 for
循环对 ResultSet
进行循环遍历,从每行构造一个 Banner
对象,接着,把 for 循环的索引作为散列值,将 Banner
对象添加到 HashMap。(我们也可以方便地使用 Vector 或其它一些 Collection
类来完成同样的任务。)
现在,内存中有了一个包含所有 Banner
的 HashMap。如果更新数据库,那么只需调用 init()
方法就可重新装入 HashMap。我们将在 increaseImpressions()
和 decreaseClicksRemaining()
方法中用到这一点。
service()
service()
方法是在我们的 BannerServlet
继承的 HttpServlet
类中定义的,可以处理任何请求,不管它是 GET
方法还是 POST
方法。对于 service()
方法的实现有两个核心部分。第一个部分处理 Web 页面发送图像请求时 servlet 的行为,第二部分处理链接请求。
最后,我们看一下从客户机发送来的 type
参数。如果 type
的值是 image
,那么我们从数据库获取一个随机的 Banner
对象,将该 Banner
对象添加到用户的会话,同时增加这一给定横幅的已显示次数,并将用户路由至 Banner
对象的图像字段中所引用的图像。
如果 type
的值是 link
,那么我们从会话中除去 Banner
对象,减少该横幅的剩余点击次数,并将用户重定向至 Banner
对象的 URL 字段中指定的链接。
其它方法
getRandomBanner()
、increaseImpressions()
和 decreaseClicksRemaining()
都是助手方法,从 service
方法中调用它们。getRandomBanner()
使用一个简单的算法从 _banners
HashMap 随机地选择一个横幅。increaseImpressions()
和 decreaseClicksRemaining()
使用 DBHandler
连接到数据库并更新给定 Banner
的信息。在这两个方法的结束部分,我们调用 init()
方法将已更新的 Banner
信息重新装入到 HashMap。
结束语
我们已经创建一个应用程序,该应用程序演示了 Apache Tomcat 和 MySQL 相互之间如何通信,并向您提供了一个能为您处理大多数数据库工作的、非常有用的可重用工具。您可以以几种方式来扩展这个应用程序,这些已超出本文的范围。正如我们前面描述的那样,您可以把这个应用程序扩展成一个系统,在这个系统中,您可以根据特定点击次数或者甚至是特定的显示次数向客户收费。可以很容易地用某个其它字段替代数据库中的 CustomerName
字段,这个字段可以是另一个包含所有客户信息的表中的主键。
您可以扩充 DBHandler
类以处理数据库连接合用。此外,可以将希望用于应用程序的查询具体化成文本、特性或 XML 文件,从而允许扩充或更改查询定义而无需编写更多代码。