什么是自定义标签?
用户定义的一种自定义的jsp标记。当一个含有自定义标签的jsp页面被jsp引擎编译成servlet时, tag标签被转化成了对一个称为标签处理类的对象的操作。于是,当jsp页面被jsp引擎转化为servlet后,实际上tag标签被转化为了对tag处理类的操作。
传统标签和简单标签
- 开发自定义标签,其核心就是要编写处理器类,一个标签对应-一个标签处理器类,而一个标签库则是很多标签处理器的集合。所有的标签处理器类都要实现JspTag接口,该接口中没有定义任何方法,主要作为Tag和SimpleTag接口的父接口。
- 在JSP2.0以前,所有标签处理器类都必须实现Tag接口,这样的标签称为传统标签。
- JSP 2.0规范又定义了一种新的类型的标签,称为简单标签,其对应的处理器类要实现 SimpleTag 接口
自定义标签的开发与应用步骤
- 编写完成标签功能的Java类(标签处理器)
- 编写标签库描述(tld)文件,在tld文件中对自定义中进行描述
- 在JSP页面中导入和使用自定义标签
范例
1. 实现标签 -athome:hello value=“athome” count=“10”-(打印 value 值 count 次)
java 类
public class SimpleTag implements javax.servlet.jsp.tagext.SimpleTag {
//定义变量
private String value;
private String count;
public void setValue(String value) {
this.value = value;
}
private void setcount(String count) {
this.count = count;
}
@Override
public void doTag() throws JspException, IOException {
//得到打印次数
int countValue = Integer.parseInt(count);
//得到 out 隐含变量
JspWriter out = context.getOut();
//循环打印
for (int i = 0; i < countValue; i++) {
out.println((i+1) + "," + value);
out.println("<br>");
}
}
@Override
public JspTag getParent() {
System.out.println("getParent");
return null;
}
@Override
public void setJspBody(JspFragment arg0) {
System.out.println("setJspBody");
}
private PageContext context = null;
@Override
public void setJspContext(JspContext arg0) {
System.out.println(arg0 instanceof PageContext);
context = (PageContext) arg0;
System.out.println("setJspContext");
}
@Override
public void setParent(JspTag arg0) {
System.out.println("setParent");
}
}
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</description>
<display-name>myTag core</display-name>
<tlib-version>1.0</tlib-version>
<!-- 建议使用标签的前缀 -->
<short-name>athome</short-name>
<!-- 作为tid 文件的id,用来唯一标识当前的 tld 文件,多个tld 文件的uri 不能重复,通过 jsp 中的tablib 标签的 uri 来引用 -->
<uri>http://www.athome.com/myTag/core</uri>
<!-- 描述自定义的 helloJXK 标签 -->
<tag>
<!-- 标签名字:在jsp 中使用的标签的名字 -->
<name>hello</name>
<!-- 标签所在的全类名 -->
<tag-class>athome.simpletag.SimpleTag</tag-class>
<!-- 标签类型 -->
<body-content>empty</body-content>
<!-- 参数 -->
<attribute>
<!-- 参数名 -->
<name>value</name>
<!-- 参数是否必须 -->
<required>true</required>
<!-- 参数是否可以接受运行时表达式的值 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>count</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
<taglib>
在 jsp 中
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 导入标签库 -->
<%@ taglib prefix="athome" uri="http://www.athome.com/myTag/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<athome:hello value="athome" count="10"/>
</body>
</html>
2. 实现标签 -athome:Max num1=" p a r a m . a " n u m 2 = " {param.a }" num2=" param.a"num2="{param.b }- (的都两个参数的最大值)
java 中
public class MaxTag extends SimpleTagSupport {
private String num1;
private String num2;
public void setNum1(String num1) {
this.num1 = num1;
}
public void setNum2(String num2) {
this.num2 = num2;
}
@Override
public void doTag() throws JspException, IOException {
//得到 pageContext
PageContext pageContext = (PageContext) getJspContext();
//得到两个参数的值
int a = Integer.parseInt(num1);
int b = Integer.parseInt(num2);
//得到 out 隐含变量
JspWriter out = pageContext.getOut();
//打印
out.println(a > b ? a : b);
}
}
tld 中(这儿只有说明的部分,全部内容参考上一个例子,下同)
<!-- 得到最大值 -->
<tag>
<name>Max</name>
<tag-class>athome.simpletag.MaxTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>num1</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>num2</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
jsp 中
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!-- 导入标签库 -->
<%@ taglib prefix="athome" uri="http://www.athome.com/myTag/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<athome:Max num1="${param.a }" num2="${param.b }"/>
</body>
</html>
3.(athome:printUpper time=“10”>come on 😒{param.name }</athome:printUpper) ----实现将标签体大写并打印time 次
java中
public class printUpper extends SimpleTagSupport {
private String time;
public void setTime(String time) {
this.time = time;
}
@Override
public void doTag() throws JspException, IOException {
//得到标签体
JspFragment bodyContent = getJspBody();
StringWriter sw = new StringWriter();
bodyContent.invoke(sw);
String content = sw.toString();
//变为大写
content = content.toUpperCase();
int count = 1;
//循环输出
try {
count = Integer.parseInt(time);
} catch (Exception e) {}
for (int i = 0; i < count; i++) {
getJspContext().getOut().println((i+1) + "," + content);
getJspContext().getOut().println("<br>"); }
}
}
tld 文件中:
<tag>
<name>printUpper</name>
<tag-class>athome.simpletag.printUpper</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>time</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
jsp 文件中(引用同上,省略,下同)
<athome:printUpper time="10">come on :${param.name }</athome:printUpper>
5模拟实现 foreach
java中
public class ForEachDemo extends SimpleTagSupport {
private Collection<?> items;
private String val;
public void setItems(Collection<?> collection) {
this.items = collection;
}
public void setVal(String val) {
this.val = val;
}
@Override
public void doTag() throws JspException, IOException {
// 遍历 collection
if (items != null) {
for (Object object : items) {
//将遍历到的对象放在 pageContext 中 ,键:var,值是遍历的对象
getJspContext().setAttribute(val, object);
//将标签内容直接输出到页面上
getJspBody().invoke(null);
}
}
}
}
tld中:
<tag>
<name>forEach</name>
<tag-class>athome.simpletag.ForEachDemo</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>val</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
jsp 中
<body>
<%
ArrayList<Customer> customers = new ArrayList<>();
customers.add(new Customer(1,"AAA",10));
customers.add(new Customer(2,"BBB",11));
customers.add(new Customer(3,"CCC",12));
customers.add(new Customer(4,"DDD",13));
customers.add(new Customer(5,"EEE",14));
request.setAttribute("customers", customers);
%>
<athome:forEach items="${requestScope.customers }" val="customer">
${customer.id }--${customer.name }--${customer.age}<br>
</athome:forEach>
</body>
6.父标签中有子标签的情况
例如:jstl 中的 c:choose
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:choose>
<c:when test="${param.age > 24 }">大学毕业</c:when>
<c:when test="${param.age > 20 }">高中毕业</c:when>
<c:otherwise>高中以下学历</c:otherwise>
</c:choose>
模拟实现:
java中
choose Java类:
public class ChooseTag extends SimpleTagSupport {
private boolean flag = true;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void doTag() throws JspException, IOException {
getJspBody().invoke(null );
}
}
when 类:
public class WhenTag extends SimpleTagSupport {
private boolean test;
public void setTest(boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
//若 test 且 parentFlag 都是真
if (test) {
//得到父标签
JspTag parent = getParent();
ChooseTag parentTag = (ChooseTag) parent;
//得到父节点的 flag
boolean parentFlag = parentTag.isFlag();
if (parentFlag) {
getJspBody().invoke(null);
parentTag.setFlag(false);
}
}
}
}
OtherWise类
public class OtherWise extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
//得到父标签
ChooseTag parent = (ChooseTag) getParent();
if (parent.isFlag()) {
getJspBody().invoke(null);
}
}
}
tld文件中
<!-- 模拟选择标签 -->
<tag>
<name>Choose</name>
<tag-class>athome.simpletag.ChooseTag</tag-class>
<body-content>scriptless</body-content>
</tag>
<tag>
<name>When</name>
<tag-class>athome.simpletag.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>athome.simpletag.OtherWise</tag-class>
<body-content>scriptless</body-content>
</tag>
jsp 中:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="athome" uri="http://www.athome.com/myTag/core"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 模拟的标签 -->
<athome:Choose>
<athome:When test="${param.age > 24 }">大学毕业</athome:When>
<athome:When test="${param.age > 20 }">高中毕业</athome:When>
<athome:OtherWise>高中以下学历</athome:OtherWise>
</athome:Choose>
<!-- jstl 中的 -->
<c:choose>
<c:when test="${param.age > 24 }">大学毕业</c:when>
<c:when test="${param.age > 20 }">高中毕业</c:when>
<c:otherwise>高中以下学历</c:otherwise>
</c:choose>
<br><br>
</body>
</html>
补充
这儿不能是脚本