自定义标签

一:自定义标签

1、自定义标签主要用于移除 JSP 页面中的 java 代码

2、要使用自定义标签,需要完成以下两个步骤:

        a、编写一个实现 Tag 接口的 java 类,把页面 java 代码写在这个 java 类中(标签处理器类)

        b、编写标签库描述符(tld)文件,在tld 文件中对标签处理器类描述成一个标签


二:入门

定义一个查看本机IP的标签:

diyTagViewIP.java

package com.haizhu.diyTag;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

public class diyTagViewIP extends TagSupport {
	
	public int doStartTag() throws JspException{
		/**
		 * 在 doStartTga 执行之前,TagSupport中的 setPageContext 方法就执行过了(服务器调用执行),所以可以直接使用
		 */
		HttpServletRequest request = (HttpServletRequest)this.pageContext.getRequest(); 
		JspWriter out = this.pageContext.getOut();
		
		String ip = request.getRemoteAddr();
		
		try {									// 这个是父类中的异常,只能捕捉,不能跟在方法后面抛出去
			out.print(ip);
		} catch (IOException e) {
			throw new RuntimeException(e);		// 那就抛出一个运行时异常
		}
		return super.doStartTag();
	}
}

viewIpTag.tld,注意这个文件的位置是在:WEB-INF 目录下

<?xml version="1.0" encoding="UTF-8" ?>

<!-- 这是从 绿色版\apache-tomcat-7.0.42\webapps\examples\WEB-INF\jsp2\jsp2-example-taglib.tld 模板中拷贝过来的 -->
<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>A tag library exercising SimpleTag handlers.</description>
    <tlib-version>1.0</tlib-version>
    <short-name>SimpleTagLibrary</short-name>
    <!-- 指定保定这些标签的 URI -->
    <uri>http://www.haizhu.cn/viewIP</uri>

    <tag>
    	<!-- 标签属性名称 -->
        <name>viewIP</name>
        <!-- 对应 的 java 类  -->
        <tag-class>com.haizhu.diyTag.diyTagViewIP</tag-class>
		<!-- 有没有标签体,这里empty 表示没有,有的话就写 JSP -->
        <body-content>empty</body-content>
    </tag>

</taglib>

DIYTagDemo.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!-- 通过 URI 引入自己定义的标签,这里prefix取值是标签的tld文件的名字,这样容易找到对应的文件,好查看源码 -->
<%@taglib uri="http://www.haizhu.cn/viewIP" prefix="viewIpTag"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'ELDemo.jsp' starting page</title>
  </head>
  
  <body>
  	您的IP是:
	<%
		String ip = request.getRemoteAddr();
		out.print(ip);
	 %>

<br><br>*********************************************************<br><br>
	您的IP是:
	<!-- 因为没有标签体,所以直接一个标签就可以了 -->
	<viewIpTag:viewIP/>
  </body>
</html>


三:分析自定义标签的执行流程

1、首先呢,需要明白的一点,运行 JSP 页面页面的时候,其实是运行编译成为 servlet 的程序

2、遇到自定义标签,首先实例化标签对应的标签处理器类

3、调用setPageContext 方法,把页面的pageContext 对象传递给标签处理器类

4、看标签是否有父标签,如果有,则把父标签多为一个对象,调用setParent方法,传递改标签处理器类,没有,传递NULL。

5、标签初始化工作后,标签处理器类开始处理标签,遇到开始标签,调用doStart方法

6、如果标签有标签体,服务器一般执行标签体

7、服务器遇到JSP页面结束标签,调用标签处理器类的 doEnd 方法

8、整个标签执行完毕后,一般情况下调用 release方法,释放标签工作时占用的资源


四:自定义标签功能扩展

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

        只需要在编写的标签类中覆写doStartTag 方法,“return Tag.EVAL_BODY_INCLUDE;”,则显示标签体,“return Tag.SKIP_BODY;”就不显示

2、控制整个JSP 页面是否执行

        覆写doEndTag 方法,“return Tag.EVAL_PAGE;”就执行余下的JSP,“return Tag.SKIP_PAGE;”就不执行余下的JSP。

3、控制JSP 页面内容重复执行:IterationTag 接口 ——> TagSupport 实现类

        先覆写 doStartTag 方法,返回 Tag.EVAL_BODY_INCLUDE ,之后覆写 doAfterBody 方法,通过返回“return IterationTag.EVAL_BODY_AGAIN”或“return IterationTag.SKIP_BODY”来控制是否再次显示 标签体中的文字

4、修改JSP 页面内容输出:BodyTag 接口 ——> BodyTagSupport 实现类

       范例:

package com.haizhu.diyTag;

import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.Tag;

public class TagDemo extends BodyTagSupport {
	// 标签开始执行的时候,执行这个方法
	public int doStartTag() throws JspException{
		// 表示将标签体封装到 bodyContent 对象中
		return BodyTag.EVAL_BODY_BUFFERED;
	}
	
	// 标签结束的时候执行这个方法
	public int doEndTag(){
		// 得到标签体
		BodyContent bc = this.getBodyContent();
		// 得到标签体内容
		String content = bc.getString();
		// 将内容转换为大写
		content = content.toUpperCase();
		try {
			// 将内容输出给 JSP 页面
			this.pageContext.getOut().write(content);
		} catch (IOException e) {
			// 抛出运行时异常
			throw new RuntimeException(e);
		}
		// 表示继续执行本页面中这个标签下面的代码
		return Tag.EVAL_PAGE;
	}
}
5、注意,sun 公司现在为了方便,现在只需要实现SimpleTag 接口,继承 SimpleTagSupport 就可以实现上面的功能了,而不必在使用IterationTag接口和BodyTag接口。
范例:

SimpleTagDemo.java

package com.haizhu.diyTag;

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;

public class SimpleTagDemo extends SimpleTagSupport {
	public void doTag() throws JspException, IOException {

		this.getJspContext().getOut().write("<br><br>**********************************得到标签内容********************************<br>");
		// 得到标签体
		JspFragment jf = this.getJspBody();
		// invoke 表示标签体执行,执行的内容是得到标签体内容输出给浏览器
		jf.invoke(this.getJspContext().getOut());
		
		this.getJspContext().getOut().write("<br><br>*********************************循环输出标签内容******************************<br>");

		// 如果想多次输出标签体,可以这么做
		for(int i=0;i<5;i++){
			jf.invoke(this.getJspContext().getOut());
		}
		
		this.getJspContext().getOut().write("<br><br>**********************************改变标签内容********************************<br>");

		// 初始化一个输出到缓冲区的流
		StringWriter sw = new StringWriter();
		// invoke 到缓冲区
		jf.invoke(sw);
		// 取出缓冲区的内容并转化为大写
		String content = sw.toString();
		content = content.toUpperCase();
		// 输出给浏览器
		this.getJspContext().getOut().write(content);

		this.getJspContext().getOut().write("<br><br>*********************************标签以下的内容*******************************<br>");
		// 控制页面标签以下的内容是否输出,更加简单,只要抛出一个异常即可
		throw new SkipPageException();
	}
}
simpleTagTLD.tld

<?xml version="1.0" encoding="UTF-8" ?>

<!-- 这是从 绿色版\apache-tomcat-7.0.42\webapps\examples\WEB-INF\jsp2\jsp2-example-taglib.tld 模板中拷贝过来的 -->
<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>SimpleTagLibrary</short-name>
    <!-- 指定保定这些标签的 URI -->
    <uri>http://www.haizhu.cn/simpleTagDemoTLD</uri>

    <tag>
    	<!-- 标签属性名称 -->
        <name>simpleTagName</name>
        <!-- 对应 的 java 类  -->
        <tag-class>com.haizhu.diyTag.SimpleTagDemo</tag-class>
		<!-- 有没有标签体,这里empty 表示没有,而有内容时传统的写法是 JSP ,这里不再是了,而是 scriptless -->
        <body-content>scriptless</body-content>
    </tag>

</taglib>

simpleTag.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.haizhu.cn/simpleTagDemoTLD" prefix="simpleTag"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>'simpleTag.jsp' 使用范例</title>
  </head>
  
  <body>
  	标签之上的内容。
	<simpleTag:simpleTagName>
		Hello world !
	</simpleTag:simpleTagName>
  	标签以下的内容。
  </body>
</html>
注意:这个标签中写了很多的功能,这些功能每个都可以写成一个标签。


6、带有属性的标签:

要想让一个自定义标签具有属性,通常需要完成两个任务:在标签处理器类中编写每个属性对应的setter方法,并在TLD文件中描述标签的属性。这样的话,JSP引擎在解析执行开始标签前,也就是在调用doStartTag方法前,会调用set 属性方法,为标签设置属性。

标签处理类:TagWithAttrDemo.java

package com.haizhu.attrTag;

import java.io.IOException;

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

public class TagWithAttrDemo extends SimpleTagSupport {
	// 定义属性,并声明setter方法
	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);
		}
	}
}
配置文件:

<?xml version="1.0" encoding="UTF-8" ?>

<!-- 这是从 绿色版\apache-tomcat-7.0.42\webapps\examples\WEB-INF\jsp2\jsp2-example-taglib.tld 模板中拷贝过来的 -->
<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>SimpleTagLibrary</short-name>
    <!-- 指定保定这些标签的 URI -->
    <uri>http://www.haizhu.cn/simpleTagDemoTLD</uri>

    <tag>
    	<!-- 标签属性名称 -->
        <name>tagWithAttr</name>
        <!-- 对应 的 java 类  -->
        <tag-class>com.haizhu.attrTag.TagWithAttrDemo</tag-class>
		<!-- 有没有标签体,这里empty 表示没有,而有内容时传统的写法是 JSP ,这里不再是了,而是 scriptless -->
        <body-content>scriptless</body-content>
		<!-- 属性 -->
        <attribute>
        	<!-- 名字 -->
        	<name>count</name>
        	<!-- 是否必须 -->
        	<required>true</required>
        	<!-- 参数赋值类型 -->
        		<!-- true:可以使用${user.name}的形式赋值,比如 count="${user.age}" -->
        		<!-- false:只能使用这种方式 count="110" -->
        	<rtexprvalue>true</rtexprvalue>
        </attribute>
    </tag>

</taglib>
显示页面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://www.haizhu.cn/simpleTagDemoTLD" prefix="simpleTag"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>'simpleTag.jsp' 使用范例</title>
  </head>
  
  <body>
	<simpleTag:tagWithAttr count="110">
		Hello world !
	</simpleTag:tagWithAttr>
  </body>
</html>



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值