1.什麼是自定義標籤?
用戶定義的一種自定義的jsp標記 。當一個含有自定義標籤的jsp頁面被jsp引擎編譯成servlet時,tag標籤被轉化成了對一個稱爲 標籤處理類 的對象的操作。於是,當jsp頁面被jsp引擎轉化爲servlet後,實際上tag標籤被轉化爲了對tag處理類的操作。
2.導入JSTL標籤庫:
通過JSTL標籤遍歷集合元素
<%@page import="com.zhaoliang.tag.Customer"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 導入JSTL標籤庫,注意:如果沒有 /jsp 會出現 XXX does not support runtime expressions-->
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<!-- 遍歷customers中元素,並打印name和age -->
<c:forEach items="${requestScope.customers }" var="customer">
--${customer.name },${customer.age }<br>
</c:forEach>
</body>
</html>
<%@page import="com.zhaoliang.tag.Customer"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<%
//模擬Servlet中的操作
List<Customer> customers = new ArrayList<Customer>();
customers.add(new Customer("AA",11));
customers.add(new Customer("BB",12));
customers.add(new Customer("CC",13));
request.setAttribute("customers", customers);
%>
<jsp:forward page="testtag.jsp"></jsp:forward>
</body>
</html>
3.標籤庫介紹:
1)接口和類之間的關係
2)自定義標籤分類:
(1)空標籤:<hello/>
(2)帶有屬性的空標籤:
<max num1=“3” num2=“5”/>
(3)帶有內容的標籤:
<greeting>
hello
</greeting>
(4)帶有內容和屬性的標籤:
<greeting name=“Tom”>
hello
</greeting>
3)自定義標籤
(1)開發自定義標籤,其核心就是要編寫處理器類,一個標籤對應一個標籤處理器類,而一個標籤庫則是很多標籤處理器的集合。所有的標籤處理器類都要實現 JspTag 接口,該接口中沒有定義任何方法,主要作爲 Tag 和 SimpleTag 接口的父接口。
(2)開發自定義標籤的步驟:①編寫完成標籤功能的 Java 類(標籤處理器) ②編寫標籤庫描述(tld)文件,在tld文件中對自定義中進行描述 ③在 JSP 頁面中導入和使用自定義標籤(3)標籤類中方法介紹
4)自定義空標籤:<hello/>
(1)編寫標籤處理類(HelloSimpleTag):該類實現了 SimpleTag 接口
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;
public class HelloSimpleTag implements SimpleTag {
<span style="white-space:pre"> </span>@Override
<span style="white-space:pre"> </span>public void doTag() throws JspException, IOException {
<span style="white-space:pre"> </span>pageContext.getOut().print("hello");
<span style="white-space:pre"> </span>HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
<span style="white-space:pre"> </span>pageContext.getOut().print("hello : " + request.getParameter("name"));
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>@Override
<span style="white-space:pre"> </span>public JspTag getParent() {
<span style="white-space:pre"> </span>// TODO Auto-generated method stub
<span style="white-space:pre"> </span>return null;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>@Override
<span style="white-space:pre"> </span>public void setJspBody(JspFragment arg0) {
<span style="white-space:pre"> </span>// TODO Auto-generated method stub
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>private PageContext pageContext;
<span style="white-space:pre"> </span>@Override
<span style="white-space:pre"> </span>public void setJspContext(JspContext arg0) {
<span style="white-space:pre"> </span>this.pageContext = (PageContext)arg0;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>@Override
<span style="white-space:pre"> </span>public void setParent(JspTag arg0) {
<span style="white-space:pre"> </span>// TODO Auto-generated method stub
<span style="white-space:pre"> </span>}
}
(2)編寫標籤庫描述文件(*.tld)
<?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">
<!-- 描述TLD文件 -->
<description>MyTag 1.0 core library</description>
<display-name>MyTag core</display-name>
<tlib-version>1.0</tlib-version>
<!-- 建議在 JSP 頁面上使用的標籤的前綴 -->
<short-name>tagZ</short-name>
<!-- 作爲TLD 文件的ID,用來唯一標識當前的 TLD 文件,多個TLD 文件的 URI 不能重複,
通過JSP頁面的 taglib 標籤的 uri 屬性來引用 -->
<uri>http://www.haha.com/mytag/core</uri>
<!-- 描述自定義的 HelloSimpleTag 標籤 -->
<tag>
<!-- 標籤的名稱 -->
<name>hello</name>
<!-- 標籤對應類的全類名 -->
<tag-class>com.haha.tag.HelloSimpleTag</tag-class>
<!-- 標籤體類型 -->
<body-content>empty</body-content>
</tag>
</taglib>
(3)在JSP 頁面導入標籤庫
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!-- 導入標籤庫(描述文件) -->
<%@ taglib prefix="tagz" uri="http://www.zhaoliang.com/mytag/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<tagz:hello/>
</body>
</html>
5)自定義帶有屬性的空標籤:
<max num1=“3” num2=“5”/>
(1)在標籤處理類中定義 XXX 屬性和 setXXX() 方法
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.SimpleTag;
public class HelloSimpleTag implements SimpleTag {
private String value;
private int count;
public void setValue(String value) {
this.value = value;
}
public void setCount(int count) {
this.count = count;
}
@Override
public void doTag() throws JspException, IOException {
pageContext.getOut().print(count + " : " + value);
pageContext.getOut().print("<br>");
HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
pageContext.getOut().print("hello : " + request.getParameter("name"));
}
@Override
public JspTag getParent() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setJspBody(JspFragment arg0) {
// TODO Auto-generated method stub
}
private PageContext pageContext;
@Override
public void setJspContext(JspContext arg0) {
this.pageContext = (PageContext)arg0;
}
@Override
public void setParent(JspTag arg0) {
// TODO Auto-generated method stub
}
}
(2)在TLD描述文件中對標籤進行描述
<?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">
<!-- 描述TLD文件 -->
<description>MyTag 1.0 core library</description>
<display-name>MyTag core</display-name>
<tlib-version>1.0</tlib-version>
<!-- 建議在 JSP 頁面上使用的標籤的前綴 -->
<short-name>tagZ</short-name>
<!-- 作爲TLD 文件的ID,用來唯一標識當前的 TLD 文件,多個TLD 文件的 URI 不能重複,
通過JSP頁面的 taglib 標籤的 uri 屬性來引用 -->
<uri>http://www.zhaoliang.com/mytag/core</uri>
<!-- 描述自定義的 HelloSimpleTag 標籤 -->
<tag>
<!-- 標籤的名稱 -->
<name>hello</name>
<!-- 標籤對應類的全類名 -->
<tag-class>com.zhaoliang.tag.HelloSimpleTag</tag-class>
<!-- 標籤體類型 -->
<body-content>empty</body-content>
<!-- 描述當前標籤的屬性 -->
<attribute>
<!-- 屬性名 -->
<name>value</name>
<!-- 該屬性是否是必須的 -->
<required>true</required>
<!-- rtexprvalue : runtime expression value
當前屬性是否接受運行時表達式的動態值 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>count</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
(3)使用標籤
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!-- 導入標籤庫(描述文件) -->
<%@ taglib prefix="tagz" uri="http://www.zhaoliang.com/mytag/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<tagz:hello value="${param.name }" count="${param.count }" />
</body>
</html>
6)帶有內容的標籤:<greeting>
hello
</greeting>
(1)若標籤中含有標籤體,則在標籤處理器中使用 JspFragment 對象封裝標籤體信息
(2)若標籤含有標籤體,則 JSP 引擎會調用 setJspBody() 方法把 JspFragment 對象傳給標籤處理器。在SimpleTagSupport 中還定義了一個 getJspBody() 方法用於返回 JspFragment 對象
(3)JspFragment 的 invoke(Writer) 方法:把標籤體內容從Writer中輸出,若爲null,則等同於invoke(getJspContext().getOut()),即直接把標籤體內容輸出到頁面上。
(4)在TLD 文件中,使用<body-content>來描述標籤體類型,取值:
①empty:沒有標籤體
②scriptless:標籤體可以包含 el 表達式和 JSP 動作元素,但不能包含 JSP 的腳本元素
③tagdependent:表示標籤體交由標籤本身去解析處理。若指定 tagdependent,在標籤體中的所有代碼都會原封不動的交給標籤處理器,而不是將執行結果傳遞給標籤處理器
練習:自定義帶有屬性和標籤體的標籤:將標籤體的內容轉換爲大寫,並輸出time次
處理器類(TestFragment)
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class TestFragment extends SimpleTagSupport {
private int time;
public void setTime(int time) {
this.time = time;
}
@Override
public void doTag() throws JspException, IOException {
//1.得到標籤體內容
JspFragment bodycontent = getJspBody();
StringWriter sw = new StringWriter();
bodycontent.invoke(sw);
String content = sw.toString();
//2.將標籤體內容轉換成大寫
content.toUpperCase();
//3.循環輸出
for(int i = 0;i < time;i++){
getJspContext().getOut().print(content);
getJspContext().getOut().print("<br>");
}
}
}
配置TLD
<tag>
<name>toUperCase</name>
<tag-class>com.javalearning.tag.TestFragment</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>time</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
測試
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="tag" uri="http://www.java.com/mytag_1/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<tag:toUperCase time="5">zhaoliang</tag:toUperCase>
</body>
</html>
練習:模擬forEach標籤
編寫標籤處理器
import java.io.IOException;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import org.apache.catalina.connector.Request;
public class ListIteratorWithBody extends SimpleTagSupport {
private List lists;
private String var;
public void setLists(List lists) {
this.lists = lists;
}
public void setVar(String var) {
this.var = var;
}
@Override
public void doTag() throws JspException, IOException {
if(lists != null){
for(Object obj : lists){
getJspContext().setAttribute(var, obj);
getJspBody().invoke(null);
}
}
}
}
配置 TLD 文件
<tag>
<name>forEach</name>
<tag-class>com.javalearning.tag.ListIteratorWithBody</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>lists</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
測試
<%
List<Customer> lists = new ArrayList<Customer>();
lists.add(new Customer("AA",12));
lists.add(new Customer("BB",13));
lists.add(new Customer("CC",14));
request.setAttribute("lists", lists);
%>
<tag:forEach lists="${requestScope.lists }" var="cust">
${cust.name }--${cust.age }
</tag:forEach>
7)帶有父標籤的標籤:
<greeting name=“Tom”>hello
</greeting>
(1)父標籤無法獲取子標籤的引用,父標籤僅把子標籤當作標籤體來使用
(2)子標籤可以通過 getParent() 方法來引用父標籤(需要繼承 SimpleTagSupport 類或者實現 SimpleTag 接口的該方法):若子標籤的確有父標籤,JSP 會把帶有父標籤的引用通過 setParent(JspTag parent) 來賦給標籤處理器
(3)由於父標籤類型爲 JspTag 類型,該接口是一個空接口,用來統一 SimpleTag 和 Tag 的,實際使用需要進行類型的強制轉換。
(4)在TLD 文件中,不需要爲父標籤進行額外的配置,但子標籤是以標籤體存在的,所以父標籤的:<body-content>scriptless</body-content>
練習:
<%--
1.開發3個標籤:choose when otherwise
2.其中when標籤有一個boolean類型的屬性:test
3.choose是when和otherwise的父標籤,when在otherwise之前使用
4.在父標籤choose中定義一個“全局”的 boolean 類型變量 flag :
用於判斷子標籤在滿足條件的情況下是否執行
1)若 when 的 test 爲 true,且 when 父標籤的 flag 也爲 true,則執行 when 的標籤體,並將 flag 置爲 false
2)若 when 的 test 爲 true,且 when 父標籤的 flag 爲 false,則不執行 when 的標籤體
3)若 flag 爲 true,otherwise執行標籤體
--%>
<tag:choose>
<tag:when test="${param.age > 22}">大學畢業</tag:when>
<tag:when test="${param.age > 18}">高中畢業</tag:when>
<tag:otherwise>高中以下...</tag:otherwise>
</tag:choose>
(1)編寫choose標籤處理器
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ChooseTag extends SimpleTagSupport {
private boolean flag = true;
public void setFlag(boolean flag) {
this.flag = flag;
}
public boolean isFlag() {
return flag;
}
@Override
public void doTag() throws JspException, IOException {
getJspBody().invoke(null);
}
}
(2)編寫when標籤處理器
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class WhenTag extends SimpleTagSupport {
private boolean test;
public void setTest(boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
if(test){
ChooseTag chooseTag = (ChooseTag)getParent();
boolean flag = chooseTag.isFlag();
if(flag){
getJspBody().invoke(null);
chooseTag.setFlag(false);
}
}
}
}
(3)編寫otherwise標籤處理器
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class OtherwiseTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
ChooseTag chooseTag = (ChooseTag)getParent();
if(chooseTag.isFlag()){
getJspBody().invoke(null);
}
}
}
(4)配置標籤
<tag>
<name>choose</name>
<tag-class>com.javalearning.tag.ChooseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
<tag>
<name>when</name>
<tag-class>com.javalearning.tag.WhenTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>otherwise</name>
<tag-class>com.javalearning.tag.OtherwiseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
(5)測試
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="tag" uri="http://www.java.com/mytag_1/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%--
1.開發3個標籤:choose when otherwise
2.其中when標籤有一個boolean類型的屬性:test
3.choose是when和otherwise的父標籤,when在otherwise之前使用
4.在父標籤choose中定義一個“全局”的 boolean 類型變量 flag :
用於判斷子標籤在滿足條件的情況下是否執行
1)若 when 的 test 爲 true,且 when 父標籤的 flag 也爲 true,則執行 when 的標籤體,並將 flag 置爲 false
2)若 when 的 test 爲 true,且 when 父標籤的 flag 爲 false,則不執行 when 的標籤體
3)若 flag 爲 true,otherwise執行標籤體
--%>
<tag:choose>
<tag:when test="${param.age > 22}">大學畢業</tag:when>
<tag:when test="${param.age > 18}">高中畢業</tag:when>
<tag:otherwise>高中以下...</tag:otherwise>
</tag:choose>
</body>
</html>