自定义标签
1.HelloWorld
1).创建一个标签处理器类:实现SimpleTag接口
2).在WEB-INF文件夹下新建一个.tld(标签描述文件)为扩展名的xml文件,并拷入固定的部分
<?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">
<description>JSTL 1.1 core library</description>
<display-name>JSTL core</display-name>
<tlib-version>1.1</tlib-version>
<short-name>c</short-name>
<uri>http://java.sun.com/jsp/jstl/core</uri>
修改为了:
<?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>zc</short-name>
<!-- 作为tld的id,用哪个来唯一标识当前的tld文件,多个tld文件的uri不能重复,
通过JSP页面的taglib标签的uri属性来引用 -->
<uri>http://www.zc.com/mytag/core</uri>
<!-- 描述自定义的HelloSimpleTag标签 -->
<tag>
<!-- 标签名:在JSP页面使用标签时的名字 -->
<name>hello</name>
<!-- 标签所在的全类名 -->
<tag-class>com.zc.javaweb.tag.HelloSimpleTag</tag-class>
<!-- 标签体的类型 -->
<body-content>empty</body-content>
</tag>
</taglib>
3).使用自定义标签:
使用taglib指令导入标签库描述文件:
<%@ taglib uri="http://www.zc.com/mytag/core" prefix="zc" %>
使用自定义标签:
<zc:hello/>
----------
循环遍历
<%
//模拟Servlet中的操作
List<Customer2> customers=new ArrayList<Customer2>();
customers.add(new Customer2(1,"A",11));
customers.add(new Customer2(2,"B",12));
customers.add(new Customer2(3,"C",13));
customers.add(new Customer2(4,"D",14));
customers.add(new Customer2(5,"E",15));
request.setAttribute("customers", customers);
%>
引入
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- 在页面上对request中的customers属性进行便遍历,打印id,name,age -->
<c:forEach items="${requestScope.customers }" var="customer">
--${customer.id }, ${customer.name }, ${customer.age }<br>
</c:forEach>
------
2.setJspContext:一定会被JSP引擎所调用,限于doYag,把代表JSP引擎的pageContext传给标签处理器类。
代码:
private PageContext pageContext;
//JSP引擎调用,把代表JSP页面的PageConetxt对象传入
//PageContext可以获取JSP页面的其他8个隐含对象。
//所以JSP页面能做的,标签处理器都可以完成
@Override
public void setJspContext(JspContext arg0) {
// TODO Auto-generated method stub
System.out.println(arg0 instanceof PageContext);
this.pageContext=(PageContext)arg0;
}
3.带属性的自定义标签:
1).先在标签处理器类中定义setter方法。建议把所以属性类型都设置为String类型
private String value;
private String count;
public void setValue(String value) {
this.value = value;
}
public void setCount(String count) {
this.count = count;
}
2).在tld描述文件中描述属性
<!-- 描述当前标签的属性 -->
<attribute>
<!-- 属性名,需和标签处理器类的setter方法定义的属性相同 -->
<name>value</name>
<!-- 该属性是否必须 -->
<required>true</required>
<!-- rtexprvalue:runtime expression value:当前属性是否可以接受运行时表达式的动态值 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<!-- 属性名 -->
<name>count</name>
<!-- 该属性是否必须 -->
<required>false</required>
<!-- rtexprvalue:runtime expression value:当前属性是否可以接受运行时表达式的动态值 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
3). 在页面中使用属性,属性名同tld文件中定义的 名字。
<zc:hello value="${param.name }" count="10"/>
4).通常情况下开发简单标签直接继承SimpleTagSupport就可以了,可以直接调用其对应该getter方法得到对应的API
源码
public class SimpleTagSupport implements SimpleTag {
@Override
public void doTag() throws JspException, IOException {
}
private JspTag parentTag;
@Override
public void setParent( JspTag parent ) {
this.parentTag = parent;
}
@Override
public JspTag getParent() {
return this.parentTag;
}
private JspContext jspContext;
@Override
public void setJspContext( JspContext pc ) {
this.jspContext = pc;
}
protected JspContext getJspContext() {
return this.jspContext;
}
private JspFragment jspBody;
@Override
public void setJspBody( JspFragment jspBody ) {
this.jspBody = jspBody;
}
protected JspFragment getJspBody() {
return this.jspBody;
}
}
4.带标签体的标签:
1).若一个标签有标签体:
<zc:testJspFragment>HelloWorld</zc:testJspFragment>
在自定义标签的标签处理器中使用JspFragment对象封装标签体信息。
2).若配置了标签含有标签体,则JSP引擎会调用setJspBody()方法
把 JspFragment 传递给标签处理器类
在SimpleTagSupport中,还定义了一个getJspBody()方法,用于返回JspFragment对象。
3).JspFragment的invoke(Writer)方法:
把标签体内容从Writer中输出,若为null则等同于invoke(getJspContext().getOut()),即直接把标签体内容输出到页面上
有时,可以借助于StringWriter,可以在标签处理器类中先得到标签体的内容:
//1.利用StringWriter得到标签体的内容
StringWriter sw=new StringWriter();
bodyContent.invoke(sw);
//2.把标签体的内容都变为大写
String content =sw.toString().toUpperCase();
//3.获取JSP页面的out隐含对象,输出到页面上
getJspContext().getOut().print(content);
4).在tld文件中,使用body-content及诶单来描述标签体的类型:
<body-content>:指定标签体的类型,大部分情况下,取值为scriptless。可能取值有3种:
empty:没有标签体
scriptless:标签体可以包含el表达式和JSP动作元素,但不能包含JSP的脚本元素
tagdependent:表示标签体交由标签本身去解析处理。
若指定tagdependent,在标签体中的所有代码都会原封不动的交给标签处理器,而不是将执行结果传递给标签处理器
<body-content>tagdependent</body-content>
5).在定义一个自定义标签:<zc:printUpper time="10" >aasadd</zc>把标签体内容转换为大写,并输出time次到
浏览器上。
6).实现forEach标签:
--两个属性:items(集合类型,collection),var(String类型)
--doTag:
*遍历tiems对应的集合,
*把正在遍历的对象放入到pageContext中,键:var 值:正在遍历的对象
*把标签体的内容直接输出到页面上。
<c:forEach items="${ requestScope.customers}" var="cust">
${pageScope.cust.id }--${cust.name }<br>
</c:forEach>
5.开发有父标签的标签:
1).父标签无法获取字标签的引用,父标签仅把字标签作为标签体来使用
2).字标签可以通过getParent()方法来获取父标签的引用(需要继承SimpleTagSupport或自实现SimpleTag接口的该方法):
若字标签的却咩有父标签,JSP引擎会把代表父标签的引用setParent(JspTag parent)赋给标签处理器
3).注意:父标签的类型是JspTag类型。该接口是一个空接口,但是来统一SimpleTag和Tag的。实际使用需要进行类型的强制转换。
子标签代码:
@Override
public void doTag() throws JspException, IOException {
//1.得到父标签的引用
JspTag parent=getParent();
//2.获得父标签的namee属性
ParentTag parentTag=(ParentTag)parent;
String name=parentTag.getName();
//3.把name值打印到JSP页面上。
getJspContext().getOut().print("字标签输出name:"+name);
}
父标签代码:
private String name="ZZCC";
public String getName() {
return name;
}
@Override
public void doTag() throws JspException, IOException {
System.out.println("父标签的标签处理器类name:"+name);
getJspBody().invoke(null);
}
4).在tld配置文件中,无需为父标签有额外的配置。但,子标签是以标签体的形式存在的,所以父标签的
为<body-content>scriptless</body-content>
5).实现
<c:choose>
<c:when test="${param.age>24}">大学毕业</c:when>
<c:when test="${param.age>20}">高中毕业</c:when>
<c:otherwise>高中以下学历</c:otherwise>
</c:choose>
--开发3个标签 :choose,when,otherwise
--其中when标签有一个boolean类型的属性:test
--choose是when和otherwise的父标签,when在otherwise之前使用
--在父标签choose中定义一个“全局” 的boolean类型的flag:用于判断子标签在满足条件的情况下是否执行
*若when的test为true,且when的父标签的flag也为true,则执行when的标签体(正常输出标签体的内容),
同时把flag设置为flase
*若when的test为true,且when的父标签的flag为flase,则不执行标签体。
*若flag为true,otherwise执行。