JSTL简单标签开发(进阶)
一、简单标签(SimpleTag)的概述
- 由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广, SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。
二、SimpleTag接口中涉及到的类的介绍
1)SimpleTag接口:
2.1.1
setJspContext方法:
用于把JSP页面的pageContext对象传递给标签处理器对象
setJspBody方法:
用于把代表标签体的JspFragment对象传递给标签处理器对象
doTag方法(非常重要):
简单标签使用这个方法就可以完成所有的业务逻辑,用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等
setParent和getParent方法:
用于把父标签处理器对象传递给当前标签处理器对象,用于获得当前标签的父标签处理器对象
2.1.2、
当web容器开始执行标签时,会调用如下方法完成标签的初始化:
- WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。
- WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法。
- 如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象。
- 如果简单标签有标签体,WEB容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。
- 执行标签时WEB容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。
2)SimpleTagSupport类
2.2.1、
- SUN公司针对SimpleTag接口提供了一个默认的实现类SimpleTagSupport,SimpleTagSupport类中实现了SimpleTag接口的所有方法,因此我们可以编写一个类继承SimpleTagSupport类,然后根据业务需要再重写doTag方法。
3)JspFragment类
2.3.1、
- WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象
2.3.2、
- JspFragment类有两个方法:
- getJspContext方法: 用于返回代表调用页面的JspContext对象.但是我们通常不这样做。习惯使用 this.getJspContext() 直接获得JspContext对象
- invoke方法(重要): 利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:
(1) 在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;
(2)在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;
(3)若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。
2.3.3、
开发带属性的标签:
- 自定义标签可以定义一个或多个属性,这样,在JSP页面中应用自定义标签时就可以设置这些属性的值,通过这些属性为标签处理器传递参数信息,从而提高标签的灵活性和复用性。
- 要想让一个自定义标签具有属性,通常需要完成两个任务:
(1)在标签处理器中编写每个属性对应的setter方法(get、set方法)
(2)在TLD文件中描术标签的属性(< attribute >< /attribute >) - 为自定义标签定义属性时,每个属性都必须按照JavaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收 JSP页面调用自定义标签时传递进来的属性值。 例如属性url,在标签处理器类中就要定义相应的setUrl(String url)方法。
- 在标签处理器中定义相应的set方法后,JSP引擎在解析执行开始标签前,也就是调用doStartTag方法前,会调用set属性方法,为标签设置属性。
三、简单标签实现页面逻辑
3.1、控制jsp页面标签体内容是否执行
- 编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法里面不调用jspFrament.invoke方法即可
- MyTagdemo1.java
public class MyTagdemo1 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
//第一种:
//this.getJspBody().invoke(this.getJspContext().getOut());
//第二种---->拆分解释:
JspContext context = this.getJspContext();// 获取PageContext对象
JspWriter out = context.getOut(); //获取向JSP页面输出信息的流对象
JspFragment jf = this.getJspBody();//获取标签体内容
jf.invoke(out);//将标签体内容输出到页面上
//第三种
//this.getJspBody().invoke(null);
}
}
- 在WEB-INF(安全)目录下新建一个mytag.tld文件,然后在mytag.tld文件中添加对该标签处理类的描述,如下:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" 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">
<!--taglib(标签库)的版本号 -->
<tlib-version>1.0</tlib-version>
<!- 标签的前缀 -->
<short-name>my</short-name>
<!-- 为自定义标签库设置一个uri,uri以/开头,/后面的内容随便写,如这里的/Simpletag , 在Jsp页面中引用标签库时,需要通过uri找到标签库 , 在Jsp页面中就要这样引入标签库:<%@ taglib prefix="my" uri="http://www.syj.cn/SimpleTag"%> -->
<uri>http://www.syj.cn/SimpleTag</uri>
<!--一个taglib(标签库)中包含多个自定义标签,每一个自定义标签使用一个tag标记来描述 -->
<!-- 一个tag标记对应一个自定义标签 -->
<tag>
<!-- 对标签的描述 -->
<description>SimpleTag(简单标签)Demo1</description>
<!-- 为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的 通过demo1就能找到对应的cn.syj.Tag.SimpleTag.MyTagdemo1类 -->
<name>demo1</name>
<!-- 标签对应的处理器类-->
<tag-class>cn.syj.Tag.SimpleTag.MyTagdemo1</tag-class>
<!--
tld文件中有四种标签体类型 :empty JSP scriptless tagdepentend
在简单标签(SampleTag)中标签体body-content的值只允许是empty和scriptless,不允许设置成JSP,如果设置成JSP就会出现异常
在传统标签中标签体body-content的值只允许是empty和JSP
如果标签体body-content的值设置成tagdepentend,那么就表示标签体里面的内容是给标签处理器类使用的 -->
<body-content>scriptless</body-content>
</tag>
- 在jsp页面中导入并使用自定义标签,如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="my" uri="http://www.syj.cn/SimpleTag"%>
<!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>标签体内容是否执行</title>
</head>
<body>
<h1>标签体内容是否执行</h1>
<my:demo1>
我是demo1:决定标签题内容是否执行
</my:demo1>
</body>
</html>
- 运行结果展示:
3.2、标签体后的内容是否被执行
- 编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法抛出SkipPageException异常即可,jsp收到这个异常,将忽略标签余下jsp页面的执行。
- MyTagdemo2.java
//决定标签后面的内容是否被执行
public class MyTagdemo2 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
this.getJspBody().invoke(null);
throw new SkipPageException();
}
}
在WEB-INF目录下的mytag.tld文件中添加对该标签处理类的描述,如下:
<!-- 标签名 -->
<name>demo2</name>
<!-- 标签处理器类-->
<tag-class>cn.syj.Tag.SimpleTag.MyTagdemo2</tag-class>
<!-- 标签体允许的内容 ,scriptless表示标签体的内容不允许是java脚本代码-->
<body-content>scriptless</body-content>
- 在jsp页面中导入并使用自定义标签,如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="my" uri="http://www.syj.cn/SimpleTag"%>
<!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>标签体后的内容是否被执行</title>
</head>
<body>
<h1>标签体后的内容是否被执行</h1>
<my:demo2>
demo2 content
</my:demo2>
demo2 after
</body>
</html>
- 运行结果:
3.3、jsp页面标签的内容重复执行
- 编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法里面重复调用jspFrament.invoke方法。
- MyTagdemo3.java
//决定标签的内容重复执行
/**
* 步骤:
* 1、获得标签体内容
* 2、将标签体的内容重复输出
*/
public class MyTagdemo3 extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
/*// 方法一、
// 1、获得标签体的内容
StringWriter sw = new StringWriter();
// 1.1、将标签体的内容写到sw流中
this.getJspBody().invoke(sw);
// 1.2、获得缓冲区中的内容转化为字符串
String msg = sw.getBuffer().toString();
// 1.3、获得输出流对象JspWrite的out
JspWriter out = this.getJspContext().getOut();
// 2、将标签体的内容重复输出
for (int i = 0; i < 3; i++) {
out.write(msg);
}
*/
// 方法二、
JspFragment jb = this.getJspBody();
for (int i = 0; i < 4; i++) {
jb.invoke(null);
}
}
}
在WEB-INF目录下的mytag.tld文件中添加对该标签处理类的描述,如下:
<tag>
<!-- 标签名 -->
<name>demo3</name>
<!-- 标签处理器类-->
<tag-class>cn.syj.Tag.SimpleTag.MyTagdemo3</tag-class>
<!-- 标签体允许的内容 ,scriptless表示标签体的内容不允许是java脚本代码-->
<body-content>scriptless</body-content>
</tag>
- 在jsp页面中导入并使用自定义标签,如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="my" uri="http://www.syj.cn/SimpleTag"%>
<!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>标签体中的内容重复输出</title>
</head>
<body>
<h1>标签体中的内容重复输出</h1>
<my:demo3>
追梦逐星<br>
</my:demo3>
</body>
</html>
- 运行结果:
3.4、修改标签体中的内容(参数决定次数.字体为红色)
- 步骤:
1)在标签处理器中编写每个属性对应的setter方法
2)在TLD文件中描术标签的属性
解释:
1)为自定义标签定义属性时,每个属性都必须按照JavaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收 JSP页面调用自定义标签时传递进来的属性值。 例如属性url,在标签处理器类中就要定义相应的setUrl(String url)方法。
2)在标签处理器中定义相应的set方法后,JSP引擎在解析执行开始标签前,也就是调用doStartTag方法前,会调用set属性方法,为标签设置属性。 - 在自定义的类(MyTagdemo3_change)中声明一个变量time。在tld文件中设置对应的参数属性,time将作为参数传递给MyTagdemo3_change类。
- MyTagdemo3_change.java
//修改标签体的内容
/**
* 步骤: 1、获得标签体内容 2、将标签体的内容进行修改 3、进行输出
*/
public class MyTagdemo3_change extends SimpleTagSupport {
private int time;
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
@Override
public void doTag() throws JspException, IOException {
// 方法一、
// 1、获得标签体的内容
StringWriter sw = new StringWriter();
// 1.1、将标签体的内容写到sw流中
this.getJspBody().invoke(sw);
// 1.2、获得缓冲区中的内容转化为字符串
// 1.2.1将标签体的字符串转化为大写,并以红色字体输出
String msg = sw.getBuffer().toString().toUpperCase();
msg = "<font color='red'>" + msg + "</font>";
// 1.3、获得输出流对象JspWrite的out
JspWriter out = this.getJspContext().getOut();
// 2、将标签体的内容重复输出
for (int i = 0; i < time; i++) {
out.write(msg);
}
}
}
- 在WEB-INF目录下的mytag.tld文件中添加对该标签处理类的描述,如下:
<tag>
<!-- 标签名 -->
<name>demo3_change</name>
<!-- 标签处理器类-->
<tag-class>cn.syj.Tag.SimpleTag.MyTagdemo3_change</tag-class>
<!-- 标签体允许的内容 ,scriptless表示标签体的内容不允许是java脚本代码-->
<body-content>scriptless</body-content>
<-- 参数描述 -->
<attribute>
<-- 参数名称描述(和自定义类中的成员属性保持一致) -->
<name>time</name>
<-- 该参数是否必须(必须会随着标签一起带出来) -->
<required>true</required>
<-- 该参数是否支持EL表达式 -->
<rtexprvalue>true</rtexprvalue>
<-- 该参数类型描述 -->
<type>int</type>
</attribute>
</tag>
在jsp页面中导入并使用自定义标签,如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="my" uri="http://www.syj.cn/SimpleTag"%>
<!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>将标签体中的字符串转化为大写并以红色字体输出</title>
</head>
<body>
<h1>将标签体中的字符串转化为大写并以红色字体输出</h1>
<my:demo3_change time="8">
zhimengzhuxing<br>
</my:demo3_change>
</body>
</html>
运行结果展示:
元素的子元素说明:
四、模仿核心标签库的开发
4.1、开发html转义标签
- MyTag_test1.java
//转义函数(filter(String message))可以参考:Tomcat9.0\apache-tomcat-9.0.13\webapps\examples\WEB-INF\classes\util下的HTMLFilter.java文件
public class MyTag_test1 extends SimpleTagSupport {
//转义函数可以参考Tomcat9.0\apache-tomcat-9.0.13\webapps\examples\WEB-INF\classes\util下的HTMLFilter.java文件
public static String filter(String message) {
if (message == null)
return null;
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuilder result = new StringBuilder(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return result.toString();
}
@Override
public void doTag() throws JspException, IOException {
//1.1将标签体内容写入到sw中
StringWriter sw = new StringWriter();
this.getJspBody().invoke(sw);
//1.2取出标签体的内容
String content = sw.getBuffer().toString();
//2.1将标签体的内容进行转义
content = filter(content);
this.getJspContext().getOut().write(content);
}
}
在WEB-INF下创建MtTagTest.tld文件,并添加代码段:
<tag>
<name>html</name>
<tag-class>cn.syj.Tag.SimpleTagTest.MyTag_test1</tag-class>
<body-content>scriptless</body-content>
</tag>
test1_html.jsp代码如下:
<!--不能忘记导入-->
<%@ taglib prefix="de" uri="http://www.syj.cn/Test"%>
<title>html转义标签</title>
</head>
<body>
<de:html>
<font color="red">追梦逐星</font>
</de:html>
</body>
</html>
运行结果:
4.2、截取字符串
- MyTag_test2.java
//截取字符串
public class MyTag_test2 extends SimpleTagSupport {
private int begin;
private int end;
public void setBegin(int begin) {
this.begin = begin;
}
public void setEnd(int end) {
this.end = end;
}
@Override
public void doTag() throws JspException, IOException {
// 1.1将标签体内容写入到sw中
StringWriter sw = new StringWriter();
this.getJspBody().invoke(sw);
// 1.2取出标签体的内容
String content = sw.getBuffer().toString().trim();
// 2.1将标签体的内容进行截取
content = content.substring(begin, end);
// 2.2将截取后的字符进行输出
this.getJspContext().getOut().write(content);
}
}
- 在WEB-INF下的MtTagTest.tld文件中,添加代码段:
<tag>
<name>substring</name>
<tag-class>cn.syj.Tag.SimpleTagTest.MyTag_test2</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>begin</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>int</type>
</attribute>
<attribute>
<name>end</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>int</type>
</attribute>
</tag>
- 运行结果:
4.3、模仿< c:when >< c:otherwise >标签
- <c:when>标签和<c:otherwise>标签对应着两个不同的标签处理器类,我们希望做到的效果是,如果<c:when>标签执行了,那么就<c:otherwise>标签就不要再执行,那么这里面就涉及到一个问题:<c:when>标签执行的时候该如何通知<c:otherwise>标签不要执行了呢?这个问题就涉及到了两个标签处理器类如何做到相互通讯的问题,如果<c:when>标签执行了,就要通过某种方式告诉<c:otherwise>标签不要执行,那么该如何做到这样的效果呢?让<c:when>标签处理器类和<c:otherwise>标签处理器类共享同一个变量就可以做到了,那么又该怎么做才能够让两个标签处理器类共享同一个变量呢,标准的做法是这样的:让两个标签拥有同一个父标签。
- 开发父标签:
MyTag_choose.java
//开发choose标签
public class MyTag_choose extends SimpleTagSupport {
//
private Boolean isExecute = false;
public Boolean getIsExecute() {
return isExecute;
}
public void setIsExecute(Boolean isExecute) {
this.isExecute = isExecute;
}
@Override
public void doTag() throws JspException, IOException {
this.getJspBody().invoke(null);
}
}
- 开发when标签和otherwise标签
MyTag_when.java
//开发choose标签
public class MyTag_when extends SimpleTagSupport {
private Boolean test;
public void setTest(Boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
MyTag_choose choose = (MyTag_choose) this.getParent();
if (choose.getIsExecute() == false && test==true) {
this.getJspBody().invoke(null);
//告诉父标签我已经执行过了
choose.setIsExecute(true);
}
}
}
MyTag_OtherWise.java
//开发OtherWise标签
public class MyTag_OtherWise extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
MyTag_choose choose = (MyTag_choose) this.getParent();
if (choose.getIsExecute() == false ) {
this.getJspBody().invoke(null);
//告诉父标签我已经执行过了
choose.setIsExecute(true);
}
//否则什么也不执行
}
}
- 在WEB-INF下的MtTagTest.tld文件中,添加代码段:
<tag>
<description>choose标签</description>
<name>choose</name>
<tag-class>cn.syj.Tag.SimpleTagTest.MyTag_choose</tag-class>
<body-content>scriptless</body-content>
</tag>
<tag>
<description>when标签</description>
<name>when</name>
<tag-class>cn.syj.Tag.SimpleTagTest.MyTag_when</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>Boolean</type>
</attribute>
</tag>
<tag>
<description>otherwise标签</description>
<name>otherwise</name>
<tag-class>cn.syj.Tag.SimpleTagTest.MyTag_OtherWise</tag-class>
<body-content>scriptless</body-content>
</tag>
test3_choose_when_otherwise.jsp代码:
<%@ taglib prefix="de" uri="http://www.syj.cn/Test"%>
<title>模仿choose_when_otherwise</title>
</head>
<body>
<h1>when标签的输出</h1>
<de:choose>
<de:when test="true">
登陆成功
</de:when>
<de:otherwise>
账号或者密码错误
</de:otherwise>
</de:choose>
<h1>otherwise标签的输出</h1>
<de:choose>
<de:when test="false">
登陆成功
</de:when>
<de:otherwise>
账号或者密码错误
</de:otherwise>
</de:choose>
</body>
</html>
- ** 运行结果展示:**
4.4、模仿< c:if >标签
- 编写标签处理器类:MyTag_if.java
//模仿c:if
public class MyTag_if extends SimpleTagSupport {
private Boolean test;
public void setTest(Boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
// 获得标签体的内容
StringWriter sw = new StringWriter();
this.getJspBody().invoke(sw);
String content = sw.getBuffer().toString();
if (test) {
this.getJspContext().getOut().write(content);
}
}
}
- 在WEB-INF目录下tld文件中添加对该标签的描述,如下:
<tag>
<name>if</name>
<tag-class>cn.syj.Tag.SimpleTagTest.MyTag_if</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>Boolean</type>
</attribute>
</tag>
- 测试:在jsp页面中导入标签库并使用if标签:
<%@ taglib prefix="de" uri="http://www.syj.cn/Test"%>
<title>模仿c:if</title>
</head>
<body>
<h1>test为true</h1>
<de:if test="true">
追梦逐星<br>
</de:if>
<h1>test为false</h1>
<de:if test="false">
不输出任何内容<br>
</de:if>
</body>
</html>
- 运行结果:
4.5、模仿< c:foreach >迭代标签
- 编写标签处理器类:
//开发forEach标签
public class MyTag_forEach extends SimpleTagSupport {
// 用来存储集合
private List items;
// 用来存放变量
private String var;
public List getItems() {
return items;
}
public void setItems(List items) {
this.items = items;
}
public String getVar() {
return var;
}
public void setVar(String var) {
this.var = var;
}
@Override
public void doTag() throws JspException, IOException {
PageContext pageContent = (PageContext) this.getJspContext();
Iterator it = items.iterator();
while (it.hasNext()) {
Object next = it.next();
pageContent.setAttribute(var, next);
this.getJspBody().invoke(null);
}
}
}
- 在WEB-INF目录下tld文件中添加对该标签的描述·,如下:
<tag>
<name>forEach</name>
<tag-class>cn.syj.Tag.SimpleTagTest.MyTag_forEach</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>items</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>String</type>
</attribute>
<attribute>
<name>var</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>String</type>
</attribute>
</tag>
- 测试:在jsp页面中导入标签库并使用forEach标签
<%@ taglib prefix="de" uri="http://www.syj.cn/Test"%>
<title>模仿c:forEach</title>
</head>
<body>
<%
List<String> list = new ArrayList<>();
list.add("追梦逐星");
list.add("zhuimengzhuxing");
pageContext.setAttribute("list", list);
%>
<de:forEach var="li" items="${list}">
${li }<br>
</de:forEach>
</body>
</html>
- 运行结果:
4.6、模仿< c:out >输出标签
- 编写标签处理器类:MyTag_out.java
public static String filter(String message) 函数参考:在D:\Tomcat9.0\apache-tomcat-9.0.13\webapps\examples\WEB-INF\classes\util\HTMLFilter.java
//开发forEach标签
public class MyTag_out extends SimpleTagSupport {
private Boolean escapeHtml;
public Boolean getEscapeHtml() {
return escapeHtml;
}
public void setEscapeHtml(Boolean escapeHtml) {
this.escapeHtml = escapeHtml;
}
@Override
public void doTag() throws JspException, IOException {
// 获得标签体的内容
StringWriter sw = new StringWriter();
this.getJspBody().invoke(sw);
String content = sw.getBuffer().toString();
JspWriter out = this.getJspContext().getOut();
if (escapeHtml == true) {
//将标签体的内容进行转义
content = filter(content);
out.write(content);
} else {
out.write(content);
}
}
public static String filter(String message) {
if (message == null)
return null;
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuilder result = new StringBuilder(content.length + 50);
for (int i = 0; i < content.length; i++) {
switch (content[i]) {
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(content[i]);
}
}
return result.toString();
}
}
- 在WEB-INF目录下tld文件中添加对该标签的描述,如下:
<tag>
<description>out标签</description>
<name>out</name>
<tag-class>cn.syj.Tag.SimpleTagTest.MyTag_out</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>escapeHtml</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>Boolean</type>
</attribute>
</tag>
- 测试:在jsp页面中导入标签库并使用out标签:
<%@ taglib prefix="de" uri="http://www.syj.cn/Test"%>
<title>模仿c:out</title>
</head>
<body>
<h1>html不进行解析</h1>
<de:out escapeHtml="true">
<a href="https://blog.csdn.net/SYJ_1835_NGE">点击转跳到MyCSDN</a>
</de:out>
<h1>解析html</h1>
<de:out escapeHtml="false">
<a href="https://blog.csdn.net/SYJ_1835_NGE">点击转跳到MyCSDN</a>
</de:out>
</body>
- 运行结果:
五、自定义标签的执行流程
流程:
-
1.JSP 容器通过调用其无参构造器,创建一个简单标签处理器实例。因此,简单的标签处理器必须有一个无参构造器。
-
2.JSP 容器调用setJspContext 方法(一定调用), 同时传递一个JspContext 对象。JspContext 最重要的方法是getOut,它返回一个JspWriter,用于将响应发送到客户端。setJspContext方法的签名如下:
public void setJspContext(JspContext jspContext}大多数时候,会需要将传进的JspContext 赋给一个类变量,以便供后续使用。 -
3.如果表示标签处理器的定制标签是嵌套在另一个标签中的, JSP 容器就会调用setParen方法。该方法具有如下签名:public void setParent(JspTag parent)
-
4.JSP 容器为给该标签定义的每个属性都调用设置方法( Setter )。
-
5 . 如果标签中有主体内容, JSP 将调用SimpleTag 接口的setJspBody 方法,将主体内容作为JspFragment 传递。如果没有主体内容, JSP 容器则不会调用这个方法。
-
6.JSP 容器调用doTag 方法(一定调用)。所有变量在doTag 方法返回时进行同步。
我们在tomcat服务器的"work\Catalina\localhost\JavaWeb_JspTag_study_20140816\org\apache\jsp"目录下可以找到将自定义的jsp翻译成Servlet后的java源代码,如下图所示:
六、打包开发好的标签库
将标签库作为一个jar包,像JSTL一样,在以后的工程中复用该标签库。
步骤:
- 1.创建一个java工程(利用java工程的自动导出功能,打包成jar包)
- 2.在java工程下面创建一个META-INF目录,将编写好的tld文件复制到该目录下
- 3.将编写好的标签类复制到java的src下(此时因为类中大都含有javaee的类,所以需要导入javaee的jar包)。右键工程属性—>Build Path—>Add Liberaries…—>添加Myeclipse Liberary(添加任意一个javaee包)
- 4.右键工程export 选项 导出jar file
七、补充
- 1)开发简单标签类时注意事项:,不要直接去实现SimpleTag接口,而是应该继承SimpleTagSupport类,SimpleTagSupport类是SimpleTag接口的一个默认实现类,通过继承SimpleTagSupport类,就可以直接使用SimpleTagSupport类已经实现的那些方法,如果SimpleTagSupport类的方法实现不满足业务要求,那么就可以根据具体的业务情况将相应的方法进行重写。
- 2)简单标签标签体的细节注意问题:
在简单标签(SampleTag)中标签体body-content中: 值只允许是empty、scriptless,不允许设置成JSP,如果设置成JSP就会出现异常。 - 3)传统标签标签体的细节注意问题
在传统标签中标签体body-content的值允许是empty、JSP、scriptless、tagdependent,body-content的值如果是设置成JSP,那么表示该标签是有标签体的,并且标签体的内容可以是任意的,包括java代码,如果是设置成scriptless,那么表示该标签是有标签体的,但是标签体的内容不能是java代码 - 4)库名不同但是uri相同解决办法:
如果在一个项目中使用或者开发了多个标签库,库名不一样但是uri设置的是一样的,通过uri引用标签库时就不知道引用哪一个标签库了,为了能够在jsp中区别到底引用的是哪个标签库,可以换一种引用方式:<%@taglib uri=“要引用的标签库的tld文件目录” prefix=“short name”%>,使用taglib指令引入标签库时,taglib指令的uri属性指定为标签库的tld文件目录,这样就可以区别开了, - 5)配置标签中的参数元素的子元素说明: