我用JSP和ASP编程已经有一段颇长的时间了,在这两种服务器端的编程解决方案中,我越来越觉得JSP的功能要比ASP强大得多。我为什么要把JSP选作首选服务器端web应用程序开发工具呢?当然,JSP迷人的特性和功能不少,但JSP的标签库是让我做出这一决定的最重要诱因之一。
为什么这样说呢?原因有两个方面:维护和开发的速度。服务器端脚本语言其实就像是开发Internet的熔炉。在一个服务器页面上,你可以很方便地混合各种不同的脚本方法和对象。这种页面简直就是建筑Web的混凝土。正是这种“材料”的混合给予了服务器端脚本强大的信息处理能力。它可以让服务器端程序设计人员开发出动态的、灵活的Web页面。但是,另一方面,脚本的自由混合也有其缺点,那就是维护起来非常麻烦,特别是随着项目规模的不断增长而显得尤其严重。更糟糕的是,随着代码的复杂性增加,开发的速度就会变慢,不利于开发中等和大型的web应用,许多中等规模或者大型的服务器端Web应用程序很晚才得以推出而且成本也无法控制。此外,一旦开发完,站点还要找合格的编程者来维护这些颇为复杂的代码,结果让这些程序员成为了一般的Web设计人员,服务器端应用程序在最终的图形设计和实现这两方面上就弱化了。
为了克服这个问题,ASP引进了COM对象技术,而JSP则提供了J2EE作为对策。这些解决方案都是建立在集中的、可重用代码库的机制之上。但是,他们使用起来可就太难了,学习所耗费的时间也很多。还有,这些解决方案并没有减少建立混乱代码的诱惑,结果,我们只能组织起大型的、内部结构良好的开发团队来使用这些技术。对于中等的项目来说,通常都较少使用这样的方法,但事实上,中等的web应用项目才是最多的。因此,许多项目都不得不使用一个不符合它们需要的开发和维护环境。
幸好,JSP提供了一个解决这一问题的更好的办法。标签库(Tag libraries)提供了一个建立可重用代码块的简单方式。一旦标签库设计好,它就可以在许多项目中再次使用。更方便的是,与COM和J2EE不同,只要你懂得写JSP,你无需学习任何其它的技巧就可以建立一个标签库!最后,标签库还改进了Web应用程序的维护性。这种对维护性的改进表现在:轻易地在 JSP页面上就实现了基于XML的可定制接口。结果可想而知,Web设计人员可以建立JSP Web应用程序而无需知道JSP是怎么回事。这样一来,Web开发就成为一项非常富有效率的团队开发任务了。JSP程序员可以建立定制的标签和后端代码模块,而Web设计人员则可以使用定制标签并且全力关注于Web设计本身。标签库解决了代码混乱的问题,而且做得干净漂亮(事实上,XML才是解决这些问题的本质所在,但是标签库还是起到了相当关键的作用)。
什么是标签库?
JSP标签库(也称自定义标签库)可看成是一种通过JavaBean生成基于XML的脚本的方法。从概念上讲,标签就是很简单而且可重用的代码结构。比方说,在我们最新发布的JSPKit(在JSP Insider内)中,使用XML标签实现了对XML文档的轻松访问。请看以下的清单A。
清单A:执行XML/XSL 转换的示例标签及其所在的HTML页面
<%@ taglib uri="http://www.jspinsider.com/jspkit/JAXP" prefix="JAXP"%>
以上的示例使用了简单的标签来访问处在幕后的更强大代码,标签部分的语句首先装载了一个XML文件,然后应用了一个XSL文件来将XML文件中的内容转换成某个表现格式,并发送给客户端,这一切仅仅只是用了一个很简单的标签。定制标签使得JSP项目中很容易创建重用的开放源代码模块,而你所需要的只是标签库和它的文档说明。
标签库的重要特性
1.易于安装在多个项目上
标签很容易从一个JSP项目迁移到其他项目。一旦建立了一个标签库,则只需要将所有的东西打包为一个JAR文件,你就可以在任何的JSP项目中重新使用。因为标签可以重新使用,标签库可以轻松地用于你自己的项目,所以标签库越来越通行。目前,最好的标签资源可以在JSPTags.com这个站点找到。
2.扩展JSP 标签库可以具备JSP规范(JSP 1.2)中的任何特性和功能,你可以无限制地扩展和增加JSP的功能,而无需要等待下一版本JSP的出现。例如,你对JSP的include调用不太满意。你可以建立自己的include标签,该标签执行的是你自己的规范。
3.容易维护
标签库使得JSP的web应用程序非常易于维护,原因有:
(1)标签应用简单,对任何人而言都很容易使用、易于理解。
(2)所有的程序逻辑代码都集中放在的标签处理器和JavaBeans中。这意味着你在升级代码时,无需要对每个使用该代码的页面进行修改,你只需要修改集中的代码文件便可。
(3)如果需要加入新的功能,你也无需修改任何已经存在的页面,可以在标签中加入额外的属性,从而引进新的行为,而其它旧的属性不变,这样所有旧的页面还可以正常工作。 例如你有一个让所有文本变蓝的标签:
但在后来项目中,你又想让蓝色变暗。你可以保留原有的标签,只要为其增加一个新的属性:shade ,如下所示:
所有旧的标签仍然可以产生蓝色的文本,但现在你可以使用同一标签来产生变暗的蓝色文本了。
(4)标签提升了代码的重用性。那些经过多次测试和使用的代码肯定具有更少的bug。所以,使用定制标签的JSP页面也同样具有更少的缺陷,维护起来自然方便多了。
4.快速的开发时间
标签库提供一个简单的方式来重用代码。在服务器端的语言中,其中一个标准的重用代码方式是使用模板。相对于使用模板库,标签库是一个更好的解决办法。使用模板库,你必须为每个项目修改模板或者且建立严格的界面,而标签库则没有这些限制,并且拥有所有面向对象的好处,可以做到灵活和更有扩展性,而且,通过重用代码,你可以花费更少的时间来做开发,更多的时间可以用在设计你的web应用上。标签库的接口也很简单,非常容易做插入、使用和调试。
标签的组成结构
虽然标签库非常易于使用,不过要建立一个标签库的内部实现机制还是颇复杂的,起码要比建立一个简单的JavaBean复杂。这个复杂是来自于标签库是由几部分构成的。不过,你只需要掌握了Java和JSP的知识就够了。
一个简单的标签由下面的元素构成:
1.JavaBean:为了得到Java与生具来的面向对象的好处,可重用的代码应该放到一个独立的代码容器中,也就是JavaBean。这些JavaBeans并不是标签库必不可少的一部分,但它们是标签库用来执行所分配任务的基础代码模块。
2.标签处理器:标签处理器是标签库的真正核心。一个标签处理器(tag handler)引用它所需要的任何外部资源(JavaBean)并且负责访问JSP页面的信息(PageContext对象)。而JSP页面则把页面上设置的标签属性和标签体中的内容都传递给标签处理器,当标签处理器完成其处理过程后,它就会把处理后的输出结果回送给JSP页面做进一步处理。
3.标签库描述符(TLD文件):这是一个简单的XML文件,它记录着标签处理器的属性、信息和位置等信息。JSP容器通过这个文件来得知从哪里及如何调用一个标签库。
4.Web站点的web.xml文件:这是Web站点的初始化文件,在这个文件中,需要定义了Web站点中用到的自定义标签,以及用来描述每个自定义标签的tld文件。
5.发布文件(WAR或JAR文件):如果你想重用自定义标签的话,你需要一个方法来将它由一个项目迁移到其他项目中去。将标签库打包为一个JAR文件是一个简单而且有效的方式。
6.JSP页面上的标签库声明:要在JSP页面中的使用某个自定义标签的话,需要使用标签库标示符在页面上进行声明。
看来要做的工作很多,刚开始用的时候当然会有点棘手,不过其实并不是很难。它的要点并不在于编码,而是在于如何将各部分正确地组织起来。这种层次性的结构是很重要的,它令标签的使用灵活和更容易转移。更重要的事,这些层次可以让整个建立标签库的过程都能通过JSP IDE(JSP的集成开发环境)自动完成。JSP IDE更可以自动完成创建定制标签的大部分工作,而你自己则只需要负责建立代码和标签处理器。
(注意:一个标签处理器仅定义一个自定义标签;一个标签库是几个处理相同任务的标签处理器的集合)
建立你的第一个标签
以下将一步一步地教你如何建立自定义的标签,具体的例子是扩展JSP,令它拥有自己的HTML编码功能。这个功能将所有的<和>字符用 HTML代码来代替。它可以很容易地扩展为做其它的编码处理。为了简化,这个例子只解释了建立自定义标签的基本要素。
创建JavaBean
代码中的任何可重用部分都应该放到一个JavaBean中。这一点是很重要的。这样你就可以在其他项目中重用这些代码了。由于任何放置在标签处理器内的代码在标签外都是不可以重用的,因此将可重用的代码部分独立开来是很重要的。在这个例子总,为HTML编码的逻辑是常用的,因此放到JavaBean中,请参看清单B
清单B:HTML编码JavaBean
/* HTML_Format.java */
public class HTML_Format extends Object implements java.io.Serializable {
/** 创建新的HTML_Format */
public HTML_Format() {}
/** 将一个字符串中所有的所有 < 和 > 字符用响应的HTML编码代替 */
public String HTML_Encode(String as_data)
{
int li_len = as_data.length();
/*string buffer的长度要比原来的字符串长*/
StringBuffer lsb_encode = new StringBuffer(li_len + (li_len/10));
/* 循环替换全部的< 和 > 字符 */
for( int li_count = 0 ; li_count < li_len ; li_count++)
{ String ls_next = String.valueOf(as_data.charAt(li_count));
if (ls_next.equals("<")) ls_next = "<";
if (ls_next.equals(">")) ls_next = ">";
lsb_encode.append( ls_next );
}
return( lsb_encode.toString() );
}
}
创建标签处理器
标签处理器的代码请参看清单C:
清单C:HTML编码标签处理器
import java.io.IOException;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
public class HTML_FormatTag extends BodyTagSupport
{
/* 1) 在标签末将会调用这个函数 */
public int doEndTag() throws JspTagException
{
try
{ /* 2)得到标签中的文本 */
BodyContent l_tagbody = getBodyContent();
String ls_output = "";
/* 3)如果标签体有文本,就处理它 */
if(l_tagbody != null)
{ HTML_Format l_format = new HTML_Format();
/* 3a) 将标签体的内容转换为一个字符串 */
String ls_html_text = l_tagbody.getString();
ls_output = l_format.HTML_Encode(ls_html_text);
}
/* 4)将结果写回到数据流中 */
pageContext.getOut().write(ls_output.trim());
}
catch (IOException e)
{ throw new JspTagException("Tag Error:" + e.toString());
}
/* 让JSP继续处理以下页面的内容 */
return EVAL_PAGE;
}
}
这个处理很简单,它包括有:
1.读入位于开始和结束标签间的文本
2.调用html编码函数
3.将结果返回到JSP页面。
创建标签描述符
我们需要描述自定义标签以让系统知道如何处理。该描述文件的后缀为.tld,TLD文件通常就以标签处理器命名,并存放在“/WEB-INF/”目录之下。请参看清单D。
清单D:HTML编码标签描述器
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib
PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
"http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<TAGLIB>
<TLIBVERSION>1.0</TLIBVERSION>
<JSPVERSION>1.1</JSPVERSION>
<SHORTNAME>HTML_FormatTag</SHORTNAME>
<URI></URI>
<INFO>HTML Encoding Tag </INFO>
<TAG>
<NAME>HTMLEncode</NAME>
<TAGCLASS>HTML_FormatTag</TAGCLASS>
<INFO>Encode HTML</INFO>
</TAG>
</TAGLIB>
更新Web XML文件
现在可以告诉JSP容器如何使用标签库了。为此要修改web.xml文件,具体说来是要在其中加入一个taglib的项目来注册该标签库,并为标签分配一个URI。URI是Web站点上唯一应用于这一特定标签的索引。由于标签今后还可能用在不同的Web站点上,所以你最好采用完整的URL和/或者包名字(package name)来保证这一唯一性。这个例子是简化了,示例代码请参看清单E。
清单E:修改web.xml文件
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<WEB-APP>
<TAGLIB>
<TAGLIB-URI>
HTMLEncode
</TAGLIB-URI>
<TAGLIB-LOCATION>
/WEB-INF/HTML_FormatTag.tld
</TAGLIB-LOCATION>
</TAGLIB>
</WEB-APP>
使用新的标签
自定义的标签设置好后,就可以用在你的JSP页面上了。要做到这一点,只需要在页面上使用taglib指示命令声明所要采用的标签即可。标签通过其唯一的 URI被索引,然后被分配给一个名字空间前缀(prefix)。这一前缀并没有什么特别的意义,只要它不与其它的名字空间冲突便可,可以任意。请参看以下的清单F和G。
清单F:在一个JSP页面上使用HTML编码标签
<%@ taglib uri="HTMLEncode" prefix="Examples" %>
<PRE>
<?XML:NAMESPACE PREFIX = Examples /><Examples:HTMLEncode>
< Hello , Simple sample >
</Examples:HTMLEncode>
</PRE>
清单G:范例代码的输出
< Hello , Simple sample >
which displays as:
< Hello , Simple sample >
通过这个标签,我就将该页面的所有代码编码了。所有的自定义标签都是在服务器上处理的。这意味着你将不会在输出的页面上看到自定义的标签。
正如你所看到的那样,建立标签并非难事。最麻烦的是学习标签处理器的整个细节。这是一个很强大的功能,我们不过是触及了皮毛。由于这一过程需要采取的步骤很多,所以刚入门的JSP程序员可能在建立标签的时候会觉得很困惑。
结论
标签库是JSP最重要的特性之一,它还处在不断的发展中。它的确是一个新事物,因此还没有被广泛采用,不过自定义标签库已经剥去了它的神秘面纱,越来越多的开发者也开始关注和使用它了。在2001年末,可预料标签库将是许多JSP项目中的一个很常见的特性。
在这篇文章中只简要地讨论了标签库的好处。标签库实际上还有许多其它强大的功能。标签库促使JSP开发进入了前所未有的新天地。对JSP开发人员来说这确实是一种很令人振奋的新技术,因为他们得到了一个可将JSP转到各个应用并且建立任何类型web应用的工具。标签库让JSP变成了最丰富、最具动态开发能力的、强大的Web编程环境。它的功能只受我们的想象和创造力限制。