Java Web基础入门第三十三讲 JSP技术——JSP简单标签开发

简单标签(SimpleTag)

由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广,SUN公司为降低标签技术的学习难度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。
在这里插入图片描述
实现SimpleTag接口的标签通常称为简单标签。简单标签共定义了5个方法:

  1. setJspContext方法;
  2. setParent和getParent方法;
  3. setJspBody方法;
  4. doTag方法(非常重要),简单标签使用这个方法就可以完成所有的业务逻辑

SimpleTag接口中的方法介绍

在这里插入图片描述

SimpleTag接口中方法的执行顺序

  • 当WEB容器开始执行标签时,会调用如下方法完成标签的初始化:

    1. WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象;
    2. WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法;
    3. 如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象;
    4. 如果简单标签有标签体,容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。
  • 执行标签时:

    1. 容器调用标签处理器的doTag()方法,开发人员在方法体内通过操作JspFragment对象,就可以实现是否执行、迭代、修改标签体的目的。

用UML时序图来表示简单标签的执行流程为:
在这里插入图片描述

面试题一:简单标签的生命周期?

答案可参照上图。

面试题二:简单标签和传统标签有什么区别?

传统标签执行完标签之后,对象不会摧毁,驻留在内存里面,为后续的请求服务;简单标签执行完标签之后,对象没有变量引用,就会成为JVM里面的垃圾,就由垃圾回收器负责回收掉,对象就会被摧毁。

JspFragment类介绍

javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的,它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段,这段JSP片段中不能包含JSP脚本元素。
WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象来表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象。JspFragment类中只定义了两个方法,如下所示。
在这里插入图片描述

invoke方法详解

JspFragment.invoke方法是JspFragment最重要的方法,利用这个方法可以控制是否执行和输出标签体的内容、是否迭代执行标签体的内容或对标签体的执行结果进行修改后再输出。例如:

  1. 在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;
  2. 在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;
  3. 若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。

开发简单标签实现页面逻辑

SUN公司针对SimpleTag接口提供了一个默认的实现类SimpleTagSupport,SimpleTagSupport类中实现了SimpleTag接口的所有方法,因此我们可以编写一个类继承SimpleTagSupport类,然后根据业务需要再重写doTag方法。

控制JSP页面某一部分内容是否执行

编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法里面不调用jspFrament.invoke方法即可。

package cn.liayun.web.simpletag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

//控制标签体是否执行
public class SimpleTagDemo1 extends SimpleTagSupport {

	@Override
	public void doTag() throws JspException, IOException {
		//控制标签体不执行,即得到标签体之后啥事都不干
		JspFragment jf = this.getJspBody();
//		jf.invoke(this.getJspContext().getOut());
	}
	
}

然后,在WEB-INF目录下新建一个simpleliayun.tld文件,然后在simpleliayun.tld文件中添加对该标签处理类的描述,如下:
在这里插入图片描述
simpleliayun.tld文件的内容如下:
在这里插入图片描述
最后,在jsp页面中导入并使用自定义标签,如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/simpletag" prefix="sliayun" %>
<!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>
	<sliayun:demo1>
		赵敏郡主,倚天屠龙记<br/>
	</sliayun:demo1>
</body>
</html>

控制整个JSP页面是否执行

编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法中抛出SkipPageException异常即可,JSP收到这个异常,将忽略标签余下JSP页面的执行。

package cn.liayun.web.simpletag;

import java.io.IOException;
import java.io.StringWriter;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

//控制标签余下的JSP不执行
public class SimpleTagDemo4 extends SimpleTagSupport {

	@Override
	public void doTag() throws JspException, IOException {
		throw new SkipPageException();
	}
	
}

然后,在WEB-INF目录下的simpleliayun.tld文件中添加对该标签处理类的描述,如下:
在这里插入图片描述
最后,在jsp页面中导入并使用自定义标签,如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/simpletag" prefix="sliayun" %>
<sliayun:demo4/>
<!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>用简单标签控制标签余下的JSP不执行</title>
</head>
<body>
	赵敏郡主,倚天屠龙记<br/>
</body>
</html>

控制JSP页面内容重复执行

编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法里面重复调用jspFrament.invoke方法即可。

package cn.liayun.web.simpletag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

//控制标签体是否执行
public class SimpleTagDemo2 extends SimpleTagSupport {

	@Override
	public void doTag() throws JspException, IOException {
		JspFragment jf = this.getJspBody();
		for (int i = 0; i < 5; i++) {
			jf.invoke(null);//默认写给浏览器,等同于jf.invoke(this.getJspContext().getOut());
		}
	}
	
}

然后,在WEB-INF目录下的simpleliayun.tld文件中添加对该标签处理类的描述,如下:
在这里插入图片描述
最后,在jsp页面中导入并使用自定义标签,如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/simpletag" prefix="sliayun" %>
<!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>
	<sliayun:demo2>
		赵敏郡主,倚天屠龙记<br/>
	</sliayun:demo2>
</body>
</html>

运行效果如下:
在这里插入图片描述

修改JSP页面内容输出

编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法中调用jspFrament.invoke方法时,让执行结果写入一个自定义的缓冲中即可,然后开发人员可以取出缓冲中的数据修改输出。

package cn.liayun.web.simpletag;

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 SimpleTagDemo3 extends SimpleTagSupport {

	@Override
	public void doTag() throws JspException, IOException {
		// 得到代表JSP标签体的JspFragment
		JspFragment jf = this.getJspBody();
		StringWriter sw = new StringWriter();
		// 将标签体的内容写入到StringWriter流中
		jf.invoke(sw);
		
		// 获取StringWriter流缓冲区的内容
		String content = sw.toString();
		content = content.toUpperCase();
		
		// 将修改后的content输出到浏览器中
		this.getJspContext().getOut().write(content);
	}
	
}

然后,在WEB-INF目录下的simpleliayun.tld文件中添加对该标签处理类的描述,如下:
在这里插入图片描述
最后,在jsp页面中导入并使用自定义标签,如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/simpletag" prefix="sliayun" %>
<!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>
	<sliayun:demo3>
		zhaomin<br/>
	</sliayun:demo3>
</body>
</html>

运行效果如下:
在这里插入图片描述

简单标签开发的一些注意细节

标签类编写细节

开发标签类时,不要直接去实现SimpleTag接口,而是应该继承SimpleTagSupport类,SimpleTagSupport类是SimpleTag接口的一个默认实现类,通过继承SimpleTagSupport类,就可以直接使用SimpleTagSupport类已经实现的那些方法,如果SimpleTagSupport类的方法实现不满足业务要求,那么就可以根据具体的业务情况将相应的方法进行重写。

tld文件中标签体类型设置细节

我们开发好一个简单标签后,需要在tld文件中添加对该标签的描述,例如:
在这里插入图片描述
开发好一个标签后,在tld文件中使用<tag>来描述一个标签,描述的内容包括标签名(name),标签处理器类(tag-class),标签体的内容(body-content)。tld文件中有四种标签体(body-content)类型 :empty、JSP、scriptless、tagdependent。

简单标签标签体的细节注意问题

在简单标签(SampleTag)中标签体body-content的值只允许是empty、scriptless、tagdependent,不允许设置成JSP,如果设置成JSP就会出现异常。
在这里插入图片描述
body-content的值如果设置成empty,那么就表示该标签没有标签体,如果是设置成scriptless,那么表示该标签是有标签体的,但是标签体中的内容不可以是<%Java代码%>,例如:
在这里插入图片描述
否则运行标签时就会出现诸如以下错误:
在这里插入图片描述
JSP标签技术出现的目的就是为了移除在JSP页面上编写的Java代码的,如果在JSP标签中允许出现Java代码,那么就违背了JSP标签技术设计时的初衷了。所以在简单标签的标签体中是不允许出现Java代码的。

传统标签标签体的细节注意问题

在传统标签中标签体body-content的值允许是empty、JSP、scriptless、tagdependent,body-content的值如果是设置成JSP,那么表示该标签是有标签体的,并且标签体的内容可以是任意的,包括Java代码,如果是设置成scriptless,那么表示该标签是有标签体的,但是标签体的内容不能是Java代码。
注意:如果传统标签和简单标签的标签体body-content的值设置成tagdependent,那么就表示标签体里面的内容是给标签处理器类使用的,tagdependent用得比较少,了解一下即可。

tld文件中标签库的uri设置细节

如果在一个项目中使用或者开发了多个标签库,例如:
在这里插入图片描述
那么标签库的uri不能设置成相同的,否则在JSP页面中通过uri引用标签库时就不知道引用哪一个标签库了,如果真的有那么巧,两个标签库的uri是刚好一样的,如下图所示:
在这里插入图片描述
那么在jsp页面中引用标签库时如果<%@taglib uri=”/simpletag” prefix=”sliayun” %>这样引用,那么就无法判断当前引用的标签库到底是liayun.tld标签库中的标签还是simpleliayun.tld标签库中的标签,因为这两个标签库的uri刚好都是”/simpletag”,在两个标签库的引用uri一样的情况下,为了能够在jsp中区别到底引用的是哪个标签库,可以换一种引用方式:<%@taglib uri="要引用的标签库的tld文件目录" prefix="sliayun"%>,使用taglib指令引入标签库时,taglib指令的uri属性指定为标签库的tld文件目录,这样就可以区别开了,例如:

  • 引用liayun.tld标签库:

    <%@taglib uri="/WEB-INF/liayun.tld" prefix="liayun"%>
    
  • 引用simpleliayun.tld标签库:

    <%@taglib uri="/WEB-INF/simpleliayun.tld" prefix="sliayun"%>
    

所以当在项目中引用了多个标签库,如果标签库的uri刚好是一样的,就可以用这种方式解决。

简单标签开发步骤总结

  1. 编写一个类继承SimpleTagSupport类,然后根据业务需要重写SimpleTagSupport类中已经实现了的方法,一般情况下只需要重写doTag()方法即可;
  2. 在WEB-INF目录下创建一个tld文件,在tld文件中添加对该标签的描述。tld文件不一定放在WEB-INF目录下,也可以放在别的目录,习惯是放在WEB-INF目录下。

开发带属性的标签

自定义标签可以定义一个或多个属性,这样,在JSP页面中应用自定义标签时就可以设置这些属性的值,通过这些属性为标签处理器传递参数信息,从而提高标签的灵活性和复用性。要想让一个自定义标签具有属性,通常需要完成两个任务:

  1. 在标签处理器中编写每个属性对应的setter方法;
  2. 在tld文件中描述标签的属性。

为自定义标签定义属性时,每个属性都必须按照JavaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收JSP页面调用自定义标签时传递进来的属性值。例如属性url,在标签处理器类中就要定义相应的setUrl(String url)方法。在标签处理器中定义相应的setter方法后,JSP引擎在解析执行开始标签前,也就是调用doStartTag方法前,会调用setter属性方法,为标签设置属性。

开发带属性的标签范例

范例一:通过标签的属性控制标签体的执行次数

首先,编写一个类继承SimpleTagSupport,然后再重写doTag方法,在doTag方法里面重复调用jspFrament.invoke方法即可。

package cn.liayun.web.simpletag;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

//控制标签余下的JSP不执行
public class SimpleTagDemo5 extends SimpleTagSupport {
	
	private int count;
	
	public void setCount(int count) {
		this.count = count;
	}

	@Override
	public void doTag() throws JspException, IOException {
		JspFragment jf = this.getJspBody();
		for (int i = 0; i < count; i++) {
			jf.invoke(null);
		}
	}
	
}

然后,在WEB-INF目录下的tld文件中添加对该标签的描述,如下所示:
在这里插入图片描述
最后,在jsp页面引入标签库并使用自定义标签:

<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/simpletag" prefix="sliayun" %>
<!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>
	<sliayun:demo5 count="9"> <!-- JSP引擎自动把字符串转成整型,但只支持8种基本数据类型的转换 -->
		赵敏郡主,倚天屠龙记<br/>
	</sliayun:demo5>
</body>
</html>

运行效果如下:
在这里插入图片描述
温馨提示:如果标签的属性值是8种基本数据类型,那么JSP页面在传递字符串时,JSP引擎会自动转换成相应的类型,但如果标签的属性值是复合数据类型,那么JSP引擎是无法自动转换的。

范例二:标签接收的属性值是一个复合数据类型,该如何给标签的属性赋值呢?

首先将SimpleTagDemo5类的代码改为:

package cn.liayun.web.simpletag;

import java.io.IOException;
import java.util.Date;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

//控制标签余下的JSP不执行
public class SimpleTagDemo5 extends SimpleTagSupport {
	
	private int count;
	private Date date;
	
	public void setCount(int count) {
		this.count = count;
	}
	
	public void setDate(Date date) {
		this.date = date;
	}

	@Override
	public void doTag() throws JspException, IOException {
		JspFragment jf = this.getJspBody();
		this.getJspContext().getOut().write(date.toLocaleString() + "<br/>");
		for (int i = 0; i < count; i++) {
			jf.invoke(null);
		}
	}
	
}

然后,在WEB-INF目录下的tld文件中添加对该标签的描述,如下所示:
在这里插入图片描述
最后,在jsp页面引入标签库并使用自定义标签:

<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="/simpletag" prefix="sliayun" %>
<!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>
	<%-- 如果一定要给标签的复合属性赋值,那么可以采用表达式的方式给复合属性赋值,如下所示: --%>
	<sliayun:demo5 count="9" date="<%=new Date() %>"> <!-- JSP引擎自动把字符串转成整型,但只支持8种基本数据类型的转换 -->
		赵敏郡主,倚天屠龙记<br/>
	</sliayun:demo5>
</body>
</html>

运行效果如下:
在这里插入图片描述

tld文件中用于描述标签属性的<attribute>元素说明

<tag>元素的<attribute>子元素用于描述自定义标签的一个属性,自定义标签所具有的每个属性都要对应一个<attribute>元素。 <attribute>元素的子元素说明如下:
在这里插入图片描述
到此,简单标签的开发技术就算是全部讲完了,在下一篇博客中会编写一些自定义标签的案例来加深自定义标签技术的学习和理解。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李阿昀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值