JSP标签介绍,自定义标签

Posted 前行者鼠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JSP标签介绍,自定义标签相关的知识,希望对你有一定的参考价值。

一、JSP标签介绍

1、 标签库有什么作用

自定义标签库是一种优秀的表现层技术,之前介绍的MVC模式,我们使用jsp作为表现层,但是jsp语法嵌套在html页面,美工还是很难直接参与开发,并且jsp脚本和html代码耦合在一起,维护成本较高。我们能不能开发一套和html风格类似并且能完成jsp脚本功能的标签来解决这种低效的协作方式呢?于是标签库就诞生了

2、 标签的继承体系

 

3、 相关类的介绍

 

3.1 Tag

/**

* The interface of a classic tag handler that does not want to manipulate its body.

*.............

*/

public interface Tag extends JspTag {

 

 

Tag接口是所有传统标签的父接口,其中定义了两个重要方法(doStartTag、

doEndTag)方法和四个常量(EVAL_BODY_INCLUDE、SKIP_BODY、EVAL_PAGE、

SKIP_PAGE),这两个方法和四个常量的作用如下:

 

1.WEB容器在解释执行JSP页面的过程中,遇到自定义标签的开始标记就会去调用标签处理器的doStartTag方法,doStartTag方法执行完后可以向WEB容器返回常量EVAL_BODY_INCLUDESKIP_BODY如果doStartTag方法返回EVAL_BODY_INCLUDEWEB容器就会接着执行自定义标签的标签体;如果doStartTag方法返回SKIP_BODYWEB容器就会忽略自定义标签的标签体,直接解释执行自定义标签的结束标记。

 

2.WEB容器解释执行到自定义标签的结束标记时,就会调用标签处理器的doEndTag方法,doEndTag方法执行完后可以向WEB容器返回常量EVAL_PAGESKIP_PAGE如果doEndTag方法返回常量EVAL_PAGEWEB容器就会接着执行JSP页面中位于结束标记后面的JSP代码;如果doEndTag方法返回SKIP_PAGEWEB容器就会忽略JSP页面中位于结束标记后面的所有内容。从doStartTagdoEndTag方法的作用和返回值的作用可以看出,开发自定义标签时可以在doStartTag方法和doEndTag方法体内编写合适的Java程序代码来实现具体的功能,通过控制doStartTag方法和doEndTag方法的返回值,还可以告诉WEB容器是否执行自定义标签中的标签体内容和JSP页面中位于自定义标签的结束标记后面的内容。

3.生命周期:setPageContext(可以获得PageContext)‐‐‐>setParent‐‐‐>doStartTag‐‐‐>doEndTag‐‐‐>release

 

 

 

3.2 JspTag

/**

 * Serves as a base class for Tag and SimpleTag.

 * This is mostly for organizational and type-safety purposes.

 *

 * @since 2.0

 */

public interface JspTag {

    // No methods even through there are some common methods

 

JspTag接口是所有自定义标签的父接口,它JSP2.0中新定义的一个标记接口,没有任何属性和方法JspTag接口有TagSimpleTag两个直接子接口,JSP2.0以前的版本 中只有Tag接口,所以把实现Tag接口的自定义标签也叫做传统标签,把实现SimpleTag 接口的自定义标签叫做简单标签

3.3 IterationTag

/**

 * The IterationTag interface extends Tag by defining one additional

 * method that controls the reevaluation of its body.

...........

 */

public interface IterationTag extends Tag {

 

 

 

 

IterationTag接口继承了Tag接口,并在Tag接口的基础上增加了一个doAfterBody方法和一个EVAL_BODY_AGAIN常量。实现IterationTag接口的标签除了可以完成Tag接口

所能完成的功能外,还能够通知WEB容器是否重复执行标签体内容。对于实现了IterationTag接口的自定义标签,WEB容器在执行完自定义标签的标签体后,将调用标签处理器的doAfterBody方法,doAfterBody方法可以向WEB容器返回常量EVAL_BODY_AGAINSKIP_BODY。如果doAfterBody方法返回EVAL_BODY_AGAINWEB容器就会把标签体内容再重复执行一次,执行完后接着再调用doAfterBody方法,如此往复,直到doAfterBody方法返回常量SKIP_BODYWEB容器才会开始处理标签的结束标记和调用doEndTag方法。

 

可见,开发自定义标签时,可以通过控制doAfterBody方法的返回值来告诉WEB容器是否重复执行标签体内容,从而达到循环处理标签体内容的效果。例如,可以通过一个

实现IterationTag接口的标签来迭代输出一个集合中的所有元素,在标签体部分指定元素的输出格式。

JSP  API中也提供了IterationTag接口的默认实现类TagSupport,我们在编写自定义标签的标签处理器类时,可以继承和扩展TagSupport类,这相比实现IterationTag接口将简化开发工作。

3.4 TagSupport

 

/**

 * A base class for defining new tag handlers implementing Tag.

 *

 * <p> The TagSupport class is a utility class intended to be used as

 * the base class for new tag handlers.  The TagSupport class

 * implements the Tag and IterationTag interfaces and adds additional

 * convenience methods including getter methods for the properties in

 * Tag.  TagSupport has one static method that is included to

 * facilitate coordination among cooperating tags.

 *

 * <p> Many tag handlers will extend TagSupport and only redefine a

 * few methods.

 */

public class TagSupport implements IterationTag, Serializable {

 

3.5 BodyTag

/**

 * The BodyTag interface extends IterationTag by defining additional methods

 * that let a tag handler manipulate the content of evaluating its body.

 .........

 */

public interface BodyTag extends IterationTag {

 

 

 

BodyTag接口继承了IterationTag接口,并在IterationTag接口的基础上增加了两个 方法(setBodyContentdoInitBody)和一个EVAL_BODY_BUFFERED常量。实现 BodyTag接口的标签除了可以完成IterationTag接口所能完成的功能,还可以对标签体内容进行修改。对于实现了BodyTag接口的自定义标签,标签处理器的doStartTag方法 不仅可以返回前面讲解的常量EVAL_BODY_INCLUDESKIP_BODY,还可以返回常量 EVAL_BODY_BUFFERED。如果doStartTag方法返回EVAL_BODY_BUFFEREDWEB容器就 会创建一个专用于捕获标签体运行结果的BodyContent对象,然后调用标签处理器的 setBodyContent方法将BodyContent对象的引用传递给标签处理器,WEB容器接着将标 签体的执行结果写入到BodyContent对象中。在标签处理器的后续事件方法中,可以通 过先前保存的BodyContent对象的引用来获取标签体的执行结果,然后调用 BodyContent对象特有的方法对BodyContent对象中的内容(即标签体的执行结果)进 行修改和控制其输出。

JSP API中也提供了BodyTag接口的实现类BodyTagSupport,我们在编写能够修 改标签体内容的自定义标签的标签处理器类时,可以继承和扩展BodyTagSupport类,这 相比实现BodyTag接口将简化开发工作。

 

3.6 BodyTagSupport

/**

 * A base class for defining tag handlers implementing BodyTag.

 * <p>

 * The BodyTagSupport class implements the BodyTag interface and adds additional

 * convenience methods including getter methods for the bodyContent property and

 * methods to get at the previous out JspWriter.

 * <p>

 * Many tag handlers will extend BodyTagSupport and only redefine a few methods.

 */

public class BodyTagSupport extends TagSupport implements BodyTag {

 

 

3.7 传统标签接口中的各个方法可以返回的返回值说明

 

 

在现在的jsp标签开发中,很少直接使用传统标签来开发了,目前用得较多的都是简单标签,所以Jsp的传统标签开发了解一下即可

3.8 SimpleTag

 

/**

 * Interface for defining Simple Tag Handlers.

 *

 * <p>Simple Tag Handlers differ from Classic Tag Handlers in that instead

 * of supporting <code>doStartTag()</code> and <code>doEndTag()</code>,

 * the <code>SimpleTag</code> interface provides a simple

 * <code>doTag()</code> method, which is called once and only once for any

 * given tag invocation.  All tag logic, iteration, body evaluations, etc.

 * are to be performed in this single method.  Thus, simple tag handlers

 * have the equivalent power of <code>BodyTag</code>, but with a much

 * simpler lifecycle and interface.</p>

 

 ..................

 

 * @see SimpleTagSupport

 * @since 2.0

 */

public interface SimpleTag extends JspTag {

 

 

 

 

 

SimpleTag接口

 

SimpleTag接口是JSP2.0中新增的一个标签接口。由于传统标签使用三个标签接口来完成不同的功能,显得过于繁琐,不利于标签技术的推广,因此,SUN公司为降低标签技术的学习难度,在JSP  2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口。SimpleTag接口与传统标签接口最大的区别在于,SimpleTag接口只定义了一个用于处理标签逻辑的doTag方法,该方法在WEB容器执行自定义标签时调用,并且只被调用一次。那些使用传统标签接口所完成的功能,例如是否执行标签体、迭代标签体、对标签体内容进行修改等功能都可以在doTag方法中完成。

 

JSP  API中也提供了SimpleTag接口的实现类SimpleTagSupport,我们在编写简单标签时,可以继承和扩展SimpleTagSupport类,这相比实现SimpleTag接口将简化开发工作

 

3.9 SimpleTagSupport

/**

 * A base class for defining tag handlers implementing SimpleTag.

 * <p>

 * The SimpleTagSupport class is a utility class intended to be used

 * as the base class for new simple tag handlers.  The SimpleTagSupport

 * class implements the SimpleTag interface and adds additional

 * convenience methods including getter methods for the properties in

 * SimpleTag.

 *

 * @since 2.0

 */

public class SimpleTagSupport implements SimpleTag {

 

 

3.10 JspFragment

/**

 * Encapsulates a portion of JSP code in an object that

 * can be invoked as many times as needed.  JSP Fragments are defined

 * using JSP syntax as the body of a tag for an invocation to a SimpleTag

 * handler, or as the body of a <jsp:attribute> standard action

 * specifying the value of an attribute that is declared as a fragment,

 * or to be of type JspFragment in the TLD.

 *

 *...........

 *

 * @since 2.0

 */

public abstract class JspFragment {

 

 

3.10.1 invoke()方法

/**

* Executes the fragment and directs all output to the given Writer,

* or the JspWriter returned by the getOut() method of the JspContext

* associated with the fragment if out is null.

.....*/

public abstract void invoke( Writer out )

        throws JspException, IOException;

 

<!‐‐

tld文件中有四种标签体类型 :emptyJSPscriptlesstagdepentend

在简单标签(SampleTag)中标签体bodycontent的值只允许是emptyscriptless,不允许设置成JSP,如果设置成JSP就会出现异常 在传统标签中标签体bodycontent的值只允许是emptyJSP 如果标签体bodycontent的值设置成tagdepentend,那么就表示标签体里面的内容是给标签处理器类使用的,例如:开发一个查询用户的sql标签,此时标签体重的SQL语句就是给SQL 标签的标签处理器来使用的<hx:sql>select * from user</hx:sql>在这种情况下,sql标签的<bodycontent>就要设置成tagdepentendtagdepentend用得比较少,了解一下即可

‐‐>

二、自定义标签

自定义标签除了可以移除jsp页面java代码外,它也可以实现以下功能

1、 传统标签开发

 

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

1.1.1 控制标签体的内容是否执行

1.1.1.1 创建一个类继承TagSupport

Tag1 .java

 

package com.hx.mytag;

 

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.TagSupport;

 

public class Tag1 extends TagSupport{

 

/**

 *

 */

private static final long serialVersionUID = 1L;

 

@Override

public int doStartTag() throws JspException {

 

//return super.doStartTag();//SKIP_BODY 标签体的内容不执行

return EVAL_BODY_INCLUDE;//标签体的内容执行

}

 

}

 

1.1.1.2 添加tld文件

 

这个文件我们没有必要重新写一遍,到Tomcat服务器上的\\apache-tomcat-8.0.53\\webapps\\examples\\WEB-INF\\jsp2中复制一个过来,修改名字存放到我们的项目中WEB-INF的任意子路径下。删除一些标签成如下内容

tag.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用来添加对taglib(标签库)的描述 -->

    <description>自定义标签库</description>

    <!--taglib(标签库)的版本号 -->

    <tlib-version>1.0</tlib-version>

    <short-name>HxTagLibrary</short-name>

    <!--

        为自定义标签库设置一个uri,uri以/开头,/后面的内容随便写,如这里的/hx ,

        Jsp页面中引用标签库时,需要通过uri找到标签库

        Jsp页面中就要这样引入标签库:<%@taglib uri="/hx" prefix="hx"%>

    -->

    <uri>/hx</uri>

    

    <!--一个taglib(标签库)中包含多个自定义标签,每一个自定义标签使用一个tag标记来描述  -->

    <!-- 一个tag标记对应一个自定义标签 -->

     <tag>

        <description>这个标签的作用是用来输出HelloWorld</description>

        <!--

            为标签处理器类配一个标签名,在Jsp页面中使用标签时是通过标签名来找到要调用的标签处理器类的

            通过name就能找到对应的类tag-class

         -->

        <name>tag1</name>

        <!-- 标签对应的处理器类-->

        <tag-class>com.hx.mytag.Tag1</tag-class>

        <body-content>jsp</body-content>

        <!--

        <body-content></body-content>标签体

        <attribute></attribute>属性

         -->

    </tag>

    

</taglib>

 

1.1.1.3 jsp页面是如何使用标签

<%@ taglib uri="tld文件中指定的唯一标识" prefix="指定标签前缀"%>

我们看到这个导入标签库的编译指令主要有两个属性,一个是用于定位我们已经写好的标签库,定位的方法就是读取每个tld文件中的URI元素的值,prefix用于指定我们使用标签时的前缀

<刚刚指定的前缀 :标签名 />

 

tag1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib  uri="/hx" prefix="h"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

</head>

<body>

<h:tag1>

<h1>Hello World</h1>

</h:tag1>

</body>

</html>

 

 

自定义标签类  doStartTag方法 return EVAL_BODY_INCLUDE

 

 

自定义标签类  doStartTag方法 return  SKIP_BODY 

 

 

 

 

1.1.2 控制标签后的jsp是否执行

那之前的Tag1.java添加doEndTag()方法

package com.hx.mytag;

 

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.TagSupport;

 

public class Tag1 extends TagSupport{

 

/**

 *

 */

private static final long serialVersionUID = 1L;

 

@Override

public int doStartTag() throws JspException {

 

//return super.doStartTag();//SKIP_BODY 标签体的内容不执行

//EVAL_BODY_INCLUDE 标签体的内容执行

 

return EVAL_BODY_INCLUDE;

}

 

@Override

public int doEndTag() throws JspException {

 

//return super.doEndTag();//EVAL_PAGE 标签后面的内容执行

return SKIP_PAGE;

}

}

 

 

tld配置不需要改

 

tag1.jsp

 

<%@ page language="java" contentType="text/html; charset=UTF-8"

    pageEncoding="UTF-8"%>

<%@ taglib  uri="/hx" prefix="h"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

</head>

<body>

<h:tag1>

<h1>Hello World</h1>

</h:tag1>

 

<span>Hello everybody</span>

</body>

</html>

 

自定义标签类  doEndTag方法 return  EVAL_PAGE 

 

 

自定义标签类  doEndTag方法 return SKIP_PAGE 

 

 

 

1.2 控制jsp页面内容重复执行

Tag2 .java

package com.hx.mytag;

 

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.TagSupport;

 

public class Tag2 extends TagSupport {

 

int count = 3;

/**

 *

 */

private static final long serialVersionUID = 1L;

 

@Override

public int doStartTag() throws JspException {

 

// return super.doStartTag();//SKIP_BODY 标签体的内容不执行

// EVAL_BODY_INCLUDE 标签体的内容执行

 

return EVAL_BODY_INCLUDE;

}

/*

 * 控制doAfterBody()方法的返回值, 如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体,

 * 依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重 复执行。

 *

 * @see javax.servlet.jsp.tagext.TagSupport#doAfterBody()

 */

@Override

public int doAfterBody() throws JspException {

count--;

if (count > 0) {

return EVAL_BODY_AGAIN;

}

return SKIP_BODY;

// return super.doAfterBody();//SKIP_BODY

}

 

}

 

在之前的tld文件中加入下面代码,<tag>元素与<tag>元素同级

<tag>

        <description>循环输出标签体的内容</description>

        <name>tag2</name>

        <tag-class>com.hx.mytag.Tag2</tag-class>

        <body-content>JSP</body-content>

    </tag>

tag2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"

pageEncoding="UTF-8"%>

<%@ taglib uri="/hx" prefix="h"%>

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

</head>

<body>

<h:tag2>

<h1>Hello World</h1>

&l

以上是关于JSP标签介绍,自定义标签的主要内容,如果未能解决你的问题,请参考以下文章

自定义JSP中的Taglib标签之四自定义标签中的Function函数

JSP 自定义标签

JSP2 的自定义标签

JSP自定义标签开放入门

JSP-Runoob:JSP 自定义标签

jsp自定义标签