自定义JSP标签

自定义JSP标签有两种方式:传统的自定义标签开发和简单标签开发。

传统的自定义标签开发:在传统的自定义标签的主体中可以包含Java程序片段,标签的处理流程比较复杂,现在一般不使用。

简单标签开发:为了简化开发标签的过程,JSP2.0引入了一种新的标签扩展机制,称为“简单标签扩展”。

简单标签的开发可以选择实现javax.servlet.jsp.tagext.SimpleTag接口,也可以继承SimpleTagSupport类。这种方式十分类似Servlet的开发,我们开发一个Servlet可以选择实现Servlet接口,也可以直接继承HttpServlet类,实际中更多地采用继承HttpServlet类。简单标签的开发实际中也是继承SimpleTagSupport类。

不过为了更好地理解整个过程,我们还是从SimpleTag接口开始讲起。

1. 实现SimpleTag接口

在javax.servlet.jsp.tagext.SimpleTag接口中定义了以下5个方法。

① void setJspContext(JspContext pc):由Servlet容器调用该方法,向SimpleTag对象传递当前的JspContext对象。JspContext类是PageContext类的父类,在JspContext类中定义了用于存取各种范围内的共享数据的方法,如getAttribute( )、setAttribute( )和removeAttribute( )方法等。

② void setParent(JspTag parent) :由Servlet容器调用该方法,向当前SimpleTag对象传递父标签的JspTag对象。

③ JspTag getParent():返回父标签的JspTag对象

④ void setJspBody(JspFragment jspBody):由Servlet容器调用该方法,向当前SimpleTag对象传递标签主体。参数jspBody表示当前标签的主体,它封装了一段JSP代码。

⑤ void doTag():该方法负责具体的标签处理过程。与传统标签处理类的doStartTag()和doEndTag()方法不同的是,doTag()方法没有返回值。

SimpleTag对象由Servlet容器负责创建。每次当Servlet容器在执行JSP文件时,遇到JSP文件中的自定义的简单标签,都会创建一个SimpleTag对象,当标签处理完毕,就会销毁该SimpleTag对象,这是与传统的自定义标签的一个不同之处。对于传统的自定义标签,Servlet容器会缓存标签处理类的实例,以便重复利用该实例。

Servlet容器在得到了SimpleTag对象后,会按照下图的流程调用SimpleTag对象的相关方法:


⑴ Servlet容器调用SimpleTag对象的setJspContext( )和setParent( )方法,把当前JSP页面的JspContext对象及父标签处理对象传给当前SimpleTag对象。如果不存在父标签,则把父标签处理对象设为null。

⑵ Servlet容器调用SimpleTag对象的一系列set方法,设置SimpleTag对象的属性。如果标签没有属性,则无需这个步骤。

⑶如果存在标签主体,Servlet容器就调用SimpleTag对象的setJspBody()方法,设置标签主体。

⑷Servlet容器调用SimpleTag对象的doTag()方法,在该方法中完成处理标签的具体逻辑。

2. 继承SimpleTagSupport类

实际开发中我们更多地是选择直接继承SimpleTagSupport类,并覆盖它的doTag()方法来开发自定义标签。

我们先来看看SimpleTagSupport类的源代码:

public class SimpleTagSupport implements SimpleTag
{
   
    private JspTag parentTag;
  
    private JspContext jspContext;
   
    private JspFragment jspBody;
  
    public SimpleTagSupport() { }
    
    public void doTag() throws JspException, IOException
    {
    }
    
    public void setParent( JspTag parent ) {
        this.parentTag = parent;
    }
    
   
    public JspTag getParent() {
        return this.parentTag;
    }
    
    public void setJspContext( JspContext pc ) {
        this.jspContext = pc;
    }
 
    protected JspContext getJspContext() {
        return this.jspContext;
    }
                
    public void setJspBody( JspFragment jspBody ) {
        this.jspBody = jspBody;
    }
    
    protected JspFragment getJspBody() {
        return this.jspBody;
    }

    public static final JspTag findAncestorWithClass(
	JspTag from, Class<?> klass) 
    {
	boolean isInterface = false;

	if (from == null || klass == null
	        || (!JspTag.class.isAssignableFrom(klass)
		    && !(isInterface = klass.isInterface()))) {
	    return null;
	}

	for (;;) {
	    JspTag parent = null;
	    if( from instanceof SimpleTag ) {
		parent = ((SimpleTag)from).getParent();
	    }
	    else if( from instanceof Tag ) {
		parent = ((Tag)from).getParent();
	    }
	    if (parent == null) {
		return null;
	    }

	    if (parent instanceof TagAdapter) {
		parent = ((TagAdapter) parent).getAdaptee();
	    }

	    if ((isInterface && klass.isInstance(parent))
		    || klass.isAssignableFrom(parent.getClass())) {
		return parent;
	    }

	    from = parent;
	}
    }    
}
可以知道,SimpleTagSupport类实现了SimpleTag接口的所有方法,除了doTag()方法为空实现,其余方法都有具体的实现。所以我们开发自己的自定义标签只需要继承SimpleTagSupport类并覆盖doTag()方法即可。

第一个自定义标签:无标签主体的简单标签

ShowInfo.java

public class ShowInfoTag extends SimpleTagSupport {
	
	private String info;
	private int num;
	
	public void setInfo(String info) {
		this.info = info;
	}
	
	public void setNum(int num) {
		this.num = num;
	}

	@Override
	public void doTag() throws JspException, IOException {

		JspContext jc=getJspContext();
		PageContext pc=(PageContext)jc;
		JspWriter out=pc.getOut();
		for(int i=0;i<num;i++){
			out.println(info+"<br>");
		}
	}
	
}
mytag.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">
    
  <description>JSTL 1.1 core library</description>
  <display-name>JSTL core</display-name>
  <tlib-version>1.1</tlib-version>
  <short-name>c1</short-name>
  <uri>www.dragon.com</uri>
  
<tag>
    
    <name>showInfo</name>
    <tag-class>com.tag.ShowInfoTag</tag-class>
    <body-content>empty</body-content>
    
    <attribute>
        <name>info</name>
        <required>true</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
    
     <attribute>
        <name>num</name>
        <required>true</required>
        <rtexprvalue>false</rtexprvalue>
    </attribute>
    
 </tag>
</taglib>
test.jsp

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c1" uri="www.dragon.com" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c1:showInfo info="hello world" num="10"/>
</body>
</html>

第二个自定义标签:有标签主体的简单标签

HelloUserTag.java

public class HelloUserTag extends SimpleTagSupport{
	
	private String username;

	public void setUsername(String username) {
		this.username = username;
	}

	@Override
	public void doTag() throws JspException, IOException {
		PageContext pc=(PageContext)getJspContext();
		JspWriter out=pc.getOut();
		JspFragment jspBody=getJspBody();
		if(!username.equals("Tom")){
			out.print("Hello,");
			jspBody.invoke(null);
		}else{
			out.print("go out,"+username+"!");
			throw new SkipPageException();
		}
	}
	
}
mytag.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.1</tlib-version>
    <short-name>c1</short-name>
    <uri>www.dragon.com</uri>
    
  <tag>
     <name>helloUser</name>
    <tag-class>com.tag.HelloUserTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
         <name>username</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>
</taglib>
test.jsp
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c1" uri="www.dragon.com"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<c1:helloUser username="${param.username}">
${param.username}<br>
</c1:helloUser>
other content......
</body>
</html>
jspBody对象为JspFragment类型。JspFragment类代表一段JSP代码,它的invoke(java.io.Writer out)方法负责执行所封装的JSP代码,并且通过out参数输出执行结果。如果参数out为null,则把执行结果输出到当前输出流中。

对于简单标签,tld文件的<tag>元素的<body-content>元素的可选值包括empty、scriptless,默认为scriptless。对于传统的自定义标签,<body-content>的值可为jsp,但是由于简单标签的主体不能包含Java程序片段等脚本元素,所以简单标签的<body-content>的值不能为jsp。

empty:表示不允许出现标签体

scriptless:允许出现标签体,但不允许出现Java代码,即不允许<% %>、<%! %>、<%= %>。

jsp:允许出现Java代码,但是简单标签不支持。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值