JAVA自定义标签教程及实例代码

来源:互联网 发布:金蝶软件版本号 编辑:程序博客网 时间:2024/05/29 17:13

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

快速入门:使用自定义标签输出客户机的IP

移除jsp页面中的java代码,只需要完成两个步骤:

编写一个实现Tag接口的Java类,并覆盖doStartTag方法,把jsp页面中的java代码写到doStartTag方法中。

编写标签库描述符(tld)文件,在tld文件中对自定义标签进行描述。

完成以上操作,即可在JSP页面中导入和使用自定义标签。

查看tag接口api文档,分析自定义标签的执行流程。

自定义标签的创建步骤:

(1)      标签处理器——java类,实现Tag接口

(2)      编写.tld:

JSP页面中使用自定义标签

<dhw:aaa>

<dhw:viewIP>系统自动调用doStartTag()

</dhw:viewIP>系统自动调用doEndTag()

</dhw:aaa>

Tag接口的执行流程

JSP引擎将遇到自定义标签时,首先创建标签处理器类的实例对象,然后按照JSP规范定义的通信规则依次调用它的方法。

       1、public voidsetPageContext(PageContext pc), JSP引擎实例化标签处理器后,将调用setPageContext方法将JSP页面的pageContext对象传递给标签处理器,标签处理器以后可以通过这个pageContext对象与JSP页面进行通信。

       2、public void setParent(Tag t),setPageContext方法执行完后,WEB容器接着调用的setParent方法将当前标签的父标签传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent方法的参数值为null。

       3、public int doStartTag(),调用了setPageContext方法和setParent方法之后,WEB容器执行到自定义标签的开始标记时,就会调用标签处理器的doStartTag方法。

       4、public int doEndTag(),WEB容器执行完自定义标签的标签体后,就会接着去执行自定义标签的结束标记,此时,WEB容器会去调用标签处理器的doEndTag方法。

       5、public void release(),通常WEB容器执行完自定义标签后,标签处理器会驻留在内存中,为其它请求服务器,直至停止web应用时,web容器才会调用release方法。

自定义标签功能扩展

自定义标签除了可以移除Jsp页面中的java代码外,它还可以用于完成一些页面逻辑,例如:

通过自定义标签可以控制jsp页面某一部分内容是否执行。

例如:<c:if>标签

通过自定义标签可以控制标签后的jsp页面是否执行。

通过自定义标签可以控制jsp页面某一部分内容重复执行。

例如:<c:foreach>标签

通过自定义标签可以修改jsp页面内容输出。

tld文件中的四种标签体类型

EMPTY  JSP scriptless  tagdepentend

简单标签

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

setJspContext方法

setParent和getParent方法

setJspBody方法

doTag方法

SimpleTag方法介绍

setJspContext方法

用于把JSP页面的pageContext对象传递给标签处理器对象

setParent方法

用于把父标签处理器对象传递给当前标签处理器对象

getParent方法

用于获得当前标签的父标签处理器对象

setJspBody方法

用于把代表标签体的JspFragment对象传递给标签处理器对象

doTag方法

用于完成所有的标签逻辑,包括输出、迭代、修改标签体内容等。在doTag方法中可以抛出javax.servlet.jsp.SkipPageException异常,用于通知WEB容器不再执行JSP页面中位于结束标记后面的内容,这等效于在传统标签的doEndTag方法中返回Tag.SKIP_PAGE常量的情况。

SimpleTag接口方法的执行顺序

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

WEB容器调用标签处理器对象的setJspContext方法,将代表JSP页面的pageContext对象传递给标签处理器对象。

WEB容器调用标签处理器对象的setParent方法,将父标签处理器对象传递给这个标签处理器对象。注意,只有在标签存在父标签的情况下,WEB容器才会调用这个方法。

如果调用标签时设置了属性,容器将调用每个属性对应的setter方法把属性值传递给标签处理器对象。如果标签的属性值是EL表达式或脚本表达式,则WEB容器首先计算表达式的值,然后把值传递给标签处理器对象。

如果简单标签有标签体,容器将调用setJspBody方法把代表标签体的JspFragment对象传递进来。

执行标签时:

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

JspFragment类

javax.servlet.jsp.tagext.JspFragment类是在JSP2.0中定义的,它的实例对象代表JSP页面中的一段符合JSP语法规范的JSP片段,这段JSP片段中不能包含JSP脚本元素。

WEB容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody方法把JspFragment对象传递给标签处理器对象。JspFragment类中只定义了两个方法,如下所示:

getJspContext方法

用于返回代表调用页面的JspContext对象.

public abstractvoid invoke(java.io.Writer out)

用于执行JspFragment对象所代表的JSP代码片段

参数out用于指定将JspFragment对象的执行结果写入到哪个输出流对象中,如果传递给参数out的值为null,则将执行结果写入到JspContext.getOut()方法返回的输出流对象中。(简而言之,可以理解为写给浏览器)

invoke方法详解

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

在标签处理器中如果没有调用JspFragment.invoke方法,其结果就相当于忽略标签体内容;

在标签处理器中重复调用JspFragment.invoke方法,则标签体内容将会被重复执行;

若想在标签处理器中修改标签体内容,只需在调用invoke方法时指定一个可取出结果数据的输出流对象(例如StringWriter),让标签体的执行结果输出到该输出流对象中,然后从该输出流对象中取出数据进行修改后再输出到目标设备,即可达到修改标签体的目的。


自定义标签制作步骤:

 

1.扩展TagSupport

2.标签所对应的tld文件配置

3.在JSP页面引用tld配置文件并使用标签

 

标签制作常用方法说明:

 

doStartTag()和doEndTag()返回值处理:

SKIP_BODY (0) :跳过了开始和结束标签之间的代码。
EVAL_BODY_INCLUDE(1):将body的内容输出到存在的输出流中
SKIP_PAGE(5): 忽略剩下的页面。
EVAL_PAGE隐含(6):继续执行下面的页



Test.jsp 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'Test.jsp' starting page</title>
  </head>
 
  <body>
    This is my JSP page. <br>
    Date : <%= new java.util.Date().toString() %> <br>
    File : <input value="<%= request.getServletPath() %>" /> 
  </body>
</html>

为了将这个这个Test.jsp改成自定义标签方法,我们分别使用简单标签和内容标签两种不同的方式实现。

1. 简单标签

由于我们需要输出两个内容(日期和文件名),因此我们为标签创建一个参数。具体代码:

DemoTag.java 
package com.mycompany;

import java.util.Date;

import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

public class DemoTag extends TagSupport {
  
  public int doStartTag() throws JspException {    
    try {
      HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
      JspWriter out = pageContext.getOut();      
      
      if (parameter.compareToIgnoreCase("filename") == 0)
        out.print(request.getServletPath());
      else 
        out.print(new Date());
      
    } catch (java.io.IOException e) {
      throw new JspTagException(e.getMessage());
    }
    
    return SKIP_BODY;
  }
  
  private String parameter = "date";
  
  public void setParameter(String parameter) {
    this.parameter = parameter;
  } 
  
  public String getParameter() {
    return parameter;
  }
}

接下来,我们创建标签文件 MyTagLib.tld。标签文件其实只是一个XML格式的说明文件,内容也很简单。

MyTagLib.tld 
<?xml version="1.0" encoding="ISO-8859-1"?>
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>

<tag>
  <name>demo</name>
  <tag-class>com.mycompany.DemoTag</tag-class>
  <body-content>empty</body-content>
  <attribute>
    <name>parameter</name>
    <required>false</required>
    <rtexprvalue>true</rtexprvalue>
  </attribute>
</tag>

</taglib>

在这个标签文件中,我们将我们创建的标签取名 demo,并声明了类型和参数(parameter)。将该文件保存在 /WEB-INF 下面。
当然,我们还需要将我们自定义的标签添加到 web.xml 中,否则还是无法使用。

web.xml 
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <jsp-config>
    <taglib>
      <taglib-uri>/WEB-INF/MyTagLib</taglib-uri>
      <taglib-location>/WEB-INF/MyTagLib.tld</taglib-location>
    </taglib>
  </jsp-config>

</web-app>

你可能在别处看到过类似的声明,只是没有外面的 jsp-config,但是我们使用的是DTD 2.4,如果不加,Eclipse 会提示出错。

到此为止,我们的自定义标签算是创建完毕。接下来,我们可以开始改写那个JSP文件来分离代码了。

Test.jsp 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@taglib uri="/WEB-INF/MyTagLib" prefix="mytag"%>
<html>
  <head>
    <title>My JSP 'Test.jsp' starting page</title>
  </head>
 
  <body>
    This is my JSP page. <br>
    Date : <mytag:demo parameter="date" /><br>
    File : <mytag:demo parameter="filename" />
  </body>
</html>

上面这些想必你已经很熟悉,我就不做多说了。

2. 内容标签

创建过程和上面大抵相同,只是程序文件和配置内容有些差异。

DemoTag2.java 
package com.mycompany;

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

import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;

public class DemoTag2 extends BodyTagSupport {
  
  public int doStartTag() throws JspTagException {    
    return EVAL_BODY_BUFFERED;
  }
  
  public int doEndTag() throws JspTagException {
    String body = this.getBodyContent().getString();
    HttpServletRequest request = (HttpServletRequest)pageContext.getRequest();
    
    body = body.replace("$date", new Date().toString());
    body = body.replace("$filename", request.getServletPath());
    
    try {
      pageContext.getOut().print(body);
    }
    catch (IOException e) {
      throw new JspTagException(e.getMessage());
    }
    
    return SKIP_BODY;
  }
}

我们将新的标签 DemoTag2 加入到上面的标签文件中。

MyTagLib.tld 
<?xml version="1.0" encoding="ISO-8859-1"?>
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>

<tag>
  <name>demo</name>
  <tag-class>com.mycompany.DemoTag</tag-class>
  <body-content>empty</body-content>
  <attribute>
    <name>parameter</name>
    <required>false</required>
    <rtexprvalue>true</rtexprvalue>
  </attribute>
</tag>

<tag>
  <name>demo2</name>
  <tag-class>com.mycompany.DemoTag2</tag-class>
  <body-content>jsp</body-content>
</tag>

</taglib>

web.xml 文件无需修改。

看看同时使用两种标签的Test.jsp效果。

Test.jsp 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%@taglib uri="/WEB-INF/MyTagLib" prefix="mytag"%>
<html>
  <head>
    <title>My JSP 'Test.jsp' starting page</title>
  </head>
 
  <body>
    This is my JSP page. <br>
    Date : <mytag:demo parameter="date" /><br>
    File : <mytag:demo parameter="filename" />

    <hr>

    <mytag:demo2>
    Date: $date<br>
    File: $filename
    </mytag:demo2>
  </body>
</html> 
原创粉丝点击