码迷,mamicode.com
首页 > Web开发 > 详细

一步一步学JSP--JSTL(三)

时间:2015-02-03 00:44:52      阅读:253      评论:0      收藏:0      [点我收藏+]

标签:java   jsp   jstl   自定义标签   

1、JSTL介绍

        JSTL(JavaServer Pages Standard Tag Library)由JCP(Java Community Process)指定标准,提供给 Java Web 开发人员一个标准通用的标签函数库。和 EL 来取代传统直接在页面上嵌入 Java 程序(Scripting)的做法,以提高程序可读性、维护性和方便性。JSTL 主要由Apache组织的Jakarta Project 实现,容器必须支持Servlet 2.4 且JSP 2.0 以上版本

         JSTL下载地址:http://tomcat.apache.org/taglibs/standard/,最新版本为JSTL 1.2,本文下载的是JSTL1.1

技术分享

下载下来的文件如下:

技术分享

安装:

       解压jakarta-taglibs-standard-1.1.2.zip,将解压后lib目录下的jstl.jar,standard.jar直接拷贝到工程下的WEB-INF/lib/目录下(如果用的是myeclipse可以不用复制这2个文件,myeclipse有自带的)。

导入标签库:

            例如:

                   <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

  • uri:用于导入标签库的uri。
  • prefix:标签库的前缀,例如:<c:out>,c就是前缀,相当于为标签取个简单好记的名字。
  • tagdir:指定标签库的路径。

2、jstl标签库

jstl标签库包括以下几个部分:

  • 核心标签库 (Core tag library)
  • 国际化标签 (I18N—capable formatting tag library)
  • 数据库标签(SQL tag library)
  • XML标签(XML tag library)
  • JSTL函数标签(Functions tag library)--EL函数

技术分享

2.1、核心标签库

  • <c:out>标签

用于输出数据的内容,一般可以用脚本表达式来输出数据,<c:out>标签的功能更强大。

技术分享

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
--------------------c:out-------------------------<br/>
	<%--直接输出字符串内容--%>
	"string" = <c:out value="string"></c:out><br/>
	
	<% 
		//put name into requestScope.
		pageContext.setAttribute("name", 
				"RiccioZhang",
				PageContext.REQUEST_SCOPE);
	%>
	<%--直接取值并输出--%>
	requestScope.name = <c:out value="${name }" ></c:out><br/>
	<%--${xxx }是取不到值的,直接用default属性的值输出--%>
	\${xxx } = <c:out value="${xxx }" default="defaultValue"></c:out><br/>
	<%--
		与上面是等价的:<c:out value="${xxx }" default="defaultValue">,
			defaultValue属性和在标签体中写默认值只能选择其一,否则会抛出异常 
	 --%>
	\${xxx } = <c:out value="${xxx }">defaultValue</c:out><br/>
	<%--
		注意:如果value="",那么就会直接输出空串,而不会输出默认值。
	--%>
	blankString = <c:out value="" default="defaultValue"></c:out><br/>
	
	<%
		//put paragraph into requestScope.
		pageContext.setAttribute("p", 
					"<p style='color: red'>This is a paragraph.</p>",
					PageContext.REQUEST_SCOPE);
	%>
	<%--对字符进行转义--%>
	<c:out value="${requestScope.p }"></c:out><br/>
	<c:out value="${requestScope.p }" escapeXml="true"></c:out>
	<c:out value="${requestScope.p }" escapeXml="false"></c:out><br/>
运行结果如下:

-------------------------------------------------------------------------------------------


技术分享


-------------------------------------------------------------------------------------------

  • <c:set >标签
  • <c:set>标签用来将变量存储到jsp范围中或者javabean中。
  • 格式1:<c:set value=“value” var=“varName” [scope=“page|request|”] />
  • 格式2:<c:set target=“varName” property=“name” [scope=“session|application”]  />

       技术分享

Book.java

package cn.zq.domain;


public class Book {
	private String id;
	private String title;
	private Double price;
	
	
	public Book() {
	}
	
	public Book(String id, String title, Double price) {
		this.id = id;
		this.title = title;
		this.price = price;
	}
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	
	public String toString(){
		return this.getClass().getSimpleName() + 
				"[id = "+id+", title="+title+", price="+price+"]";
	}
}


	--------------------c:set-------------------------<br/>
	将变量存储到jsp范围中:<br/>
	<%-- 
		value属性中的值等价于在标签体中写的值(可以为el表达式),但是两者不能同时存在。
	--%>
	<c:set var="name" value="RiccioZhang" scope="page"></c:set>
	1--> pageScope.name = <c:out value="${name }" /><br/>
	<c:set var="name2"  scope="session">RiccioZhang2</c:set>
	2--> sessionScope.name2 = <c:out value="${name2 }" /><br/>
	
	设置javabean的属性:<br/>
	<%
		Book book = new Book("001", "Thinking in java", 66.8);
		pageContext.setAttribute("book", book, PageContext.REQUEST_SCOPE);
	%>
	book = <c:out value="${book }"></c:out><br/>
	<c:set target="${book }" property="id" value="002" ></c:set>
	<c:set target="${book }" property="title" value="Java Core I"></c:set>
	<c:set target="${book }" property="price" value="88.8"></c:set>
	<%--注意当没有var属性时指定scope属性会抛出异常--%>
	book = <c:out value="${book }"></c:out><br/>
	<c:set target="${book }" property="id" var="b" scope="session">003</c:set>
	<c:set target="${book }" property="title">Java Core II</c:set>
	<c:set target="${book }" property="price" value="102"></c:set>
	book = <c:out value="${book }"></c:out><br/>
	b = <c:out value="${sessionScope.b }"></c:out><br/>
	
	设置Map:<br/>
	<%
		Map<String, String> map = new HashMap<String, String>();
		pageContext.setAttribute("map", map, PageContext.REQUEST_SCOPE);
	%>
	<c:set target="${requestScope.map }" property="name" value="RiccioZhang"></c:set>
	<c:set target="${requestScope.map }" property="age" value="22"></c:set>
	<c:set target="${requestScope.map }" property="address" value="GZ"></c:set>
	\${requestScope.map } = ${requestScope.map }

                运行结果如下:

---------------------------------------------------------------------------------------------------------


技术分享


---------------------------------------------------------------------------------------------------------

  • <c: remove>标签

<c: remove>标签用于移除各种web域的属性。<c:remove var="varName"      [scope="{page|request|session|application}"] />

	--------------------c:remove-------------------------<br/>
	<%
		Object o = new Object();
		pageContext.setAttribute("o", o, PageContext.PAGE_SCOPE);
		pageContext.setAttribute("o", o, PageContext.REQUEST_SCOPE);
		pageContext.setAttribute("o", o, PageContext.SESSION_SCOPE);
		pageContext.setAttribute("o", o, PageContext.APPLICATION_SCOPE);
	%>
	<%--
		未指定scope属性,则会调用pageContext.removeAttribute(name)方法,
		会从各个域中移除
	 --%>
	<c:remove var="o"/>
	\${pageScope.o} = ${pageScope.o}<br/>
	\${requestScope.o} = ${requestScope.o}<br/>
	\${sessionScope.o} = ${sessionScope.o}<br/>
	\${applicationScope.o} = ${applicationScope.o}<br/>
	
	<%
		o = new Object();
		pageContext.setAttribute("o", o, PageContext.PAGE_SCOPE);
		pageContext.setAttribute("o", o, PageContext.REQUEST_SCOPE);
		pageContext.setAttribute("o", o, PageContext.SESSION_SCOPE);
		pageContext.setAttribute("o", o, PageContext.APPLICATION_SCOPE);
	%>
	<%--
		指定scope,则从指定域中移除
	 --%>
	<c:remove var="o" scope="page"/>
	<c:remove var="o" scope="application"/>
	\${pageScope.o} = ${pageScope.o}<br/>
	\${requestScope.o} = ${requestScope.o}<br/>
	\${sessionScope.o} = ${sessionScope.o}<br/>
	\${applicationScope.o} = ${applicationScope.o}<br/>

执行结果如下:

---------------------------------------------------------------------------------------------------------


技术分享

---------------------------------------------------------------------------------------------------------

  • <c:catch>标签

         <c:catch>标签用于捕获嵌套在标签体中的内容抛出的异常,其语法格式如下:<c:catch [var="varName"]>nested actions</c:catch>。var属性用于标识<c:catch>标签捕获的异常对象,它将保存在page这个Web域中。

--------------------c:catch-------------------------<br/>
	<c:catch var="ex">
		<%
			int i = 1/0;
		%>
	</c:catch>
	\${pageScope.ex.message } = ${pageScope.ex.message }<br/>
	\${ex.cause } = ${ex.cause }<br/>
	\${ex.stackTrace } = ${ex.stackTrace}<br/>

结果如下:

---------------------------------------------------------------------------------------------------------

技术分享

---------------------------------------------------------------------------------------------------------

  • <c:if>标签
<c:if test=“”>标签可以构造简单的“if-then”结构的条件表达式

技术分享

--------------------c:if-------------------------<br/>
	<c:if test="${empty user }">
		对不起,您还未登录!
	</c:if>
  • <c: choose>标签
<c:choose>标签用于指定多个条件选择的组合边界,它必须与<c:when>和<c:otherwise>标签一起使用。使用<c:choose>,<c:when>和<c:otherwise>三个标签,可以构造类似 “if-else if-else” 的复杂条件判断结构。
--------------------c:choose-------------------------<br/>
	<c:set var="num" value="${param.num }"></c:set>
	<c:choose>
		<c:when test="${empty num}">
			您未输入任何数据!
		</c:when>
		<c:otherwise>
			您输入的是:${num }
		</c:otherwise>
	</c:choose>

请求url:http://localhost:8080/jstl/jstl.jsp?num=10086,结果如下:

---------------------------------------------------------------------------------------------------------

--------------------c:choose-------------------------
您输入的是:10086

---------------------------------------------------------------------------------------------------------

  • <c:forEach>标签

<c:forEach>标签用于对一个集合对象中的元素进行循环迭代操作,或者按指定的次数重复迭代执行标签体中的内容。

语法1:
<c:forEach [var="varName"]
    items="collection" [varStatus="varStatusName"]
    [begin="begin"]
    [end="end"]
    [step="step"]>
        //Body内容
</c:forEach>

语法2:
<c:forEach [var="varName"]
    [varStatus="varStatusName"]
    begin="begin"
    end="end"
    [step="step"]>
        //Body内容
</c:forEach>

技术分享

	--------------------c:forEach-------------------------<br/>
	<%
		Map<String, String> person = new HashMap<String, String>();
		person.put("name", "RiccioZhang");
		person.put("age", "22");
		person.put("addr", "GZ");
		pageContext.setAttribute("person", person);
	%>
	不使用标签迭代map:<br/>
	<%
		for(Map.Entry<String, String> entry : person.entrySet()){
			pageContext.setAttribute("entry", entry);
	%>
		${entry.key } = ${entry.value }<br/>
	<%
		}
	%>
	
	标签迭代--> Map:<br/>
	<%--
		varStatus保存着当前的迭代信息, 他有如下几个属性:
		* index 现在迭代成员的索引
		* count 成员的总数
		* first 当前是否为第一个成员
		* last 当前是否为最后一个成员
	           可以用begin指定迭代从哪个索引开始,
	           end指定从哪个索引处结束(包含),
	           step指定迭代的步长。
	           
	 --%>
	<c:forEach var="en" items="${person }" varStatus="stat">
		\${stat.index} = ${stat.index}<br/>
		\${stat.count} = ${stat.count}<br/>
		\${stat.first} = ${stat.first}<br/>
		\${stat.last} = ${stat.last}<br/>
		${en.key } = ${en.value }<br/>
	-------------------------------------------------<br/>
	</c:forEach>
	标签迭代--> Collection:<br/>
	<%
		Collection<Book> books = new HashSet<Book>();
		books.add(new Book("001", "Thinking in java", 78.0));
		books.add(new Book("002", "Java Core I", 67.0));
		books.add(new Book("003", "Java Core II", 102.0));
		pageContext.setAttribute("books", books);
	%>
	<c:forEach var="book" items="${books }">
		\${book} = ${book}<br/>
	</c:forEach>
	标签迭代--> array:<br/>
	<%
		pageContext.setAttribute("colors", new String[]{"red", "blue", "green", "pink", "dark"});
	%>
	<c:forEach var="color" items="${colors }">
		\${color } = ${color }<br/>
	</c:forEach>
	<%--
		需求: 迭代Collection中的Map中的数组中的Collection.
	 --%>
	 <%
	 	Collection<Map<String, Collection[]>> coll = new ArrayList<Map<String, Collection[]>>();
	 	
	 	Map<String, Collection[]> m = new HashMap<String, Collection[]>();
	 	for(int i = 1; i <= 3; i++){
	 		String key = "s" + i;
	 		Collection<String>[] arrays = new Collection[i];
	 		for(int j = 0; j < arrays.length; j++){
	 			Collection<String> c = new ArrayList<String>();
	 			c.add("a("+i+", "+j+")");
	 			arrays[j] = c;
	 		}
	 		m.put(key, arrays);
	 	}
	 	
	 	coll.add(m);
	 	pageContext.setAttribute("coll", coll);
	 %>
	 <c:forEach var="m" items="${coll}">
	 	<c:forEach var="entry" items="${m }">
	 				${entry.key } = 
			 		[
			 		<c:forEach var="arr" items="${entry.value }" >
			 			<c:forEach var="hs" items="${arr }">
	 						<c:forEach var="s" items="${hs}">
	 							${s }
	 						</c:forEach>
			 			</c:forEach>
			 		</c:forEach>
			 	    ]
			 	<br/>
	 		</c:forEach>
	 </c:forEach>
	 
	 <c:forEach var="floor" begin="1" end="10" step="1">
	 	第${floor }楼<br/>
	 </c:forEach>

运行结果如下:

*******************************************************

--------------------c:forEach-------------------------
不使用标签迭代map:
age = 22
name = RiccioZhang
addr = GZ
标签迭代--> Map:
${stat.index} = 0
${stat.count} = 1
${stat.first} = true
${stat.last} = false
age = 22
-------------------------------------------------
${stat.index} = 1
${stat.count} = 2
${stat.first} = false
${stat.last} = false
name = RiccioZhang
-------------------------------------------------
${stat.index} = 2
${stat.count} = 3
${stat.first} = false
${stat.last} = true
addr = GZ
-------------------------------------------------
标签迭代--> Collection:
${book} = Book[id = 001, title=Thinking in java, price=78.0]
${book} = Book[id = 002, title=Java Core I, price=67.0]
${book} = Book[id = 003, title=Java Core II, price=102.0]
标签迭代--> array:
${color } = red
${color } = blue
${color } = green
${color } = pink
${color } = dark
s2 = [ a(2 0) a(2 1) ]
s1 = [ a(1 0) ]
s3 = [ a(3 0) a(3 1) a(3 2) ]
第1楼
第2楼
第3楼
第4楼
第5楼
第6楼
第7楼
第8楼
第9楼
第10楼

*******************************************************

  • <c:forTokens>标签

用来浏览一字符串中所有的成员,其成员是由定义符号所分隔的

<c:forTokens
        items="stringOfTokens"
        delims="delimiters"
        [var="varName"]
        [varStatus="varStatusName"]
        [begin="begin"]
        [end="end"]
        [step="step"]>
      //body内容
</c:forTokens>

         技术分享

	 --------------------c:forTokens-------------------------<br/>
	 <c:forTokens var="d" items="aa,bb,cc" delims=",">
	 	\${d} = ${d }<br/>
	 </c:forTokens>
	 <%
		 pageContext.setAttribute("o", new Object());
	 %>
	 <c:forTokens var="d2" items="${o }" delims="@">
	 	\${d2} = ${d2 }<br/>
	 </c:forTokens>

运行结果如下:

-------------------------------------------------------------------------

--------------------c:forTokens-------------------------
${d} = aa
${d} = bb
${d} = cc
${d2} = java.lang.Object
${d2} = 1eb01e5

-------------------------------------------------------------------------

  • <c:param>标签
在JSP页面进行URL的相关操作时,经常要在URL地址后面附加一些参数。<c:param>标签可以嵌套在<c:import>、<c:url>或<c:redirect>标签内,为这些标签所使用的URL地址附加参数。

<c:param>标签在为一个URL地址附加参数时,将自动对参数值进行URL编码,例如,如果传递的参数值为“中国”,则将其转换为“%d6%d0%b9%fa”后再附加到URL地址后面,这也就是使用<c:param>标签的最大好处。

示例:<c:param name="name" value="value" />

  • <c:import>标签

用来引入包含文件的内容。

技术分享

 --------------------c:import-------------------------<br/>
	  直接通过var获取:<br/>
	  <c:import url="/1.txt" charEncoding="GBK">
	  </c:import>
	  <br/>
	    通过varReader获取:<br/>
	  <c:import url="/1.txt" varReader="r" charEncoding="GBK">
		 <%
		 	StringReader reader = (StringReader)pageContext.findAttribute("r");
		 	char[] buf = new char[1024];
		 	int len = -1;
		 	while( ( len = reader.read(buf) ) != -1 ){
		 		out.print(new String(buf, 0, len));
		 	}
		 %>
	  </c:import>
  • <c:url>标签
<c:url>标签用于在JSP页面中构造一个URL地址,其主要目的是实现URL重写。URL重写就是将会话标识号以参数形式附加在URL地址后面

技术分享

	  --------------------c:url-------------------------<br/>
	  <c:url var="url" value="/aaa/xxx.jsp" scope="page">
	  	<c:param name="country" value="中国"></c:param>
	  	<c:param name="city" value="武汉"></c:param>
	  </c:url>
	  \${url } = ${url }<br/>

结果如下:

${url } = /day11/aaa/xxx.jsp?country=%e4%b8%ad%e5%9b%bd&city=%e6%ad%a6%e6%b1%89

  • <c:redirect>标签

<c:redirect>标签用于实现请求重定向

技术分享

	 --------------------c:redirect-------------------------<br/>
	 <c:redirect url="/index.jsp" context="/el"></c:redirect>

3、自定义标签

3.1、什么是自定义标签

         自定义标签是指JSP自定义标签。自定义标签在功能上逻辑上与JavaBean类似,都封装Java代码。自定义标签是可重用的组件代码,并且允许开发人员为复杂的操作提供逻辑名称。自定义标签是JSP1.1规范里最早提出的。从标签的来源上看,JSP的标签库可以分为两种类型:一种是JSP标准标签库(JSTL,JSP Standard Tag Library),它是JSP开发环境供应商开发的。另一种是JSP开发环境的使用者(即用户)自己定义的标签。通过使用标签库,让JSP页面变得更加简洁,减少了JSP页面脚本代码量,大大降低JSP页面的复杂度,并且是代码最大程度是重用。

标签的几种形式:

  • 主体和内容都为空的:<demo:hello   />
  • 包含属性的标签:<demo:hello   name=“zq”/>
  • 包含主体内容的标签:<demo:hello>RiccioZhang</demo:hello>
  • 包含主体内容和属性的标签:<demo:hello name=“zq”>RiccioZhang</demo:hello>
  • 嵌套的标签:

         <demo:hello>
             <demo:user name=“zq”/
         </demo:hello>

标签库的接口和类的继承关系(标签库的api定义在javax.servlet.jsp.tagext下):

技术分享

开发自定义标签,其核心就是要编写处理器类,一个标签对应一个标签处理器类,而一个标签库则是很多标签处理器的集合。JSP所有的标签处理器类都实现javax.servlet.jsp.tagext.JspTag接口。这个接口是一个标记接口 。它有两个直接子接口:

  • 简单标签:标签处理类实现SimpleTag接口,它是JSP2.0新增加的接口,代表简单的标签。
  • 经典标签:JSP2.0以前标签处理类实现Tag接口,它是经典的必须实现的接口,它有一个直接子接口IterationTag

自定义标签执行流程:

技术分享

开发一个自定义的标签包含以下步骤:

1、根据业务要求确定标签形式
2、创建自定义标签的处理类。
3、创建自定义标签的库描述文件*.tld(Tag Library Descriptor File)
4、将tld描述文件放到WEB-INF或其子目录下。
5、在web.xml中声明所引用的自定义标签(在servlet2.4,jsp2.0以上的版本不用配置此项)。
6、在页面上使用JSP的自定义标签。

3.2、简单标签

为了简化自定义标签的开发,JSP2.0开始又引入了一种新的标签扩展机制。
称为“简单标签扩展”:
1、对于熟悉Java编程语言的开发人员,可以定义实现javax.servlet.jsp.tagext.SimpleTag接口的标签处理类。
2、SimpleTag的一个子类是:SimpleTagSupport。

SimpleTag接口的优点:

  • 和JSP1.2中的已有接口不同的是,SimpleTag接口不使用doStartTag()和doEndTag()方法,而提供一个简单的doTag()方法。这个方法在调用该标记时只被使用一次,需要在一个自定义标记中实现所有逻辑过程、循环和对标记体的输出等。从这个方面来讲,SimpleTag可以和IterationTag达到同等的作用。但SimpleTag的方法和周期要简单的多。
  • 在SimpleTag中还有用来设置JSP内容的setJspBody()和getJspBody()方法。web容器使用setJspBody()方法定义一个代表JSP内容的JspFragment对象。实现SimpleTag标记的程序可以在doTage方法中根据需要多次调用getJspBody().invokie()方法以处理JSP内容
  • 对于前台web页面制作人员,在JSP1.2时代Taglib页面调用实际上是比较复杂的,SimpleTag+EL表达式语言极大的简化了taglib调用,对不懂java的人员也可以轻松编写JSP页面的目的。

实现SimpleTag接口:

  • setJspContext方法:该方法把代表JSP页面的pageContext对象传递给标签处理器对象
  • setParent方法:该方法把父标签处理器对象传递给当前标签处理器对象
  • getParent()方法:该方法用于获得标签的父标签处理器对象
  • setJspBody:方法:由Servlet容器调用此方法,用于设置标签的主体部分。
  •      JspFrgment类代表JSP的部分代码,它的方法有:invoke方法用于执行body体部分的内容。将内容输出到IE上。
  • doTag() 方法:负责标签的处理过程,完成所有的标签逻辑。与doStartTag和doEndTag方法不同的是doTag方法没有返回值。该方法可以抛出javax.servlet.jsp.SkipPageException 异常,用于通知web容器不在执行JSP页面中位于结束标记后面的内容。
  • SimpleTag接口的一个实现类为SimpleTagSupport。开发时,只需要继承SimpleTagSupport类,并覆盖doTag方法即可。

实现SimpleTag接口的标签处理器的生命周期:

技术分享

  • 自定义一个标签输出系统当前时间

(1)写一个java类

package cn.zq.tag;

import java.io.IOException;
import java.io.Writer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;

public class MyDateTag implements SimpleTag{
	
	private JspContext context; //接收pageContext对象
	
	/*
	 * 将pageContext对象传递进来 
	 */
	public void setJspContext(JspContext context) {
		this.context = context;
	}
	
	public void doTag() throws JspException, IOException {
		Writer writer = context.getOut();
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS");
		writer.write(df.format(new Date()));
	}

	public JspTag getParent() {
		return null;
	}

	public void setJspBody(JspFragment fragment) {
		
	}

	public void setParent(JspTag tag) {
		
	}

}

(2) 在WEB-INF目录下新建一个tld目录,并在这个目录下新建一个my.tld(其实就是一个xml格式的文件)文件(解析引擎会在WEB-INF以及子目录下查找tld文件):

my.tld

<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">
    <description>my taglib</description>
    <display-name>my taglib</display-name>
    <tlib-version>1.0</tlib-version>
    <short-name>my</short-name>
    <uri>http://www.ricciozhang.cn/jsp/jstl/my</uri>
    
    <tag>
    	<name>date</name>
    	<tag-class>cn.zq.tag.MyDateTag</tag-class>
    	<!-- empty 标签体为空 -->
    	<body-content>empty</body-content>
    </tag>
</taglib>
(3) 配置tld文件(可选)

在web.xml文件中可以做如下的配置:


	<jsp-config>
		<taglib>
			<taglib-uri>http://www.ricciozhang.cn/jsp/jstl/my</taglib-uri>
			<taglib-location>/WEB-INF/tld/my.tld</taglib-location>
		</taglib>
	</jsp-config>

(4)使用标签

  引入标签库:<%@ taglib uri="http://www.ricciozhang.cn/jsp/jstl/my" prefix="my" %>

  使用:<my:date/>

说明:

  • 此标签类也必须要配置到tld文件中。
  • 对于SimpleTagSupport配置文件中的<body-content>子元素,由于其主体不能包含Java程序片段,即它不处理body部分的内容,所以<body-content>子元素的值不能为JSP.
  • 如果需要使用session等信息,可以先通过获取pageContext的方式获取:PageContext pc = (PageContext)getJspContext();

body-content元素说明:

Body-content元素可以包含的值为:

  • JSP:接收所有的JSP语法。
  • EMPTY:没有标签体
  • tagdependent:不解析body部分的标签。由自定义标签接收数据再行处理。若指定该值,标签体中的所有代码原封不动的交给标签处理器,而不是将执行结果传递给标签处理器
  • scriptless:接收EL,文本和JSP动作,但不接收<%= ..%>java脚本片段。

       如:如果使用scriptless则使用以下语法是错误的:行(2)
              1 <my:simple name=“zq">
              2    <%="Hello"%>
              3   <br/>
                 </my:simple>
如果将第二行换成:<c:out value=‘Hello’/>就可以了

  • 定义一个标签输出最大值

        (1)java类

package cn.zq.tag;

import java.io.IOException;
import java.io.Writer;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;

public class MyMaxValueTag implements SimpleTag{
	
	private JspContext context;
	
	private Integer num1;
	private Integer num2;

	public void setNum1(Integer num1) {
		this.num1 = num1;
	}

	public void setNum2(Integer num2) {
		this.num2 = num2;
	}

	public void setJspContext(JspContext pc) {
		context = pc;
	}
	
	public void doTag() throws JspException, IOException {
		Writer out = context.getOut();
		if(num1 > num2){
			out.write("最大值为:" + num1);
		}else{
			out.write("最大值为:" + num2);
		}
	}

	public JspTag getParent() {
		return null;
	}

	public void setJspBody(JspFragment jspBody) {
		
	}

	public void setParent(JspTag parent) {
		
	}

}


        (2)配置tld文件

<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

    <tlib-version>1.0</tlib-version>
    <short-name>my2</short-name>
    <uri>http://www.ricciozhang.cn/jsp/jstl/my2</uri>
    
 	<tag>
 		<name>max</name>
 		<tag-class>cn.zq.tag.MyMaxValueTag</tag-class>
 		<body-content>empty</body-content>
 		<attribute>
 			<name>num1</name>
 			<required>true</required>
 			<!-- 是否支持el表达式 -->
 			<rtexprvalue>true</rtexprvalue>
 			<type>java.lang.Integer</type>
 		</attribute>
 		<attribute>
 			<name>num2</name>
 			<required>true</required>
 			<!-- 是否支持el表达式 -->
 			<rtexprvalue>true</rtexprvalue>
 			<type>java.lang.Integer</type>
 		</attribute>
 	</tag>
</taglib>

        (3)使用标签

<my2:max num2="12" num1="14"/>

  • 定义一个标签,带有三个属性,分别用于指定起始数、结束数和步长
        
package cn.zq.tag;

import java.io.IOException;
import java.io.Writer;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;

public class CircleTag implements SimpleTag{
	
	private JspContext context;
	
	private Integer begin;
	private Integer end;
	private Integer step;
	
	public void setBegin(Integer begin) {
		this.begin = begin;
	}

	public void setContext(JspContext context) {
		this.context = context;
	}

	public void setEnd(Integer end) {
		this.end = end;
	}

	public void setStep(Integer step) {
		this.step = step;
	}

	public void setJspContext(JspContext pc) {
		context = pc;
	}

	public void doTag() throws JspException, IOException {
		Writer out = context.getOut();
		for(int i = begin; i <= end; i+=step){
			out.write( i +"<br/>");
		}
	}

	public JspTag getParent() {
		return null;
	}

	public void setJspBody(JspFragment jspBody) {
		
	}

	public void setParent(JspTag parent) {
		
	}

}

<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

    <tlib-version>1.0</tlib-version>
    <short-name>my2</short-name>
    <uri>http://www.ricciozhang.cn/jsp/jstl/my3</uri>
    
 	<tag>
 		<name>circle</name>
 		<tag-class>cn.zq.tag.CircleTag</tag-class>
 		<body-content>empty</body-content>
 		<attribute>
 			<name>step</name>
 			<required>true</required>
 			<!-- 是否支持el表达式 -->
 			<rtexprvalue>true</rtexprvalue>
 			<type>java.lang.Integer</type>
 		</attribute>
 		<attribute>
 			<name>end</name>
 			<required>true</required>
 			<!-- 是否支持el表达式 -->
 			<rtexprvalue>true</rtexprvalue>
 			<type>java.lang.Integer</type>
 		</attribute>
 		<attribute>
 			<name>begin</name>
 			<required>true</required>
 			<!-- 是否支持el表达式 -->
 			<rtexprvalue>true</rtexprvalue>
 			<type>java.lang.Integer</type>
 		</attribute>
 	</tag>
</taglib>

使用:

<%@ taglib uri="http://www.ricciozhang.cn/jsp/jstl/my3" prefix="my3" %>

<my3:circle begin="1" end="10" step="1"/>


  •   定义一个标签,将标签体的内容全部转换成大写并输出
package cn.zq.tag;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;

public class MyToUpperCaseTag implements SimpleTag{
	
	private JspContext context;
	private JspFragment jspBody;
	private JspTag parent;
	

	public void setJspContext(JspContext pc) {
		context = pc;
	}
	
	public void doTag() throws JspException, IOException {
		Writer out = context.getOut();
		StringWriter sw = new StringWriter();
		jspBody.invoke(sw);
		out.write(sw.toString().toUpperCase());
	}

	public JspTag getParent() {
		return parent;
	}

	public void setJspBody(JspFragment jspBody) {
		this.jspBody = jspBody;
	}

	public void setParent(JspTag parent) {
		this.parent = parent;
	}

}

<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">

    <tlib-version>1.0</tlib-version>
    <short-name>my4</short-name>
    <uri>http://www.ricciozhang.cn/jsp/jstl/my4</uri>
    
 	<tag>
 		<name>toUpperCase</name>
 		<tag-class>cn.zq.tag.MyToUpperCaseTag</tag-class>
 		<body-content>scriptless</body-content>
 	</tag>
</taglib>

	<my4:toUpperCase>
		asdfGDDDeyehehe
	</my4:toUpperCase>

JspFragment类:

  • 该类的实例对象代表 JSP 页面中的一段符合 JSP 语法规范的 JSP 片段,这段 JSP 片段不能包含 JSP 脚本元素(<% … %>)
  • JSP 引擎在处理简单标签的标签体时,会把标签体内容用一个 JspFragment  对象表示,并调用标签处理器对象的 setJspBody 方法把 JspFragment 对象传递给标签处理器对象。得到代表标签体的 JspFragment 对象后,标签开发者就可以在标签处理器中根据需要调用 JspFragment 对象的方法,进而决定如何处理标签体。
  • getJspContext 方法:该方法用于返回代表调用页面的 JspContext 对象

                   Invoke 方法(java.io.Writer out):该方法用于执行 JspFragment 对象所代表的 JSP 代码片段。在 doTag() 方法中可以根据需要调用该方法。
                  该方法的参数 out 用于指定将 JspFragment 对象的执行结果写入到哪个输出流对象中。若传递参数 out 的值为 null,则将执行结果写入到  JspContext.geOut() 方法返回的输出流对象中。
                若想在标签处理器中修改标签体内容:需在调用 invoke 方法时指定一个可取出结果数据的输出流对象(如:StringWriter),让标签体的执行结果输出到该输出流中,然后从该输出流对象中取出数据进行修改后再输出到目标设备


使用SimpleTagSupport实现遍历集合:

package cn.zq.tag;

import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class ForEachTag extends SimpleTagSupport{
	
	@SuppressWarnings("rawtypes")
	private Iterator iterator;
	private String var;
	
	public void setItems(Object items) {
		
		//if items is null, then return empty iterator.
		if(items == null){
			iterator = Collections.EMPTY_LIST.iterator();
		}else{
			
			if(items instanceof Collection){
				Collection coll = (Collection) items;
				iterator = coll.iterator();
			}else if(items instanceof Map){
				Map map = (Map) items;
				iterator = map.entrySet().iterator();
			}else if(items.getClass().isArray()){
				List list = new ArrayList();
				for(int i = 0; i < Array.getLength(items); i++){
					Object item = Array.get(items, i);
					list.add(item);
				}
				iterator = list.iterator();
			}else{
				throw new IllegalArgumentException("Can't iterate " + items.getClass().getName());
			}
		}
	}

	public void setVar(String var) {
		this.var = var;
	}

	public void doTag() throws JspException, IOException {
		if("".equals(var)){
			throw new NullPointerException("var can't be blank.");
		}
		JspContext context = getJspContext();
		JspFragment body  = getJspBody();
		while(iterator.hasNext()){
			Object o = iterator.next();
			context.setAttribute(var, o);
			body.invoke(null);
		}
		context.removeAttribute(var);
	}
}

 	<tag>
 		<name>forEach</name>
 		<tag-class>cn.zq.tag.ForEachTag</tag-class>
 		<body-content>scriptless</body-content>
 		
 		<attribute>
 			<name>items</name>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 			<type>java.lang.Object</type>
 		</attribute>
 		<attribute>
 			<name>var</name>
 			<required>true</required>
 			<rtexprvalue>false</rtexprvalue>
 			<type>java.lang.String</type>
 		</attribute>
 	</tag>

<%
		pageContext.setAttribute("arrs", new int[]{1,2,3,4,5,6,7});
	%>
	<zq:forEach items="${ arrs}" var="arr">
		${arr}<br/>
	</zq:forEach>
	<%
		pageContext.setAttribute("list", Arrays.asList(new String[]{"zq", "zy", "lzh"}));
	%>
	<zq:forEach items="${ list}" var="item">
		${item}<br/>
	</zq:forEach>
	<%
		Map map = new HashMap();
		for(int i = 0; i < 4; i++){
			Book b = new Book(String.valueOf(i), "title"+i, i*10 + 2.5);
			map.put(b.getId(), b);
		}
		pageContext.setAttribute("map", map);
	%>
	<zq:forEach items="${map }" var="entry">
		${entry.key } = ${entry.value }<br/>
	</zq:forEach>

关于简单标签的几点说明:  如果想要不执行标签下面的jsp代码,则只需在doTag方法中抛出javax.servlet.jsp.SkipPageException异常就行,简单标签处理类在每次调用标签时都会创建一次实例,所以是线程安全的。

3.3、经典标签

    自定义标签的主要接口类:

  •    TagSupport

             使用最为频繁的类,可设置属性。

  • BodyTagSupport

             可以处理body体部分的内容,使用不是很多。

  • SimpleTagSupport

            简单标签实现类,是JSP2.0以后添加的新类,可以快速开发自定义标签。

Quick Start:

  • 用户需求:用户进入主页显示当前时间格式为:yyyy-MM-dd HH:mm:ss 星期一

         按照JSP的开发原则,不建议在JSP页面上出现Java代码。而其他标签如JSTL又无法实现用户的需求,那就只能书写自定义的标签了。
开发:

  • 第一步:书写一个类实现Tag接口。

            在doStartTag中书写要输出的代码。

package cn.zq.tag;

import java.io.IOException;
import java.io.Writer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.Tag;

public class CurrentDateTag implements Tag{
	
	private PageContext pc;
	private Tag parent;
	
	public CurrentDateTag(){
		System.out.println(this.getClass().getName());
	}
	
	/**
	 * 1.设置pageContext对象
	 */
	public void setPageContext(PageContext pc) {
		this.pc = pc;
	}
	
	/**
	 * 2.设置父标签
	 */
	public void setParent(Tag t) {
		parent = t;
	}
	
	/**
	 * 3.处理开始标签
	 */
	public int doStartTag() throws JspException {
		Writer out = pc.getOut();
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
		try {
			out.write(df.format(new Date()));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return 0;
	}
	
	/**
	 * 4、处理结束标签
	 */
	public int doEndTag() throws JspException {
		return 0;
	}

	public Tag getParent() {
		return parent;
	}

	public void release() {
		
	}
}


  • 第二步:在tld(Tag Lib Description)文件中描述标签接口的类文件。

       可以通过MyEclipse的向导创建tld文件,建议使用tld1.2版本。也可以在jstl中获取一个tld文件然后加以修改。

	<tag>
 		<name>curDate</name>
 		<tag-class>cn.zq.tag.CurrentDateTag</tag-class>
 		<body-content>empty</body-content>
 	</tag>

  • 第三步:在web.xml中配置tld文件。(可选)在jsp-config中配置
  • 第四步:在jsp页面上引用自定义标签。使用<%@ taglib …%>引用自定义标签。
    <%@ taglib uri="http://www.ricciozhang.cn/jsp/jstl/zq" prefix="zq" %>
    <zq:curDate/><br/>


        API说明:

  • JspTag接口:

          所有的标签处理类,都要实现JspTag接口。这个接口只是一个标识接口,它里面没有定义任何方法。

  • Tag接口:

            Tag接口定义了所有传统标签处理类要实现的基本方法。
            setPageContext(PageContext ctx)由Servlet容器调用。向当前的标签处理类传递当前PageContext对像。
            setParent(Tag t) – 由Servlet容器调用此方法,向当前Tag对象传递父标签的Tag对像。
            doStartTag() – 当遇到标签体开始标记时执行的方法,需要用户实现。
            doEndTag() – 当遇到标签体结束标记时执行的方法。需要用户实现。

    

  doStartTag和doEndTag的返回值说明:

  • doStartTag和doEndTag方法都要求用户返回一个int类型的值,此值决定标签的后续部分如何处理。
  • doStartTag的两个返回值是:

            Tag.SKIP_BODY:表示标签的主体部分将被忽略。
            Tag.EVAL_BODY_INCLUDE:表示标签的主体部分将被正常执行。

  • doEndTag的两个返回值是:

          Tag.SKIP_PAGE:表示停止标签后面的JSP代码的执行。
          Tag.EVAL_PAGE:表示按正常顺序执行标签的后续JSP代码。


TagSupport类

  • TagSupport类添加了默认的实现,在实际的开发,基本上都是使用此类来开发自定义的标签。
  • 在使用此类进行开发时,只需要实现部分方法即可。
  • 此类支持自定义的属性。

再谈tld文件部署:

  • 第一种方式:

            将tld文件放到WEB-INF/tlds目录下,项目可以自己识别此文件。即不需要在web.xml中配置即可以在jsp页面上引用。引用时使用在tld文件中定义的uri加以引用。

  • 第二种方式:

          将你的标签处理类打包成jar文件,然后将tld文件放到jar包中的META-INF目录下,将此jar文件拷贝到lib目录下,即可以自动加载。

  如果你是最终发布的应用程序建议使用第二种方式,
  如果你是测试或开发阶段建议使用第一种方式。

小细节:

  • 当Servlet容器初始化自定义标签的处理类时,会调用它的无参数构造方法,所以,不要修改默认构造,更不要书写带有参数的构造方法。
  • 当继承TagSupport实现自定义的标签类时,不要在构造方法中访问pageContext变量。因为此时Servlet容器还没有调用setPageContext方法设置pageContext变量的值。
  • 当一个自定义标签初始化完成后,就由Servlet容器来进行管理。Servlet容器只会在第一次使用自定义标签时初始化自定义标签,且只会初始化一次。所以在Tomcat的生命周期内,自定义标签的构造方法只会执行一次。
  • 自定义标签的setPageContext方法在每次请求此标签时都会被执行一次。用于重新设置pageContext对像。
  • 如果是继承的TagSupport,则不建议覆盖setPageContext方法。
  • 如果实现的是Tag接口,则必须提供PageContext的成员变量。

BodyTagSupport类:

  • 如果希望操纵标签体的内容,可以让自定义处理类继承BodyTagSupport类。
  • BodyTagSupport类拥有一个bodyContent成员变量,用于缓存主体内容。
  • 当标签处理到标签体内容的时候,会调用setBodyContent方法将标签体内容保存到bodyContent变量当中。所以,不要试图在doStartTag方法中获取bodyContent的内容。因为尚没有读到body体部分。
  • 要处理body体部分,可以在doEndTag方法中进行处理。
  • 注意必须在doStartTag中设置返回值为BodyTag.EVAL_BODY_BUFFERED,Servlet容器才会将body部分通过setBodyContent方法设置到bodyContent变量上。对于其他的两个返回值:SKIP_BODY,EVAL_BODY_INCLUDE都不会调用setBodyContent方法。一定要加以注意。
  • bodyContent变量的getString()方法用于获取原始内容。

package cn.zq.tag;

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

public class BodyDemoTag extends BodyTagSupport{

	private static final long serialVersionUID = -7320348789459562269L;
	
	public int doStartTag() throws JspException {
		return EVAL_BODY_BUFFERED;
	}
	
	public int doEndTag() throws JspException {
		try {
			String str = getBodyContent().getString();
			JspWriter out = pageContext.getOut();
			out.print(str);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return EVAL_PAGE;
	}

}

 	<tag>
 		<name>BodyDemo</name>
 		<tag-class>cn.zq.tag.BodyDemoTag</tag-class>
 		<body-content>JSP</body-content>
 	</tag>

	<%
		pageContext.setAttribute("name", "RiccoZhang");
	%>
	<zq:BodyDemo>
		name = ${name }<br/>
	</zq:BodyDemo>

创建和使用Iterator标签:

  • JSP页面上通常在遍历集合中的数据。如之前大家使用过的c:forEach.
  • TagSupport类实现的IterationTag接口,所以使用此类完全可以完成遍历功能。
  • IterationTag接口扩展了一个返回值为:在doStartTag和doEndTag中都可以使用此值:

            EVAL_BODY_AGIN可以用于重复执行body体部分。

  • IterationTag接口的doAfterBody方法中如果返回的是EVAL_BODY_AGIN则会重复执行body体部分。
  • doAfterBody方法会多次执行,如果要声明循环变量,则应该将循环变量声明成成员变量,在doAfterBody中进行迭代。

Iterator简单实例:输出Body部分N次

package cn.zq.tag;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.IterationTag;
import javax.servlet.jsp.tagext.Tag;

public class SimpleIteratorTag implements IterationTag{
	
	private Tag parent;
	private PageContext pc;
	private int i = 0;
	
	public void setPageContext(PageContext pc) {
		i = 0;
		this.pc = pc;
	}
	
	public void setParent(Tag t) {
		parent = t;
	}
	
	public int doStartTag() throws JspException {
		return EVAL_BODY_INCLUDE;
	}
	
	public int doAfterBody() throws JspException {
		if(i < 10){
			i++;
			System.err.println("i >> " + i);
			return EVAL_BODY_AGAIN;
		}
		return SKIP_BODY;
	}
	
	public int doEndTag() throws JspException {
		return EVAL_PAGE;
	}


	public Tag getParent() {
		return parent;
	}

	public void release() {
		System.out.println("release....");
	}
}

	<tag>
 		<name>simpleIterator</name>
 		<tag-class>cn.zq.tag.SimpleIteratorTag</tag-class>
 		<body-content>scriptless</body-content>
 	</tag>

用TagSupport实现遍历Collection集合的功能

  • TagSupport是IterationTag的子类:
  • 步骤如下:

             1、TagSupport实现了IterationTag接口,并添加了默认实现。
              2、通过属性接收需要遍历的集合,同时要声明一个变量。以便于将信息保存到pageContext中。

     

package cn.zq.tag;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;

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

public class IteratorCollectionTag extends TagSupport{

	private static final long serialVersionUID = 2606376711004300944L;
	
	private Iterator items; //集合公用迭代器
	private String var;

	public void setVar(String var) {
		this.var = var;
	}
	
	public void setItems(Collection items){
		if(items != null){
			this.items = items.iterator();
		}else{
			this.items = Collections.EMPTY_LIST.iterator();
		}
	}
	
	public int doStartTag() throws JspException {
		return EVAL_BODY_INCLUDE;
	}
	
	public int doAfterBody() throws JspException {
		if(items.hasNext()){
			pageContext.setAttribute(var, items.next());
			return EVAL_BODY_AGAIN;
		}
		return SKIP_BODY;
	}
}
 	<tag>
 		<name>iteratorCollection</name>
 		<tag-class>cn.zq.tag.IteratorCollectionTag</tag-class>
 		<body-content>JSP</body-content>
 		<attribute>
 			<name>items</name>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 			<type>java.util.Collection</type>
 		</attribute>
 		<attribute>
 			<name>var</name>
 			<required>true</required>
 			<rtexprvalue>false</rtexprvalue>
 			<type>java.lang.String</type>
 		</attribute>
 	</tag>

遍历Map类型的集合:

package cn.zq.tag;

import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

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

public class IteratorMapTag extends TagSupport{

	private static final long serialVersionUID = 3276279245657573036L;
	
	private String var;
	private Iterator<Map.Entry> items;
	
	public void setVar(String var) {
		this.var = var;
	}
	
	public void setItems(Map map){
		if(map == null){
			items = Collections.EMPTY_MAP.entrySet().iterator();
		}else{
			items = map.entrySet().iterator();
		}
	}
	
	public int doStartTag() throws JspException {
		return EVAL_BODY_INCLUDE;
	}
	
	public int doAfterBody() throws JspException {
		if(items.hasNext()){
			pageContext.setAttribute(var, items.next());
			return EVAL_BODY_AGAIN;
		}
		return SKIP_BODY;
	}

}
 	 	<tag>
 		<name>iteratorMap</name>
 		<tag-class>cn.zq.tag.IteratorMapTag</tag-class>
 		<body-content>JSP</body-content>
 		<attribute>
 			<name>items</name>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 			<type>java.util.Map</type>
 		</attribute>
 		<attribute>
 			<name>var</name>
 			<required>true</required>
 			<rtexprvalue>false</rtexprvalue>
 			<type>java.lang.String</type>
 		</attribute>
 	</tag>
</taglib>

迭代所有类型的集合标签:

package cn.zq.tag;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

public class IteratorTag extends TagSupport{

	private static final long serialVersionUID = -3164171313267237222L;
	
	private Iterator<? extends Object> items; //集合通用接口
	private String var;
	
	public void setVar(String var){
		this.var = var;
	}
	
	public void setItems(Object o){
		if(o == null){
			items = new ArrayList().iterator();
		}else if(o instanceof Collection){
			Collection coll = (Collection) o;
			items = coll.iterator();
		}else if(o instanceof Map){
			Map map = (Map) o;
			items = map.entrySet().iterator();
		}else if(o.getClass().isArray()){
			int len = Array.getLength(o);
			List list = new ArrayList(); 
			for(int i = 0; i < len; i++){
				Object ob = Array.get(o, i);
				list.add(ob);
			}
			items = list.iterator();
		}else{
			throw new IllegalArgumentException("items can't be iterted.");
		}
	}
	
	public int doStartTag() throws JspException {
		return EVAL_BODY_INCLUDE;
	}
	
	public int doAfterBody() throws JspException {
		if(items.hasNext()){
			pageContext.setAttribute(var, items.next());
			return EVAL_BODY_AGAIN;
		}
		pageContext.removeAttribute(var);
		return SKIP_BODY;
	}
}

       <tag>
 		<name>iterator</name>
 		<tag-class>cn.zq.tag.IteratorTag</tag-class>
 		<body-content>JSP</body-content>
 		<attribute>
 			<name>items</name>
 			<required>true</required>
 			<rtexprvalue>true</rtexprvalue>
 			<type>java.lang.Object</type>
 		</attribute>
 		<attribute>
 			<name>var</name>
 			<required>true</required>
 			<rtexprvalue>false</rtexprvalue>
 			<type>java.lang.String</type>
 		</attribute>
 	</tag>

	----------iterator---------<br/>
	<zq:iterator items="${arrs }" var="arr">
		${arr }<br/>
	</zq:iterator>
	<zq:iterator items="${list }" var="l">
		${l }<br/>
	</zq:iterator>
	<zq:iterator items="${map }" var="entry">
		${entry.key } = ${entry.value }<br/>
	</zq:iterator>

  • 处理对象数组和基本类型数组

          对象数组:String[] ss = {…};

           保存基本数据的数组:int[] age={…}.
  •  对于对象数据:可以使用:

           Object[] oo = (Object[])ss;

  •  但对于基本类型的数组:

           Object[] oo = (Object[])age;//将抛出ClassCastException

  •  解决方案:使用Array对数组进行反射操作:

int len = Array.getLength(age);
List<Object> list = new  ArrayList<Object>();
for(int i=0;i<len;i++){
        Object oo = Array.get(age,i);
        list.add(oo);
}

4、自定义函数

自定义函数库:

  • 自定义函数与自定义标签一样也要配置到tld文件当中。
  • 自定义函数的方法必须声明成public static类型。
  • 以下实现一个自定义函数,它实现页面上两个数的相加。

第一步:写java代码

package cn.zq.fun;

public class AddFun {
	
	public static int add(String x, String y){
		int c = new Integer(x) + new Integer(y);
		return c;
	}
}


第二步:建立一个taglib2.0以上版本的tld文件。

第三步:在tld文件中添加以下配置。

<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1"> 
    <tlib-version>1.0</tlib-version>
 	<short-name>fn</short-name>
 	<uri>http://www.zq.cn/jsp/jstl/fn</uri>
 	
 	<function>
 		<name>add</name>
 		<function-class>cn.zq.fun.AddFun</function-class>
 		<function-signature>int add(java.lang.String, java.lang.String)</function-signature>
 	</function>
</taglib>

第四步:在页面引用

<%@ taglib uri="http://www.zq.cn/jsp/jstl/fn" prefix="fn" %>
${fn:add("1","2") }


练习:实现一个sayHi自定义函数

package cn.zq.fun;

public class SayHiFuc {
	
	public static String sayHi(String name){
		return "Hi, " + name;
	}
}

 	<function>
 		<name>sayHi</name>
 		<function-class>cn.zq.fun.SayHiFuc</function-class>
 		<function-signature>java.lang.String sayHi(java.lang.String)</function-signature>
 	</function>
${fn:sayHi("RiccioZhang") }


关于标准函数库的相关内容,请查看fn.tld的相关内容



一步一步学JSP--JSTL(三)

标签:java   jsp   jstl   自定义标签   

原文地址:http://blog.csdn.net/ricciozhang/article/details/43372779

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!