注意这里讲介绍自定义标签库(taglib),将原本需要写在jsp中的java代码封装起来,成为可复用的组件。 taglib本意是为了弥补jsp的先天不足,但它的笨重与复杂也颇为经典,可惜有的地方又不得不用,如果对其没有耐心尽可跳过。 如果你不满足以下任一条件,请继续阅读,否则请跳过此后的部分,进入下一章:第 10 章 综合电子留言板。
回到联系簿的例子第 5.2 节 “Read(读取)”,不觉得这个list.jsp中的java代码太碍眼了吗? <% List list = contactDao.getAll(); for (int i = 0; i < list.size(); i++) { pageContext.setAttribute("contact", list.get(i)); pageContext.setAttribute("row", i % 2 != 0 ? "odd" : "even"); %> <tr class="${row}" onmouseover="this.className='highlight';" onmouseout="this.className='${row}';"> <td>${contact.username}</td> <td>${contact.sex}</td> <td>${contact.email}</td> <td>${contact.qq}</td> <td>${contact.descn}</td> <td><a href="edit.jsp?id=${contact.id}">修改</a> | <a href="remove.jsp?id=${contact.id}">删除</a></td> </tr> <% } %> 如果能像使用jsp动作(action)一样,使用<jsp:xxx>的形式进行循环该多好啊?可惜jsp动作(action)的功能太少了,它没办法进行循环,我们只好自己实现taglib。 比较一下使用taglib前后jsp中的样子。 <lingirl:for var="contact" items="${list}"> <tr class="${contact_row}" onmouseover="this.className='highlight';" onmouseout="this.className='${contact_row}';"> <td>${contact.username}</td> <td>${contact.sex}</td> <td>${contact.email}</td> <td>${contact.qq}</td> <td>${contact.descn}</td> <td><a href="contact.do?method=edit&id=${contact.id}">修改</a> | <a href="contact.do?method=remove&id=${contact.id}">删除</a></td> </tr> </lingirl:for> taglib的写法和jsp动作(action)很相似,是由taglib前缀,冒号,标签名三者的组合体。其中taglib前缀是用jsp指令(direction)定义的。 <%@ taglib uri="WEB-INF/tld/lingirl.tld" prefix="lingirl" %> 这里的jsp指令(direction)是专门用来定义标签库的,uri指定tld定义文件的位置,prefix指定对应的taglib前缀。通过这里的定义才能在下面使用taglib。 看看taglib带给了我们什么?
了解过如何使用我们的taglib,现在可以看具体实现了,首先我们要编写一个ForTag.java。
经过如此一番周折,ForTag可以从标签获得参数,并对数据进行循环处理了。最后一步还要为它编写tld(taglib definition)标签库定义文件,提供给jsp指令(direction)引用。 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java./dtd/web-jsptaglibrary_1_2.dtd"> <taglib> <tlib-version>1.0</tlib-version> <jsp-version>1.2</jsp-version> <short-name>lingirl</short-name> <uri>http://www./lingirl</uri> <tag> <name>for</name> <tag-class>anni.ForTag</tag-class> <attribute> <name>var</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> </attribute> <attribute> <name>items</name> <required>true</required> <rtexprvalue>true</rtexprvalue> <type>java.util.Collection</type> </attribute> </tag> </taglib> 前面一大堆复杂难懂的标签指定我们使用taglib规范的版本,进入tag部分才开始定义名字为for的标签,使用tag-class指定对应的类,再定义两个参数:var和items。required说明参数不能省略必须手工设置。rtexprvalue表示参数部分可以使用el,否则就只能用字符串。type对应的是类中使用的真实类型,taglib会根据它做类型转换。 全部的例子在09-01目录下,注意编译taglib需要将jsp-api.jar加入classpath,参考WEB-INF/src/compile.bat。 结果,为了替换4,5行java代码,我们需要编写一个ForTag.java,一个对应tld文件,在jsp中引用tld,最后才能使用ForTag对list进行循环。不得不说一句:“太麻烦啦。” taglib太笨重,也太复杂了。编写一个taglib花费的力气太大,又不容易修改或扩展。一般情况下,taglib都是由别人写好,我们再直接调用。sun就为标签库定义了一套标准,叫做jstl(java standard taglib)java标准标签库,可以去http://jakarta./taglibs/index.html下载apache实现的jstl。 想在项目里使用jstl,首先要把jstl.jar和standard.jar两个文件放到/WEB-INF/lib/目录下。 然后在list.jsp中加入jsp指令(direction)引用jstl中定义的标签库。 <%@ taglib prefix="c" uri="http://java./jsp/jstl/core"%> 这里的uri是固定写法,只要写成这个就可以使用jstl了,jstl中包含多个标签库,这里我们只用到core。 经过上述配置,现在可以使用jstl了,代码如下: <c:forEach var="contact" items="${list}" varStatus="status"> <c:set var="row" value="${status.index % 2 != 0 ? 'odd' : 'even'}"/> <tr class="${row}" onmouseover="this.className='highlight';" onmouseout="this.className='${row}';"> <td>${contact.username}</td> <td>${contact.sex}</td> <td>${contact.email}</td> <td>${contact.qq}</td> <td>${contact.descn}</td> <td><a href="contact.do?method=edit&id=${contact.id}">修改</a> | <a href="contact.do?method=remove&id=${contact.id}">删除</a></td> </tr> </c:forEach> 这里使用的是c:forEach,它也是一个执行循环的标签,var和items参数的意义与上边谈到的lingirl:for标签已知,分别代表循环变量和循环数据。唯一不同的是多了一个varStatus参数,这个参数表示当前行的状态,其中status.index表示当前行的序号,我们就通过序号计算奇偶行。 在c:forEach标签中,我们还看到一个c:set标签,它的作用是可以将指定的变量保存到作用域中,默认作用域是page,这里我们使用status.index计算出行的奇偶性,然后保存到row中,后面就可以直接使用${row}调用了。 jstl中的c:forEach不但可以处理Collection,还可以处理数组和Map,使用jstl我们更容易写出结构一致的代码,以初学jsp来说,自定义taglib还是太复杂了,所以还是先学习一些常用的jstl为好。 例子在lingo-sample/09-02下,其中只有list.jsp中使用了jstl。 |
|