日期:2014-05-16  浏览次数:20352 次

JSP自定义标签小结

已经好久没有写博客了,这段时间看过很多书,包括《浪潮之巅》(好书,推荐大家看看),《暗时间》(也很不错,刘末鹏讲时间管理的),还有断断续续研究了IOC和spring的实现代码,这部分收获不大,单纯的为了看代码而看代码,现在打算学习设计模式后再来深入。这段时间,在看martin的《企业应用模式》,这是本好书,但翻译看着感觉怪怪的,好多名词怪怪的。但买了就要学习一下,基本看下还是可以的。

今天来重新学习一下基本的东西。很久以前就学习过JSP自定义标签,JSTL更是经常使用,但说到写一个自定义标签,如果没有重新看一下,倒真不知道如何下手。相信很多朋友有同样的感觉,看过的东西,没用一段时间很快就忘记了,特别是技术方面的。究其原因,还是我们没能深入了解它的本质,没有深入理解。

我们一起来看一下。

首先我们必须知道一个标签可以包含什么东西:拿一个JSTL核心标签来看一下:

<c:forEach var="item" items="${items}">
    XXXX
</c:forEach>

??? 我们看到,一个标签可以包含属性,这个可以随便,自己定个数,也可以有标签体,当然这个标签体又可以是另外一个标签,如此类推。

那究竟怎么来实现呢?首先我们可以看看JAVA EE中的Tag相应的层级结构。

?

?

我们可以看到基本的接口是JspTag,当然我们没必要去实现这个接口,因为JAVA EE已经帮我们实现了一部分,如果

我们不需要标签体,我们可以简单地继续TagSupport,而如果我们需要标签体,我们可以直接继承BodyTagSupport。这

个在我们之后的例子可以看到。(我们只看有标签体的例子,没有标签体的大家可以自己试下,很简单)。

那么基本的信息,我们知道了,是时候开始代码了。建项目这些就不废话了。

自定义标签包括如下几个步骤:

1)自定义标签处理类(即我们刚才说的继承TagSupport或BodyTagSupport,或者在新的JSP2里面的SimpleTag)。

2)一个标签描述文件,tld,这个我们可以通过打JAR包或者直接放在META—INF文件夹下,容器会自动进行搜索。

3)在web.xml中进行配置jsp-config进行配置taglib-uri及taglig-location。

4)在JSP页面上用taglib命令引用,然后就可以使用了。

?

看起来很简单,对吧。实际上也就那么回事。开始我们的代码。

1)首先来自定义标签处理类:

我这里写了一个进行循环输出的,这里我暂时处理 的是String类型,其他类型的大致相同。

package com.shun.customtag;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;

public class IteratorTag extends BodyTagSupport{

	private static final long serialVersionUID = 1L;

	private Iterator<String> it;
	private String name;//这里name作为循环的变量名称,相当于forEach中的var
	
	public void setName(String name) {
		this.name = name;
	}
	
	public void setItems(Collection<String> items){
		if(items.size() > 0) {
			it = items.iterator();
		}
	}
	
	public int doAfterBody() throws JspException {
		return iterateItems();
	}

	public int doEndTag() throws JspException {
		//这里必须把body里面的内容输出,否则标签内的内容会为空
		if (bodyContent != null) {
			try {
				bodyContent.writeOut(bodyContent.getEnclosingWriter());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return EVAL_PAGE;
	}

	public int doStartTag() throws JspException {
		if (it == null) {
			return SKIP_BODY;
		} else {
			return iterateItems();
		}
	}
	
	/**
	 * 这里进行遍历传入的items对象
	 * @return
	 */
	private int iterateItems(){
		//如果还存在值,则把它放入pageContext,即当前页面下,以便我们可以在body中进行取出
		if (it.hasNext()) {
			pageContext.setAttribute(name, it.next());
			return EVAL_BODY_AGAIN;
		} 
		return EVAL_PAGE;
	}

}

? 看到这里,也许有些人有疑问,怎么来确定返回的是EVAL_啥呢?

这个基本上是下面的情况:

doStartTag(标签处理开始,即遇到开始标签时)一般返回EVAL_BODY_INCLUDE或者SKIP_BODY

doEndTag(标签处理结束,即遇到结束标签时)一般返回EVAL_PAGE或者SKIP_PAGE。

doAfterBody(标签体处理完成后)一般可以返回EVAL_BODY_AGAIN或者EVAL_BODY_BUFFER(这个是JSP2新的,JS