自定义标签:
步骤:
1 2 3 | 标签处理类(标签也是一个对象,那么就需要先有类!) tld文件,它是一个xml 页面中使用<%@taglib%>来指定t1d文件的位置 |
标签类:
标签接口:
public interface SimpleTag
extends JspTag
每次执行标签都会调用这个方法(Tomcat调用):
public void doTag() throws JspException,java.io.IOException
设置父标签:
public void setParent(JspTag parent)
返回父标签(非生命周期方法):
public JspTag getParent()
设置JSP上下文对象(子类是PageContext):
public void setJspContext(JspContext pc)
设置标签体:
public void setJspBody(JspFragment jspBody)
自定义的标签类
package tag;
import java.io.IOException;
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;
/**
* 自定义标签 1
* @author CDU_LM
*
*/
public class MyTag1 implements SimpleTag {
private PageContext pageContext;
private JspFragment body;
/**
* 所有setXxx()方法都会在doTag()方法之前被Tomcat调用!
* 所以在doTag()方法中就可以使用Tomcat传递过来的对象。
*/
@Override
public void doTag() throws JspException, IOException {
// 使用一个顶九个的PageContext对象获取out来输出内容
pageContext.getOut().print("Hello!MyTag1!!!");
}
@Override
public JspTag getParent() {
return null;
}
@Override
public void setJspBody(JspFragment jspBody) {
// 接收标签体
this.body = jspBody;
}
@Override
public void setJspContext(JspContext context) {
// 接收PageContext对象
this.pageContext = (PageContext) context;
}
@Override
public void setParent(JspTag parent) {
}
}
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>tag1</short-name> <!-- 前缀 -->
<uri>http://www.cdml.cn/tag/tag-1.0</uri> <!-- 地址 -->
<tag>
<name>MyTag1</name><!-- 自定义当前标签名称 -->
<tag-class>tag.MyTag1</tag-class> <!-- 自定义的标签位置 -->
<body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
</taglib>
jsp测试:
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="/WEB-INF/tld/tag1.tld" prefix="t1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>title</title>
</head>
<body>
<h1><t1:MyTag1/></h1>
</body>
</html>
访问结果:
下面还有一个实现了SimpleTag接口的标签支持类SimpleTagSupport:
SimpleTagSupport:
这个类实现了SimpleTag接口,将所有Tomcat传递的参数都保存起来了,并提供了get方法供子类获取参数。
package tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MyTag2 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
// 获取标签体
this.getJspBody();
// 获取PageContext对象
this.getJspContext().getOut().pring("Hello!2222222");
// 获取父标签
this.getParent();
}
}
向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">
<tlib-version>1.0</tlib-version> <!-- 版本 -->
<short-name>tag1</short-name> <!-- 前缀 -->
<uri>http://www.cdml.cn/tag/tag-1.0</uri> <!-- 地址 -->
<tag>
<name>MyTag1</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag1</tag-class> <!-- 自定义的标签位置 -->
<body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
<tag>
<name>MyTag2</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag2</tag-class> <!-- 自定义的标签位置 -->
<body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
</taglib>
访问结果:
所以一个tld文件可以配置多个标签类。
标签体配置:
1 2 3 4 5 6 7 | empty:无标签体 JSP:传统标签支持它,从JSP2. 0 后不再支持,已经不再支持使用<body-content>Jsp</body-content>。标签体内可以是任何东西:EL、JSTL、<%=%>、<%%>,以及html; scriptless.:标签体内不能是Java脚本,但可以是EL、JSTL等。在simpleTag.中,如果需要有标签体,那么就使用该选项; tagdependent:标签练内容不做运算﹐由标签处理类自行处理,无论标签体内容是EL、JSP、JSTL,都不会做运算。这个选项几乎没有人会使用! |
简单的说就是无标签体用 empty,有标签体用 scriptless 。
创建类:
package tag;
import java.io.IOException;
import java.io.Writer;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MyTag3 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
Writer write = this.getJspContext().getOut(); // 获取当前jsp页面的输出流
write.write("********************<br/>");
this.getJspBody().invoke(write); // 执行标签体内容,把结果写到指定的流中,即页面中。
write.write("<br/>********************");
}
}
配置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">
<tlib-version>1.0</tlib-version> <!-- 版本 -->
<short-name>tag</short-name> <!-- 前缀 -->
<uri>http://www.cdml.cn/tag/tag-1.0</uri> <!-- 地址 -->
<tag>
<name>MyTag1</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag1</tag-class> <!-- 自定义的标签位置 -->
<body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
<tag>
<name>MyTag2</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag2</tag-class> <!-- 自定义的标签位置 -->
<body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
<tag>
<name>MyTag3</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag3</tag-class> <!-- 自定义的标签位置 -->
<body-content>scriptless</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
</taglib>
jsp测试:
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="/WEB-INF/tld/tag.tld" prefix="t1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>title</title>
</head>
<body>
<%
request.setAttribute("req", "这是张三娃娃");
%>
<t1:MyTag3>
${req}
</t1:MyTag3>
</body>
</html>
访问结果:
不在执行标签下面内容的标签:
1 2 | 在标签处理类中的doTag()中使用skipPageException来结束! Tomcat会调用标签处理类的doTag()方法,然后Tomcat会得到skipPageException,它会跳过本页面其他内容! |
创建自定义标签类:
package tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MyTag4 extends SimpleTagSupport{
@Override
public void doTag() throws JspException, IOException {
this.getJspContext().getOut().print("只能看到我这里了,下面的内容看不见了!!");
throw new SkipPageException(); // 抛出这个异常后,标签后面的内容将不可见!
}
}
配置tld文件:
加入MyTag4标签之前的访问页面:
加入MyTag4标签后的访问页面:
查看内容不显示的原因:
打开编译后的jsp文件tag1_jsp.class:
这里会定义一些变量,就是在jsp或类中需要用到的变量;
向下滑到使用MyTag4标签的位置:
发现这里是一个判断句,if中有一个函数_jspx_meth_t1_005fMyTag4_005f0,下面查看这个函数:
方法最后返回的是false,所以不会执行if中的return; 也就是说正常情况下if判断失败会继续向下执行,从而显示下面的jsp页面内容,但是这里执行doTag()方法时,执行的是类MyTag4中的doTag()方法:
这个方法抛出了一个异常,那么在函数_jspx_meth_t1_005fMyTag4_005f0执行doTag()方法的时候就会跟着向上级抛出MyTag4中的异常,也就是SkipPageException
当他向外抛出这个异常的时候,再看if所处的范围是在try语句中:
那么它抛出的SkipPageException就会被捕获,然后执行对应的catch语句:
在这之后,它执行的内容或者步骤是什么都不重要了,此时需要关注的就是:
1 2 3 4 5 6 7 | if 语句中的函数抛出了异常,异常抛到了此时的 try 语句中 异常被捕获,代码执行跳转到 catch 语句中 结果就是 if 后面的语句都被跳过了 而 finally 语句块中只是执行释放PageContext对象,而没有其它内容 |
所以这就是访问jsp页面后在标签MyTag4后面的内容全部都不会显示的原因。
带有属性的自定义标签
创建一个自定义标签类,类中创建属性,该属性必须由set()方法,该set()方法是由Tomcat在doTag()方法之前进行调用,所以set()方法中将属性任意设置都可以在doTag()方法中使用:
自定义标签类:
package tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class MyTag5 extends SimpleTagSupport {
private boolean test;
@Override
public void doTag() throws JspException, IOException {
if (test) { // test为true才执行标签体
// 执行标签体
this.getJspBody().invoke(null); // 输出传递null,默认使用的是当前页面的out
}
}
/**
* 这个方法是Tomcat调用,在doTag()方法之前调用
*
* @param test
* @throws IOException
* @throws JspException
*/
public void setTest(boolean test) throws JspException, IOException {
this.test = test;
}
}
在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">
<tlib-version>1.0</tlib-version> <!-- 版本 -->
<short-name>tag</short-name> <!-- 前缀 -->
<uri>http://www.cdml.cn/tag/tag-1.0</uri> <!-- 地址 -->
<tag>
<name>MyTag1</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag1</tag-class> <!-- 自定义的标签位置 -->
<body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
<tag>
<name>MyTag2</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag2</tag-class> <!-- 自定义的标签位置 -->
<body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
<tag>
<name>MyTag3</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag3</tag-class> <!-- 自定义的标签位置 -->
<body-content>scriptless</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
<tag>
<name>MyTag4</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag4</tag-class> <!-- 自定义的标签位置 -->
<body-content>empty</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
</tag>
<tag>
<name>MyTag5</name><!-- 自定义当前标签名称,jsp页面调用的名称 -->
<tag-class>tag.MyTag5</tag-class> <!-- 自定义的标签位置 -->
<body-content>script</body-content> <!-- 指定标签体内容,此处使用的是空标签,类似HTML中的<br/> -->
<attribute><!-- 配置属性标签 -->
<name>test</name><!-- 属性名称 -->
<required>true</required><!-- 该属性是否为必需,是则为true,否为false -->
<rtexprvalue>true</rtexprvalue><!-- 属性值是否为EL表达式,是为true,否为false -->
</attribute>
</tag>
</taglib>
jsp页面代码:
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="/WEB-INF/tld/tag.tld" prefix="t1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>title</title>
</head>
<body>
<t1:MyTag5 test="${empty param.xxx }">
<h1>
<t1:MyTag4 />
</h1>
</t1:MyTag5>
<%
request.setAttribute("req", "这是张三娃娃");
%>
<h1>
<t1:MyTag1 />
</h1>
<h1>
<t1:MyTag2 />
</h1>
<t1:MyTag3>
${req}
</t1:MyTag3>
</body>
</html>
当进行无参访问时:
当进行有参访问时:
那么带有属性的标签就自定义成功了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)