· 使用 DBTag 的标记库示例
通常善意的朋友和专家会告诉 JSP 程序员新手一些基本知识,其中之一就是不要使用 scriptlet。相反,他们会让 JSP 程序员新手使用定制标记。我们利用定制标记扩展 JSP 平台的功能:同代码库相连的定制 XML 样式标记实现预期功能。我们将会在下个示例中看到 DBTag 的工作情况。
Jakarta TagLibs Project 是 Jakarta Project(请参阅参考资料)的一个子工程,该工程是 Java Servlet 和 JavaServer Pages 技术的官方参考实现。
在 Jakarta TagLibs Project 的支持下开发的一个包是 DBTag 定制标记库(以前叫做 JDBC 标记库)。清单 4 里的 JSP 页面把 scriptlet 替换成定制标记,实现的点击计数器和清单 3 中的一模一样。
清单 4. JSP 页面使用 DBTag
<HTML>
<HEAD>
<TITLE>Jakarta DBTags example</TITLE>
</HEAD>
<BODY>
<%@ taglib uri="http://jakarta.apache.org/taglibs/dbtags" prefix="sql" %>
<%-- open a database connection --%>
<sql:connection id="conn1">
<sql:url>jdbc:mysql://localhost/test</sql:url>
<sql:driver>org.gjt.mm.mysql.Driver</sql:driver>
</sql:connection>
<%-- insert a row into the database --%>
<sql:statement id="stmt1" conn="conn1">
<%-- set the SQL query --%>
<sql:query>
insert counters(page,hitCount) values(´<%=request.getRequestURI()%>´, 0)
</sql:query>
<%-- the insert may fail, but the page will continue --%>
<sql:execute ignoreErrors="true"/>
</sql:statement>
<%-- update the hit counter --%>
<sql:statement id="stmt1" conn="conn1">
<%-- set the SQL query --%>
<sql:query>
update counters set hitCount = hitCount + 1 where page like ´<%=request.getRequestURI()%>´
</sql:query>
<%-- execute the query --%>
<sql:execute/>
</sql:statement>
<P>This page has been hit
<%-- query the hit counter --%>
<sql:statement id="stmt1" conn="conn1">
<sql:query>
select hitCount from counters where page like ´<%=request.getRequestURI()%>´
</sql:query>
<%-- process only the first row of the query --%>
<sql:resultSet id="rset2" loop="false">
<sql:getColumn position="1"/>
</sql:resultSet>
</sql:statement>
times. The page counter is implemented using the Jakarta Project´s
DBTags tag library, calling JDBC indirectly.</P>
<%-- close a database connection --%>
<sql:closeConnection conn="conn1"/>
</BODY>
</HTML>
我不知道您的感受如何,可我感觉到有一点失望。在我看来这似乎还不如 scriptlet 示例清晰,而且我知道也不会有哪个不编程的 HTML 页面设计者会对此感到满意。但是问题出在哪儿呢?毕竟,我们已听从了大多数人的建议:我们抛弃了 scriptlet,用定制标记取而代之。
开发定制标记库相对简单些,但也要费些思考,而且费时。我常推荐的做法是标记库的作者们先用 scriptlet 为标记行为建立原型,再把这些 scriptlet 变成标记。
一种可选择的解决方案是使用 Allaire 的 JRun Server Tag(JST),使您可以通过把每个标记作为一个 JSP 页面(以 .jst 为扩展名)来编写,从而为标记库建立原型。JST 把页面转变成运行时标记处理程序,这样 JST 技术对客户机页面来说就是透明的。虽然 Allaire 宣称“目标是把 JST 建成一种可移植技术以使 J2EE 社区的所有成员都能从中受益”,但 JST 目前还只能在 JRun 中使用。时间将会证明 JST 是否会成为开发标记更通用的工具。与此同时,我们发现 scriptlet 为开发标记的业务逻辑奠定了良好的基础;逻辑经调试后,我们把它迁移成为标记处理程序类。
关于标记库 Allaire 没有告诉您的是:标记设计是一种语言设计。迄今为止,所写的大多数标记库是由程序员为程序员写的;这些标记的语义适合于其它的程序员。不仅如此,还记得模式和表示的分离吗?DBTag 对这一点不太支持。sql:getColumn 标记同 jsp:getProperty 动作类似:它把标记的结果直接发给输出流。这给 DBTag 的利用与把输出转化成要求的格式之间的分离带来了困难。最后,请注意清单 3 和 清单 4 的逻辑差异。DBTag 的 execute 标记使用所有来自通过 JDBC 发送的 update 语句的更新计数;可以回收的只有查询结果。这意味我们无从知道 update 语句更新了多少行。因此我们不得不切换 update 和 insert 语句;我们总是试图插入新记录、迫使 DBTag ?略任何错误,然后执行更新。
对 DBTag 标记库公正的评价是,对于程序员来说这是个不错的标记库。除更新计数的使用外,代码提供的与 JDBC 的映射相当不错。但其中也存在问题:标记提供的只不过是对 JDBC 包的直接翻译。除隐藏了一些异常处理之外,标记库实际上并没有提供对 scriptlet 任何抽象。这对从功能中分离表示当然于事无补。
因此,真正的问题不在于是使用 scriptlet 还是使用标记;这种问题不是分离功能和表示的问题的原因,而是结果。解决方案是要以适当的说明级别上为表示页面的作者提供更高级别的功能。认为标记优于 scriptlet 的原因在于:根据定义,scriptlet 是编程,而标记可以表示高级概念。
(未完待续)








