4.jstl

0.jstl标签介绍

JavaServer Pages标准标记库(JSTL)是一个有用的JSP标签的集合,它封装了许多JSP应用程序通用的核心功能。

一、作用:JSTL支持常见的,结构性任务,如迭代和条件,标签为操纵XML文件,国际化标签和SQL标签。
它还提供了一个框架,将现有的自定义标签和JSTL标签。

二、组成
	JSTL标签进行分类,根据其功能分为以下,可用于创建一个JSP页面时,JSTL标签库组:

	1.核心标签(Core Tags)

	2.格式化标签(Formatting tags)

	3.SQL标签(SQL tags)

	4.XML标签(XML tags)

	5.JSTL函数(JSTL Functions)

三、安装JSTL库:
	1.如果您使用的是Apache Tomcat容器,那么按照下面两个简单的步骤:

	下载的二进制发行版,从Apache标准标记库和解压的压缩文件。

	使用标准的标签库从Jakarta Taglibs分布,复制发行版'lib'目录到应用程序的JAR文件 webapps\ROOT\WEB-INF\lib 目录中。

	要使用JSTL库,要在每一个JSP的顶部,使用该库必须包括一个<taglib>指令。
	
	2.在开发中使用时注意:使用MyEclipse,不需要我们自己导入jar包,jar在创建项目的时候自动导入;
	
	如果使用的是eclipse必须自己导入。
	jar包:jstl-1.2.jar,standard-1.1.2.jar(不是必须)
	

1.c核心标签

一、在页面导入JSTL核心标签库
	<%taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
	注意,使用时会出现两种标签库,建议使用第二种
	JSTL1.0 的声明是:<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
	JSTL1.1 的声明是:<%@ taglib prefix="c" uri=http://java.sun.com/jsp/jstl/core %>

二、常用的标签
	1.<c:set>
		<c:set var="a" value="hello"/> 		创建名为a,值为hello的域属性,范围:page
		<c:set var="a" value="hello" scope="session"/> scope指定作用域session,request,page
	
	2.<c:out>
		<c:out value="aaa"/> 		输出字符串aaa
		<c:out value="${aaa }"/> 	输出域属性aaa,其中与${aaa}相同
		<c:out value="${aaa }" default="没有找到值"/>	如果${aaa}不存在,那么输出xxx字符串
		<c:out value="${aaa }" escapeXml="true"/>		如果${aaa}中包含特殊字符,那么转义它。这可以防止javascript攻击
		
		escapeXml的用法,如果:<c:set var="a" value="<font size=16>java</font>" />
		<c:out value="${a }"  escapeXml="true"></c:out>,默认为true,输出:<font size=16>java</font>
		<c:out value="${a }"  escapeXml="false"></c:out>,输出大字体大小为16的:java
	
	3.<c:remove>
		<c:remove var="a"/> 				删除名为a的域属性
		<c:remove var="a" scope="page"/> 	删除page域中名为a的域属性
	
	4.<c:url>
		<c:url value="/AServlet"/> 	输出URL:/项目名/AServlet
		<c:url value="/AServlet" var="url" scope="page"/> 把生成的url保存到page域中,而不会输出
		<c:url value="/AServlet">	输出URL:/项目名/AServlet?username=%xx%xx%xx%xx%xx%xx,其中张三会被URL编码
		   <c:param name="username" value="张三"/>
		</c:url/>
	
	5.<c:if>
	<c:if test="${user.id eq 1}"> 当条件为true时执行标签体内容
	    hello
	</c:if>
	
	6.<c:choose>
		<c:choose>
		    <c:when test="${条件1}">a</c:when>
		    <c:when test="${条件2}">b</c:when>
		    <c:when test="${条件3}">c</c:when>
		    <c:otherwise>d</c:otherwise>
	  	</c:choose>
	
	  等同与:
	  if() {
	  } esle if() {
	  } esle if() {
	  } else if() {
	  } else {
	  }
	
	7.<c:forEach>	可以用来遍历数组、List、Map
		(1). 计数循环,默认增加1
			从1到10
			<c:forEach begin="1" end="10" var="i">
			 ${i}
			</c:forEach>
			等同于
			for(int i = 1; i <= 10; i++) {
			  out.println(i);
			}
			从1到10,每次增加2
			<c:forEach begin="1" end="10" var="i" step="2">
			 ${i}
			</c:forEach>
			等同于
			for(int i = 1; i <= 10; i+=2) {
			  out.println(i);
			}
		-------------
		(2). 遍历数组
		<%
			String[] names = {"zhangSan", "liSi", "wangWu", "zhaoLiu"};
			pageContext.setAttribute("ns", names);
		%>
		<c:forEach var="item " items="${ns } ">
			<c:out value="name: ${item } "/><br/>
		</c:forEach>
		-------------
		(3). 遍历List
		<%
			List<String> names = new ArrayList<String>();
			names.add("zhangSan");
			names.add("liSi");
			names.add("wangWu");
			names.add("zhaoLiu");
			pageContext.setAttribute("ns", names);
		%>
		<c:forEach var="item" items="${ns }"> 
			<c:out value="name: ${item }"/><br/>
		</c:forEach>
		-------------
	 	(4). 遍历Map
		<%
			Map<String,String> stu = new LinkedHashMap<String,String>();
			stu.put("number", "N_1001");
			stu.put("name", "zhangSan");
			stu.put("age", "23");
			stu.put("sex", "male");
			pageContext.setAttribute("stu", stu);
		%>
		<c:forEach var="item " items="${stu }">
			<c:out value="${item.key }: ${item.value } "/><br/>
		</c:forEach>
		-------------
		(5). 循环状态对象
		循环状态对象是用来说明循环的状态的,属性如下:
		count:int类型,当前以遍历元素的个数;
		index:int类型,当前元素的下标;
		first:boolean类型,是否为第一个元素;
		last:boolean类型,是否为最后一个元素;
		current:Object类型,表示当前对象。
		
		<c:forEach var="item" items="${ns }" varStatus="vs" >
			<c:if test="${vs.first } ">第一行:</c:if>
			<c:if test="${vs.last } ">最后一行:</c:if>
			<c:out value="第${vs.count } 行: "/>
			<c:out value="[${vs.index } ]: "/>
			<c:out value="name: ${vs.current } "/><br/>
		</c:forEach>
		
三、其他C标签	
	1.<c:redirect>
		<c:redirect url="http://www.baidu.com"/>	重定向到url,以get请求
	
	2.<c:catch>标签捕获任何Throwable,发生在它的身上,有选择地公开。简单地用于错误处理,更优雅地处理这个问题。
		<c:catch var ="catchException">		var是自定义的异常名称
			<% int x = 5/0;%>
	 	</c:catch>

		<c:if test = "${catchException != null}">
		   <p>The exception is : ${catchException} <br />
		   There is an exception: ${catchException.message}</p>
		</c:if>
	3.<c:import>标记提供<include>的所有的功能动作,但也可以包含绝对URL
		<c:import var="data"  url="http://www.baidu.com"/>
		<c:out value="${data}" escapeXml="false"/>
		属性	 			描述	 								必需	 			默认值
		url	 			URL检索和导入到页面	 				Yes	 			None
		context	 		/后面的本地Web应用程序的名称	 		No	 			目前的应用
		charEncoding	为导入数据使用的字符集	 			No	 			ISO-8859-1
		var				变量的名称存储导入的文本	 			No	 			Print to page
		scope			 变量作用域用于存储导入的文本	 		No	 			Page
		varReader	 	替代变量的名称,暴露的java.io.Reader	No	 			None

2.fmt格式化标签

一、导入JSTL格式化标签库
	<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
	
二、常用标签库
	1.<fmt:formatDate>时间格式化,详细看《fmt formatDate标签.png》
		<%
			Date date = new Date();
			pageContext.setAttribute("d", date);
		%>
		<fmt:formatDate value="${d }" pattern="yyyy-MM-dd HH:mm:ss "/>

	2.<fmt:formatNumber>数字格式化,详细看《fmt formatNumber.png》	
		<%
			double d1 = 3.5;
			double d2 = 4.4; 
			pageContext.setAttribute("d1", d1);
			pageContext.setAttribute("d2", d2);
		%>
		<fmt:formatNumber value="${d1 }" pattern="0.00 "/><br/>
		<fmt:formatNumber value="${d2 }" pattern="#.## "/>
	
		pattern:0.00,表示小数不足两位时,使用0补足两位
		pattern:#.##,表示小数不足两位时,有几位显示几位,不会补足
		
三、i18n使用标签
	1.国际化要使用语言文件,以properties为例。
		message_zh_CN.properties保存中文
		message_en_GB.properties保存英文
	
	2.设置本地语言和国家等
		<fmt:setLocale value="en_GB" />
		<fmt:setLocale value="zh_CN" />
		<fmt:setLocale value="${pageContext.request.locale}" />
		
	3.导入文件束,在src下的文件,basename是文件名的前半部分,后半部分可不写,
		<fmt:setBundle basename="message" var="propertiesName" />
	
	4.调用值
		<fmt:message bundle="${propertiesName }" key="sys.login.message"></fmt:message>
	
	5.设置编码
		<fmt:requestEncoding value="UTF-8" />
	
	6.设置时区
		<fmt:timeZone>

3.sql标签

一、JSTL的SQL标签库标签可以交互关系型数据库(如Oracle,MySQL或Microsoft SQL Server的关系数据库管理系统)。
	<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
	
	已经过时了,不要使用啦。已经过时了,不要使用啦。已经过时了,不要使用啦。已经过时了,不要使用啦。
二、标签
	1.注册数据源<sql:setDataSource>
	
	<sql:setDataSource 
		var="account_db" //名称
		driver="com.mysql.jdbc.Driver"			
		url="jdbc:mysql://localhost:3306/accountbook?useUnicode=true&characterEncoding=utf8"
		user="root"  
		password="root"
		scope="page"	//作用域
	/>
	
	2.<sql:query>查询
		<sql:query 
			dataSource="${account_db}" 
			sql="select * from type" 
			var="result" 
			startRow="0"	该行的结果个数,在开始记录,默认0
			maxRows="5"		结果存储在变量中的最大数目
		/>
		或:
		<sql:query dataSource="${account_db}" var="result">
			SELECT * from Employees;
		</sql:query>
		
		处理查询的结果,.rows就是查询结果,且返回的结果中是以数据库字段名称来调用属性值
		<c:forEach items="${result.rows }" var="res">
			${res.id }----${res.name }----${res.creTime }----${res.user_id }<br />
		</c:forEach>
	
	3.<sql:update>标签执行SQL语句不返回数据,例如SQL INSERT,UPDATE或DELETE语句
		<sql:update dataSource="${account_db}" var="count">
		   INSERT INTO TYPE VALUES (8, 2, 'Nuha', 'Ali');
		</sql:update>
	
	4.<sql:transaction>
		用于<sql:query>和<sql:update>组成事务。可以把尽可能多的<sql:query>和<sql:update>作为<sql:transaction>
		内部语句来使他们成为一个单个事务。如果一个异常被任何嵌套的动作抛出,
		它确保了嵌套的动作进行数据库的修改是提交或回滚
	
		<sql:transaction dataSource="${account_db}">
			
			<sql:update var="count">
				UPDATE Students SET last = 'Ali' WHERE Id = 102
			</sql:update>
			
			<sql:update var="count">
				UPDATE Students SET last = 'Shah' WHERE Id = 103
			</sql:update>
			
			<sql:update var="count">
				INSERT INTO Students VALUES (104,'Nuha', 'Ali', '2010/05/26');
			</sql:update>
			
		</sql:transaction>
	
	5.<sql:param>
		与<sql:query>标签和<sql:update>标签嵌套使用,用来提供一个值占位符。如果是一个null值,则将占位符设为SQL NULL。
	
		<c:set var="empId" value="103"/>

		<sql:update dataSource="${account_db}" var="count">
			DELETE FROM Employees WHERE Id = ?
			<sql:param value="${empId}" />
		</sql:update>
	
	6.<sql:dateParam>//type	 DATE (只有日期),TIME(只有时间), TIMESTAMP (日期和时间)
		标签与<sql:query>标签和<sql:update>标签嵌套使用,用来提供日期和时间的占位符。如果是一个null值,则将占位符设为SQL NULL。
		<%
			Date DoB = new Date("2001/12/16");
			int studentId = 100;
		%>
		 
		<sql:update dataSource="${snapshot}" var="count">
		   UPDATE Students SET dob = ? WHERE Id = ?
		   <sql:dateParam value="<%=DoB%>" type="DATE" />
		   <sql:param value="<%=studentId%>" />
		</sql:update>

4.ELfn函数标签

一、导入函数库
	<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

二、EL函数库介绍
	String toUpperCase(String input):转换成大写
	String toLowerCase(String input):转换成小写
	int indexOf(String input, String substring):返回大串中,小串的位置
	boolean contains(String input, String substring):返回大串中是否包含小串
	boolean containsIgnoreCase(String input, String substring):忽略大小写的是否包含
	boolean startsWith(String input, String substring):是否以小串为前缀
	boolean endsWith(String input, String substring):是否以小串为后缀
	String substring(String input, int beginIndex, int endIndex):截取子串
	String substringAfter(String input, String substring):截取小串后的部分!${fn:substringAfter(hello-world, "-")},输出为world
	String substringBefore(String input, String substring):截取小串前面的部分
	String escapeXml(String input):把字符串的">"、"<"。。。转义了!
	String trim(String input):去除前后空格
	String replace(String input, String substringBefore, String substringAfter):替换
	String[] split(String input, String delimiters):分割字符串为数组
	int length[用来返回字符串、数组、以及各种集合的长度](Object obj):可以获取字符串、数组、各种集合的长度!
	String join(String array[], String separator):与split是相反的,使用指定分割符来连接数组,返回一个字符串。

三、案例
	<%
		String[] strs = {"a", "b","c"};
		List list = new ArrayList();
		list.add("a");
		pageContext.setAttribute("arr", strs);
		pageContext.setAttribute("list", list);
	%>
	
	${fn:length(arr) }						<br/><!--3-->
	${fn:length(list) }						<br/><!--1-->
	${fn:toLowerCase("Hello") }				<br/> <!-- hello -->
	${fn:toUpperCase("Hello") }				<br/> <!-- HELLO -->
	${fn:contains("abc", "a")}				<br/><!-- true -->
	${fn:containsIgnoreCase("abc", "Ab")}	<br/><!-- true -->
	${fn:contains(arr, "a")}				<br/><!-- true -->
	${fn:containsIgnoreCase(list, "A")}		<br/><!-- true -->
	${fn:endsWith("Hello.java", ".java")}	<br/><!-- true -->
	${fn:startsWith("Hello.java", "Hell")}	<br/><!-- true -->
	${fn:indexOf("Hello-World", "-")}		<br/><!-- 5 -->
	${fn:join(arr, ";")}					<br/><!-- a;b;c -->
	${fn:replace("Hello-World", "-", "+")}	<br/><!-- Hello+World -->
	${fn:join(fn:split("a;b;c;", ";"), "-")}<br/><!-- a-b-c -->
	${fn:substring("0123456789", 6, 9)}		<br/><!-- 678 -->
	${fn:substring("0123456789", 5, -1)}	<br/><!-- 56789 -->
	${fn:substringAfter("Hello-World", "-")}<br/><!-- World -->
	${fn:substringBefore("Hello-World", "-")}<br/><!-- Hello -->
	${fn:trim("     a b c     ")}			<br/><!-- a b c -->
	${fn:escapeXml("<html></html>")}		<br/><!-- <html></html> -->

############################################################################################
一、自定义EL函数库
	
	1.函数库的Java类
		写一个类,写一个有返回值的静态方法;
		编写itcast.tld文件,可以参数fn.tld文件来写,把itcast.tld文件放到/WEB-INF目录下;
		在页面中添加taglib指令,导入自定义标签库。

	2.或是将写好的函数库打成jar包
		把tld文件放到META-INF下!
		把jar包放到lib中
		在jsp中<%@ taglib %>的uri给出tld中的<uri>

二、代码案例
		
	1.静态方法

		public class FunctionDemo {
			public static String toUpperCase(String str){				
				return str.toUpperCase();
			}
			public static String go(){
				System.out.println(str.toUpperCase());
				return "go";
			}
		}

	2.itcast.tld(默认是放在WEB-INF目录下)
		<?xml version="1.0" encoding="UTF-8"?>
		<taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
			version="2.0">
			
			<tlib-version>1.0</tlib-version>
			<short-name>cao</short-name>
			<uri>http://www.cao.cn/cao</uri>
			
			<function><!-- 定义函数1 -->
				<name>toUppercase</name>
				<function-class>com.jstl.FunctionDemo</function-class>
				<function-signature>java.lang.String toUpperCase(java.lang.String)</function-signature>
			</function>
			
			<function><!-- 定义函数2 -->
				<name>go</name>
				<function-class>com.jstl.FunctionDemo</function-class>
				<function-signature>java.lang.String go()</function-signature>
			</function>
		</taglib>
	
	2.1、(可选步骤)前提是把tld文件放到了WEB-INF目录下。
			告知应用,tld文件和tld中的uri的对应。修改web.xml,增加以下内容:
		<jsp-config>
			<taglib>
				<taglib-uri>http://www.cao.cn/cao</taglib-uri>
				<taglib-location>/WEB-INF/cao.tld</taglib-location>
			</taglib>
		</jsp-config>
	
	3.index.jsp
	<%@ taglib prefix="cao" uri="/WEB-INF/itcast.tld" %>
	或<%@ taglib prefix="cao" uri="http://www.cao.cn/cao" %>

	${cao:toUppercase("asdasdasd") }
	${cao:go }

5.xml标签

已经过时了,不要使用啦。

6.el表达式

一、EL表达式简介

  EL 全名为Expression Language。EL主要作用:
  1、获取数据
    EL表达式主要用于替换JSP页面中的脚本表达式,以从各种类型的web域 中检索java对象、获取数据。(某个web域 中的对象,访问javabean的属性、访问list集合、访问map集合、访问数组)
  2、执行运算
    利用EL表达式可以在JSP页面中执行一些基本的关系运算、逻辑运算和算术运算,以在JSP页面中完成一些简单的逻辑运算。${user==null}
  3、获取web开发常用对象
    EL 表达式定义了一些隐式对象,利用这些隐式对象,web开发人员可以很轻松获得对web常用对象的引用,从而获得这些对象中的数据。
  4、调用Java方法
    EL表达式允许用户开发自定义EL函数,以在JSP页面中通过EL表达式调用Java类的方法。

二、获取数据

  使用EL表达式获取数据语法:"${标识符}"
  EL表达式语句在执行时,会调用pageContext.findAttribute方法,用标识符为关键字,分别从page、request、session、application四个域中查找相应的对象,找到则返回相应对象,找不到则返回"" (注意,不是null,而是空字符串)。

  EL表达式可以很轻松获取JavaBean的属性,或获取数组、Collection、Map类型集合的数据

	${name}等同于pageContext.findAttribute("name")

三、常用用法
	1.根据key取map集合的数据
       ${map.c}  
       ${map["c"]}
	
	2.获取list,set和数组
		${list[1]}
    
    3.迭代Map集合
      <c:forEach var="me" items="${map}">
          ${me.key}=${me.value}
      </c:forEach>


四、执行运算
	+-*/四则运算符就不说啦
	
	1.关系运算符,返回Boolean值
	结合c标签使用,如:<c:if test="${1 == 1 }" ><span>ok</span></c:if>
		${5 == 5}${5 eq 5}也是可以用来比较字符串${"a" == "a"}${"a" eq null}
		${5 != 5}${5 ne 5}
		${5 < 5}${5 lt 5}
		${5 < 5}${5 gt 5}
		${5 <= 5}${5 le 5}
		${5 >= 5}${5 ge 5}
		
	2、逻辑运算符:
		${true && true}${true and true}		true
		${true || false}${true or false}	true	
		${! true}${not true}				false

 	3、empty运算符:检查对象是否为null(空)	
		<c:if test="${empty(emptyList)}">
			对不起,没有您想看的数据
		</c:if>

  4、二元表达式:${user!=null?user.name :""}
  
	5、[ ] 和 . 号运算符

五、获得web开发常用对象

  EL表达式语言中定义了11个隐含对象,使用这些隐含对象可以很方便地获取web开发中的一些常见对象,并读取这些对象的数据。
  语法:${隐式对象名称}:获得对象的引用

	序号	隐含对象名称		描       述
	1		pageContext			对应于JSP页面中的pageContext对象(注意:取的是pageContext对象。)
	2		pageScope			代表page域中用于保存属性的Map对象
	3		requestScope		代表request域中用于保存属性的Map对象
	4		sessionScope		代表session域中用于保存属性的Map对象
	5		applicationScope	代表application域中用于保存属性的Map对象
	6		param				表示一个保存了所有请求参数的Map对象
	7		paramValues			表示一个保存了所有请求参数的Map对象,它对于某个请求参数,返回的是一个string[]
	8		header				表示一个保存了所有http请求头字段的Map对象,注意:如果头里面有"-" ,			
								例Accept-Encoding,则要header["Accept-Encoding"]
	9		headerValues		表示一个保存了所有http请求头字段的Map对象,它对于某个请求参数,返回的是一个string[]数组。
								注意:如果头里面有"-" ,例Accept-Encoding,则要headerValues["Accept-Encoding"]
	10		cookie				表示一个保存了所有cookie的Map对象
	11		initParam			表示一个保存了所有web应用初始化参数的map对象
	${pageContext.request.contextPath }			/20160605_http

六、使用EL调用Java方法

  EL表达式语法允许开发人员开发自定义函数,以调用Java类的方法。语法:${prefix:method(params)}
  在EL表达式中调用的只能是Java类的静态方法,这个Java类的静态方法需要在TLD文件中描述,才可以被EL表达式调用。
  EL自定义函数用于扩展EL表达式的功能,可以让EL表达式完成普通Java程序代码所能完成的功能。

	1、EL Function开发步骤

	  一般来说, EL自定义函数开发与应用包括以下三个步骤:
	  1、编写一个Java类的静态方法
	  2、编写标签库描述符(tld)文件,在tld文件中描述自定义函数。
	  3、在JSP页面中导入和使用自定义函数


	2、开发EL Function注意事项

	  编写完标签库描述文件后,需要将它放置到<web应用>\WEB-INF目录中或WEB-INF目录下的除了classes和lib目录之外的任意子目录中。 
	  TLD文件中的<uri> 元素用指定该TLD文件的URI,在JSP文件中需要通过这个URI来引入该标签库描述文件。
	  <function>元素用于描述一个EL自定义函数,其中:
	  <name>子元素用于指定EL自定义函数的名称。
	  <function-class>子元素用于指定完整的Java类名,
	  <function-signature>子元素用于指定Java类中的静态方法的签名,方法签名必须指明方法的返回值类型及各个参数的类型,各个参数之间用逗号分隔。

	3、EL注意事项

	  EL表达式是JSP 2.0规范中的一门技术 。因此,若想正确解析EL表达式,需使用支持Servlet2.4/JSP2.0技术的WEB服务器。
	注意:有些Tomcat服务器如不能使用EL表达式
		(1)升级成tomcat6
		(2)在JSP中加入<%@ page isELIgnored="false" %>


	4.直接调用对象的方法
	比如响应中有值为:money,他是一个BigDecimal类型的数据,如果想在页面上与整数
	0判断,需要将对象转为int类型,我们可以调用他的intValue方法。
	
	BigDecimal money == new BigDecimal(0.00);

	${money.intValue() eq 0} 结果是页面打印 true

7.自定义jstl标签

一、标签的存在,用来替代<%...%>!(在jsp上,是禁止写java脚本的)
	JSP到底要做些什么!(1. 收集用户的参数,传递给Servlet。2. 把Servlet的处理结果显示给用户看)

二、自定义标签
	
	流程
		1.写一个标签处理类
		2.编写tld文件(标签库描述符)
		3.JSP页面中<% taglib %>导入标签库
	
	1.写一个标签处理类
		Tag(老版本)、SimpleTag(JSP2.0提供的新接口)、继承TagSupport类
		(1).Tag接口:其中的方法都是由容器调用的。
			常量:
				SKIP_BODY:忽略标签的主体内容。只为doStartTag方法服务
				EVAL_BODY_INCLUDE:不忽略标签的主体内容。只为doStartTag方法服务
				SKIP_PAGE:忽略结束标签之后的内容。只为doEndTag方法服务
				EVAL_PAGE:不忽略结束标签之后的内容。只为doEndTag方法服务
			方法:
				int doStartTag():容器调用。遇到自定义标签的开始标签时被调用。
				int doEndTag():容器调用。遇到自定义标签的结束时被调用。
				void setPageContext(PageContext pc):由容器调用。处理标签之前就会调用。
				void setParent(Tag t):由容器调用。处理标签之前就会调用。目标传递进父标签,没有传递null。
				void release() :由容器调用,释放标签类占用的资源。
				
				
		(2).IterationTag接口:继承Tag接口。增加重复执行主体内容的方法
			int doAfterBody():执行完主体后会被容器调用该方法。
				该方法的返回值只能是:Tag.SKIP_BODY,忽略主体,进入结束标签处理。
									  IterationTag.EVAL_BODY_AGAIN,再执行一次主体内容。
			
		(3).BodyTag接口:继承IterationTag接口。增加了获取主体内容的方法。
			int EVAL_BODY_BUFFERED:给doStartTag()方法用的。只有返回该值,以下2个方法才会被容器调用。
			
			void doInitBody():初始化主体。容器调用
			void setBodyContent(BodyContent b) :设置主体内容。容器调用。BodyContent就代表着主体内容。
		
		(4).SimpleTag接口:*****jsp2.0添加,是目前jstl标签的实现接口
			void doTag():每次执行标签时都会调用这个方法!容器调用。
			JspTag getParent():获取父标签!(不是生命周期方法,没人会调用它,除了我们自己)
			void setJspBody(JspFragment jspBody):容器调用。传入标签的主体内容。
			void setJspContext(JspContext pc):容器调用。传入PageContext对象。
			void setParent(JspTag parent):容器调用。传入父标签。
	
		(5).继承SimpleTagSupport
			void doTag():我们只需要完成这一个方法即可,其他的方法都被父类完成了。
			SimpleTagSupport类还提供了一系列的get方法,用来获取tomcat传递进来"礼物"!

	2.编写tld文件
		<tag>
			<!-- 标签名称 -->
			<name>myTag1</name>
			<!-- 标签处理类 -->
			<tag-class>cn.itcast.tags.MyTag1</tag-class>
			<!-- 标签体的类型,empty表示没有标签体 -->
			<body-content>empty</body-content>
		</tag>

	3.在jsp中导入标签库
		<%@ taglib prefix="" uri=""%>


三、自定义标签概述

	1.自定义标签的步骤
		其实我们在JSP页面中使用标签就等于调用某个对象的某个方法一样,例如:<c:if test="">,这就是在调用对象的方法一样。自定义标签其实就是自定义类一样!
		定义标签处理类:必须是Tag或SimpleTag的实现类;
		编写标签库描述符文件(TLD);

	SimpleTag接口是JSP2.0中新给出的接口,用来简化自定义标签,所以现在我们基本上都是使用SimpleTag。
	Tag是老的,传统的自定义标签时使用的接口,现在不建议使用它了。

	2.SimpleTag接口介绍
		SimpleTag接口内容如下:
		void doTag():标签执行方法;
		JspTag getParent():获取父标签;
		void setParent(JspTag parent):设置父标签
		void setJspContext(JspContext context):设置PageContext
		void setJspBody(JspFragment jspBody):设置标签体对象;

	请记住,万物皆对象!在JSP页面中的标签也是对象!你可以通过查看JSP的"真身"清楚的知道,所有标签都会变成对象的方法调用。
		标签对应的类我们称之为"标签处理类"!
	
	标签的生命周期:
	1.当容器(Tomcat)第一次执行到某个标签时,会创建标签处理类的实例;
	2.然后调用setJspContext(JspContext)方法,把当前JSP页面的pageContext对象传递给这个方法;
	3.如果当前标签有父标签,那么使用父标签的标签处理类对象调用setParent(JspTag)方法;
	4.如果标签有标签体,那么把标签体转换成JspFragment对象,然后调用setJspBody()方法;
	5.每次执行标签时,都调用doTag()方法,它是标签处理方法。

四、案例

	1.创建类HelloTag.java
		public class HelloTag implements SimpleTag {
			private JspTag parent;
			private PageContext pageContext;
			private JspFragment jspBody;
			
			public void doTag() throws JspException, IOException {
				pageContext.getOut().print("Hello Tag!!!");[获取out对象,输出Hello Tag!!!]
			}
			public void setParent(JspTag parent) {
				this.parent = parent;
			}
			public JspTag getParent() {
				return this.parent;
			}
			public void setJspContext(JspContext pc) {
				this.pageContext = (PageContext) pc;
			}
			public void setJspBody(JspFragment jspBody) {
				this.jspBody = jspBody;
			}
		}

	2. 标签库描述文件(TLD)
		标签库描述文件是用来描述当前标签库中的标签的!标签库描述文件的扩展名为tld,你可以把它放到WEB-INF下,这样就不会被客户端直接访问到了。
		hello.tld
		<?xml version="1.0" encoding="UTF-8"?>
		<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
			xmlns:xml="http://www.w3.org/XML/1998/namespace" 
			xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
			xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
								http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd ">

			<tlib-version>1.0</tlib-version>[指定当前标签库的版本]
			<short-name>itcast</short-name>[指定当前标签库的简称,这个名称无所谓了,随便起。]
			<uri>http://www.itcast.cn/tags</uri>[指定标签库的uri]
			<tag>[部署一个标签!一个<tag>表示一个标签。]
				<name>hello</name>[指定标签的名称]
				<tag-class>cn.itcast.tag.HelloTag</tag-class>[指定标签处理类]
				<body-content>empty</body-content>[指定标签体内容类型为空类型,即没有标签体。]
			</tag>
		</taglib>

	3. 使用标签
		在页面中使用标签分为两步:
		使用taglib导入标签库;
		使用标签;

		<%@ taglib prefix="it" [指定标签库前缀]uri="/WEB-INF/hello.tld"[指定标签库的tld文件位置] %>
		......
		<it:hello/>

五、自定义标签进阶
	1.继承SimpleTagSupport
	  继承SimpleTagSuppport要比实现SimpleTag接口方便太多了,现在你只需要重写doTag()方法,其他方法都已经被SimpleTagSuppport完成了。

		public class HelloTag extends SimpleTagSupport {
			public void doTag() throws JspException, IOException {
				this.getJspContext().getOut().write("<p>Hello SimpleTag!</p>")[向页面输出!注意,不能向页面输出<%%>东西!];
			}
		}

	2.有标签体的标签
		我们先来看看标签体内容的可选值:
		<body-content>元素的可选值有:
		empty:无标签体。
		JSP[SimpleTag不能使用它!]:传统标签支持它,SimpleTag已经不再支持使用<body-content>JSP</body-content>。
		标签体内容可以是任何东西:EL、JSTL、<%=%>、<%%>,以及html; 
		scriptless[它使用的最多!]:标签体内容不能是Java脚本,但可以是EL、JSTL等。在SimpleTag中,如果需要有标签体,那么就使用该选项;
		tagdependent[没人会用!]:标签体内容不做运算,由标签处理类自行处理,无论标签体内容是EL、JSP、JSTL,都不会做运算。这个选项几乎没有人会使用!

	自定义有标签体的标签需要:
	获取标签体对象:JspFragment jspBody = getJspBody();;
	把标签体内容输出到页面:jspBody.invoke(null);
	tld中指定标签内容类型:scriptless。

	public class HelloTag extends SimpleTagSupport {
		public void doTag() throws JspException, IOException {
			PageContext pc = (PageContext) this.getJspContext();
			HttpServletRequest req = (HttpServletRequest) pc.getRequest();
			String s = req.getParameter("exec");
			if(s != null && s.endsWith("true")) {
				JspFragment body = this.getJspBody()[获取当前标签的标签体对象];
				body.invoke[向页面输出标签体内容。](null);
			}
		}
	}
	
	<tag>
		<name>hello</name>
		<tag-class>cn.itcast.tags.HelloTag</tag-class>
		<body-content>scriptless</body-content>[指定标签体内容为scriptless,即标签体内容可以是正常的html,也可以是EL或JSTL]
	</tag>
    <itcast:hello>
     	<h1>哈哈哈~</h1>
    </itcast:hello>

	3.不执行标签下面的页面内容
	  如果希望在执行了自定义标签后,不再执行JSP页面下面的东西,那么就需要在doTag()方法中使用SkipPageException。
	public class SkipTag extends SimpleTagSupport {
		public void doTag() throws JspException, IOException {
			this.getJspContext().getOut().print("<h1>只能看到我!</h1>");
			throw new SkipPageException();[这个异常不会导致页面报错,但该标签下的内容就看不到了!]
		}
	}
	<tag>
		<name>skip</name>
		<tag-class>cn.itcast.tags.SkipTag</tag-class>
		<body-content>empty</body-content>
	</tag>
  <itcast:skip/>
  <h1>看不见我!</h1>

	4.带有属性的标签
	  一般标签都会带有属性,例如<c:if test="">,其中test就是一个boolean类型的属性。完成带有属性的标签需要:
	在处理类中给出JavaBean属性(提供get/set方法);
	在TLD中部属相关属性。

	public class IfTag extends SimpleTagSupport {
		private boolean test;
		public boolean isTest() {
			return test;
		}
		public void setTest[该方法会在doTag()之前被调用,传入属性值。](boolean test) {
			this.test = test;
		}
		@Override
		public void doTag() throws JspException, IOException {
			if(test) {
				this.getJspBody().invoke(null);
			}[如果test为true,执行标签体内容,否则什么都不做。]
		}
	}
	<tag> 
		<name>if</name> 
		<tag-class>cn.itcast.tag.IfTag</tag-class> 
		<body-content>scriptless</body-content>
		<attribute>[声明属性]
			<name>test</name>[属性名称为test]
			<required>true</required>[为true表示属性是必须的,为false表示属性为可选的。]
			<rtexprvalue>true</rtexprvalue>[为true表示属性值可以为EL或JSTL,否则表示只能是常量。]
		</attribute> 
	</tag>
	<%
		pageContext.setAttribute("one", true);
		pageContext.setAttribute("two", false);
	%>
	<it:if test="${one }">xixi</it:if>[可以看到xixi]
	<it:if test="${two }">haha</it:if>[不会执行haha]
	<it:if test="true">hehe</it:if>[可以看到hehe]

文章信息

张雪随笔
master
Homepage
Issues
Download

This Software is under the terms of The Unlicense.