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_INCLUDE或SKIP_BODY。如果doStartTag方法返回EVAL_BODY_INCLUDE,WEB容器就会接着执行自定义标签的标签体;如果doStartTag方法返回SKIP_BODY,WEB容器就会忽略自定义标签的标签体,直接解释执行自定义标签的结束标记。
2.WEB容器解释执行到自定义标签的结束标记时,就会调用标签处理器的doEndTag方法,doEndTag方法执行完后可以向WEB容器返回常量EVAL_PAGE或SKIP_PAGE。如果doEndTag方法返回常量EVAL_PAGE,WEB容器就会接着执行JSP页面中位于结束标记后面的JSP代码;如果doEndTag方法返回SKIP_PAGE,WEB容器就会忽略JSP页面中位于结束标记后面的所有内容。从doStartTag和doEndTag方法的作用和返回值的作用可以看出,开发自定义标签时可以在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接口有Tag和SimpleTag两个直接子接口,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_AGAIN或SKIP_BODY。如果doAfterBody方法返回EVAL_BODY_AGAIN,WEB容器就会把标签体内容再重复执行一次,执行完后接着再调用doAfterBody方法,如此往复,直到doAfterBody方法返回常量SKIP_BODY,WEB容器才会开始处理标签的结束标记和调用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接口的基础上增加了两个 方法(setBodyContent、doInitBody)和一个EVAL_BODY_BUFFERED常量。实现 BodyTag接口的标签除了可以完成IterationTag接口所能完成的功能,还可以对标签体内容进行修改。对于实现了BodyTag接口的自定义标签,标签处理器的doStartTag方法 不仅可以返回前面讲解的常量EVAL_BODY_INCLUDE或SKIP_BODY,还可以返回常量 EVAL_BODY_BUFFERED。如果doStartTag方法返回EVAL_BODY_BUFFERED,WEB容器就 会创建一个专用于捕获标签体运行结果的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)中标签体body‐content的值只允许是empty和scriptless,不允许设置成JSP,如果设置成JSP就会出现异常 在传统标签中标签体body‐content的值只允许是empty和JSP 如果标签体body‐content的值设置成tagdepentend,那么就表示标签体里面的内容是给标签处理器类使用的,例如:开发一个查询用户的sql标签,此时标签体重的SQL语句就是给SQL 标签的标签处理器来使用的<hx:sql>select * from user</hx:sql>在这种情况下,sql标签的<body‐content>就要设置成tagdepentend,tagdepentend用得比较少,了解一下即可
‐‐>
二、自定义标签
自定义标签除了可以移除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标签介绍,自定义标签的主要内容,如果未能解决你的问题,请参考以下文章