JSP 2.0: The New Deal, Part 1 作者: Hans Bergsten, 《JavaServer Pages, 3rd Edition》11/05/2003 期待已久的日子即将到来: 最新版JavaServer Pages (JSP)2.0 规范即将和其他的J2EE 1.4一同发布。新的JSP版本有一个新的飞跃,采用了新的方式:由于新的语言表达式(Expression Language,以下简称为EL)和JSP标准标签库(JSP Standard Tag Library ,以下简称为JSTL)这两种新的方式,在页面中不需要用java,对于开发一般的应用来说,重用代码变得更加容易。更具体来说,JSP 2.0带来了以下的优点:
在众多的书籍中,这是头一个讲解JSP 2.0新特性的文章。在这一部分,我们将看到和EL相关的信息,其他的新特性留到后面。在这里我假定读者已经熟悉JSP 1.2,而且至少听说过JSTL。 你可能对这本第三版的《JavaServer Pages》感兴趣。这本书中,我尽可能在细节上讲述所有的内容,而且并不认为你对JSP或者JSTL了解一切。这本书预计在2003年12月 出版,但是你现在可以在http://www.amazon.com、Barnes&Noble,或者其他在线书店预订。 EL(The Expression Language) 如果过去使用过JSTL,那么你可能已经熟悉 了EL。EL在JSTL 1.0规范中被引入,用来在运行期间对Java表达式中action element属性赋值提供另一种选择。当JSTL EL已经非常迅速的流行起来情况下,还是存在一个问题: JSTL EL 表达式仅仅可以与JSTL和custom action一起使用,怎样才能使用非标准API对EL表达式求值? JSP 2.0中,JSP容器自己可以理解EL表达式。这使你在所有过去只能应用Java表达式的地方应用EL表达式成为可能,比如:标准和定制action的属性值,模板文本。 在我们看具体的例子前,让我们更进一步的看看 什么是EL。EL是从JavaScript中获得启发的一种语言,XPath(一种用来访问XML文档的语言),但是EL在对变量的null值和执行更多 数据类型的自动类型转换的处理上更加宽松。这些新特性对于web应用非常重要,在这些应用中输入通常通过html表单的request parameter来得到。这些参数可能仅仅在某些请求下才能体现出来,而且浏览器经常将request parameter作为文本发送,然而应用程序经常需要把他们作为数字类型、布尔类型(true 或者 false)来使用。通过EL,你根本就很少需要关心缺少某些参数的值或者类型转换。 一个EL表达式包含变量和操作符。任何存储在某个JSP作用范围(如:page、 request、session、application)的bean能被作为一个EL变量来使用。另外,EL支持以下预定义的变量:
操作符描述了你对变量所期望的操作。如果你之前曾经使用过任何编程语言的话,在EL表达式中所使用的操作符对你来说可能看起来很熟悉。因为它们和那些在大多数语言中所支持的操作符一样。
一个EL表达式可以包含:数字、文本(在单引号或者双引号之间)、布尔值、null值。 因为一个EL表达式可以出现在静态文本出现的 地方,因此你必须告诉JSP容器它应该被当作一个EL表达式来处理。你可以通过使用定界符来做到这一点。一个EL表达式总是以”${ }”来标记(一个“$”符号和一个左花括号,右花括号)。这里有一个EL表达式,它将一个命名为amount的变量加5: ${amount + 5} 如果你想要将5加到一个bean的property上,可以使用property访问操作符: ${order.amount + 5} 在当前这个指定的bean或者collection集合中,Property访问操作符(一个“.“符号)告诉EL去寻找名字为amount的property。 ${order['amount'] + 5} 在[]之间的值必须是一个property的名字(就像上面的例子中那样)或者是一个保存property名字的变量(或者是一个完整的EL子表达式)。 EL表达式可以被用来赋值给任何标准的或者定制的JSP行为属性(action attribute),这些行为属性被标记为可以接受动态值(或者请求期间的属性值,就象它被正式调用一样): <c:out value="${order.amount + 5}"/> 在JSP 2.0之前,你不得不使用Java表达式去给一个属性动态赋值。在过去的很多年中,这已经成为语法混乱的一个普遍根源。 最后,EL表达式可以在页面中和模板直接混合使用。当你生成HTML并且需要设置一个动态值给一个属性的时候,这非常方便: <input name="firstName" value="${customer.firstName}"> JSP 1.2中,你不得不使用JSTL的<c:out>来实现同样的事情,最后把各种不同类型的元素混合起来,这导致程序理解起来非常的困难: <input name="firstName" value="<c:out value="${customer.firstName}"/>" >
新JSTL 1.1 Tag Library 标识符 JSTL1.1发布的是一个初级的版本,主要 目的是用来整合JSTL和JSP2.0 。最明显的变化是JSTL1.0 “孪生函数库”(一组库用来接受EL表达式,另外一组用来接受JAVA表达式),而它们已经被一组既可以用于EL表达式也可以用于JAVA表达式的函数库 所代替。 在JSTL 1.1中使用以下标识符:
如果你曾经使用过JSTL1.0,你可能会注意到新的标识符和旧的EL库标试符一模一样,除了加入了“/jsp path” element。你也可能注意到在JSTL1.1中有一个库,包含了EL的函数。我们稍后就会看到。 一个新的EL操作符 在JSP页面中一个非常普遍的需求就是:当某 个条件为真时,要在网页中包含一些文字。在JSP1.2和JSTL1.1中,用具有代表性的<c:if>来实现,但是这样做非常繁琐。 JSP2.0增加了一个新的条件操作符用于EL,以更加优雅的方式来处理这样的情况。这个条件操作符存在于很多编程语言中(比 如:Java,C,JavaScript),因此你可能以前就见过它。它判断一个布尔的条件,当条件为真或者假时,分别取不同的结果。 一个能清楚说明它如何工作的例子: <select name="artist"> <option value="1" ${param.artist == 1 ? 'selected' : ''}> Vesica Pisces <option value="2" ${param.artist == 2 ? 'selected' : ''}> Cortical Control <option value="3" ${param.artist == 3 ? 'selected' : ''}> Vida Vierra </select> 在这里,我使用了EL表达式和条件操作符来选 择是否包含 html 中的 “selected”属性,只有符合条件的 “option” 才被添加 “selected” 属性。如果条件(param.artist==1)为真时,前面的“selected” 才被添加到网页中;否则就添加后面的(在这里是空字符串 ‘’)到页面中。 EL函数 当EL从JSTL规范中移到JSP规范中,它使用了一个如何进行函数调用的技巧。这个EL函数语法非常简单:方法名,紧接着在圆括号中有一组参数:<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> ${fn:length(myCollection)} 这是一个属于标签库中的函数,并且函数名字在页面中所包含的前缀要指定taglib库。在这个例子中,我使用了前缀fn,这是JSTL function库默认的前缀。 标签库描述符(Tag Library Descriptor,TLD)将函数名称映射到一个由JAVA实现的静态方法中:<function> <description> Returns the number of items in a collection or the number of characters in a string. </description> <name>length</name> <function-class> org.apache.taglibs.standard.functions.Functions </function-class> <function-signature> int length(java.lang.Object) </function-signature> </function> 在这里最有趣的element 是<function-signature>。它包含一个函数返回类型的声明,静态的方法的名字,在圆括号中声明该方法所有参数的类型(可以 没有参数或者有多个,参数间用逗号间隔开)。返回值类型和参数类型必须是java的原始类型(Object)或者是其他合法类型。 这个静态方法 length()在Jakarta Taglibs标准库中用类似于下面的代码实现的:public static int length(Object obj) throws JspTagException { if (obj == null) return 0; if (obj instanceof String) return ((String)obj).length(); if (obj instanceof Collection) return ((Collection)obj).size(); if (obj instanceof Map) return ((Map)obj).size(); int count = 0; if (obj instanceof Iterator) { Iterator iter = (Iterator) obj; count = 0; while (iter.hasNext()) { count++; iter.next(); } return count; } if (obj instanceof Enumeration) { Enumeration enum = (Enumeration) obj; count = 0; while (enum.hasMoreElements()) { count++; enum.nextElement(); } return count; } try { count = Array.getLength(obj); return count; } catch (IllegalArgumentException ex) {} throw new JspTagException("Unsupported type")); } 就像你所看到的,在那里没有什么出奇的地方。它是一个常规的静态方法,这个函数中通过对运行期中的参数类别的判断,找出参数的长度。 除了在这个方法中使用的length()方法,JSTL1.1标签库还包含了许多其它经常使用的函数:
结束语: 在这篇文章中,我从EL讲到JSTL1.1规 范、EL新特色和JSTL 1.1函数库。接下来的部分我将要告诉你:关于JSP error-page的改进和增强; jsp:id 属性带来的益处;新的配置属性描述符;JSP2.0如何使JSP操作XML变得更加容易;自定义标签库的新特性。 如果你想要尝试JSP2.0的新特性,我建议 你使用Apache Tomcat 5。它是最早实现了JSP新规范的容器之一。在公布最终版本的JSP 2.0规范之前,一个被标记为“stable”版本的Tomcat是不能被发布的。但是最新的beta版已经被证实是非常稳定的,不要理会beta版的标 记。Tomcat 5在the Jakarta Project site可以下载。 |