返回

Java精选笔记_自定义标签

发布时间:2022-09-30 14:35:02 318
# php# java# 数据# 技术# 信息

自定义标签

自定义标签入门

什么是自定义标签

自定义标签可以有效地将HTML代码与Java代码分离,从而使不懂Java编程的HTML设计人员也可以编写出功能强大的JSP页面

JSP规范中定义了多个用于开发自定义标签的接口和类,它们都位于javax.servlet.jsp.tagext包中

JSP自定义标签是用户定义的JSP语言元素,可以看成是一种通过标签处理器生成基于XML脚本的方法。

自定义标签在功能上和逻辑上都与JavaBean类似,都是一组可重用的组件代码。相较于JavaBean,自定义标签可以使Web开发者可以完全从Java编程中脱离开来,专注于页面显示和格式上面去,所以具有广阔的发展前景。

自定义标签的构成

一个自定义标签一般由JavaBean、标签库描述、标签处理器、web.xml文件配置、标签库声明等元素所构成。

自定义标签声明

当JSP页面中引用自定义标签时,用来在页面上对自定义标签进行声明的。

taglib编译指令的作用主要是定义一个标签库路径及其前缀

<%@ taglib="URLToTagLibrary" prefix="tagPrefix"%>

标签库描述符文件

是一个描述标签库的XML文档

TLD包含有关整个库以及库中包含的每一个标签的信息。它把自定义标签与对应的处理程序关联起来。TLD文件名称必须扩展名为.tld。

TLD文件存储在Web模块的WEB-INF目录下或者子目录下,并且一个标签库要对应一个标签库描述文件,而在一个描述文件中可以包含多个自定义标签的声明

子元素

元素

说明 元素 说明

用于设置标签库版本 用于设置标签库的可选小图标

用于设置标签库要求的JSP规范版本 用于设置标签库的可选大图标

用于设置该标签库的助记名 用于设置标签库的描述信息

唯一标识该标签库的URI 用于设置标签库的监听器类

用于设置标签库显示的可选名 用于设置标签库的具体标签

真正用来查找标签库中具体标签的是元素

子元素

元素

说明 元素 说明

用于设置标签的唯一名称 用于设置标签的可选小图标

用于设置标签处理器的完全限定名 用于设置标签的可选大图标

用于设置脚本变量信息的子类名称 用于设置标签的描述信息

用于设置标签的正文内容类型 用于设置标签的脚本变量信息

用于设置标签显示的可选名 用于设置标签的属性信息

标签处理器

是一个描述标签库的XML文档

TLD包含有关整个库以及库中包含的每一个标签的信息。它把自定义标签与对应的处理程序关联起来。TLD文件名称必须扩展名为.tld。

TLD文件存储在Web模块的WEB-INF目录下或者子目录下,并且一个标签库要对应一个标签库描述文件,而在一个描述文件中可以包含多个自定义标签的声明

<taglib>子元素

元素

说明 元素 说明

<tlib-version>

用于设置标签库版本 <small-icon> 用于设置标签库的可选小图标

<jsp-version>

用于设置标签库要求的JSP规范版本 <large-icon> 用于设置标签库的可选大图标

<short-name>

用于设置该标签库的助记名 <description> 用于设置标签库的描述信息

<uri>

唯一标识该标签库的URI <listener> 用于设置标签库的监听器类

<display-name>

用于设置标签库显示的可选名 <tag> 用于设置标签库的具体标签

真正用来查找标签库中具体标签的是<tag>元素

<tag>子元素

元素

说明 元素 说明

<name>

用于设置标签的唯一名称 <small-icon> 用于设置标签的可选小图标

<tag-class>

用于设置标签处理器的完全限定名 <large-icon> 用于设置标签的可选大图标

<tei-class>

用于设置脚本变量信息的子类名称 <description> 用于设置标签的描述信息

<body-content>

用于设置标签的正文内容类型 <variable> 用于设置标签的脚本变量信息

<display-name>

用于设置标签显示的可选名 <attribute> 用于设置标签的属性信息

标签处理器

把自定义标签的主体和属性转变为HTML代码的实际工作,是由标签处理器来完成的。

标签处理器也叫标签处理类,它是一个Java类。当JSP容器编译自定义标签时,就会需要使用标签处理器类的实例。

标签处理器虽然是一个Java类,但不仅仅是一个普通的Java类,在定义时需要满足特殊的要求。开发的标签处理类必须实现Tag或者BodyTag接口类(它们包为javax.servlet.jsp.tagext)

BodyTag接口是继承了Tag接口的子接口。如果创建的自定义标签不带体式,可以实现Tag接口,但是如果创建的自定义标签带体,则需要实现BodyTag接口。

Tag接口类方法

方法名

方法描述

setPageContext(PageContext pc)

设置当前页面的上下文

setParent(Tag t)

设置这个标签处理类的父类

getParent()

获得父类

doStartTag()

处理这个实例中的开发标签

doEndTag()

处理这个实例中的结束标签

release()

由标签处理类引起,来释放状态

BodyTag子接口类重新定义了两个新方法

方法名

方法描述

setBodyContent(BodyContent b)

为体中代码作初始化

doInitBody()

为标签体中的内容设置属性

在标签处理器中定义了标签处理方法doStartTag()和doEndTag(),这两个方法分别在标签开始和结束时执行处理和输出动作。

这两个方法都要求分别返回一个状态码,通知JSP容器岁自定义标签的处理结果及整个JSP页面的运行状态

状态码一共有四种

生命周期

生成servlet需要创建标签处理器类的一个实例

初始化标签处理器,是servlet获知其存在性

如果标签具有属性,属性的取值通过处理器提供setter方法传入到对象

调用标签处理器的doStrartTag()方法并返回一个整数值

标签体被评估或忽略后调用标签处理器的doEndTag()方法

调用标签处理器的release()方法销毁标签处理器实例

自定义标签的开发步骤

1、编写标签处理器

开发自定义标签的核心任务就是要编写作为标签处理器的Java类。

传统标签开发

实现javax.servlet.jsp.tagext.Tag接口

调用doStartTag()方法

简单标签开发

实现javax.servlet.jsp.tagext.SimpleTag接口

调用doTag()方法

2、编写标签库描述符(tld)文件

要想让JSP引擎在遇到自定义标签时,能找到其所对应的标签处理器类,还必须编写一个标签库描述符(Tag Library Descriptor)文件,简称TLD文件。

一个标签处理器类要想被JSP容器找到并调用,必须在TLD文件中进行注册, 一个TLD文件中可以注册多个标签处理器类,每个自定义标签的注册名称不能相同,同一个TLD文件中注册的多个标签处理器类就形成了一个自定义标签库。

TLD文件是基于XML文件的,其内容的编写需要遵循XML语法规范。

3、在JSP页面导入和使用自定义标签

TLD文件编写完成后,就可以在JSP文件中使用自定义标签。在使用自定义标签之前,首先需要使用taglib指令来引入TLD文件

<%@taglib  uri = ""  prefix = "" %>

uri属性用于指定引用的是哪一个TLD文件,它应该和要引入的TLD文件中<uri>元素的值保持一致。

prefix属性用于为引入的TLD文件指定一个“引用代号”,在使用这个标签库中注册的自定义标签时都需要加上这个“引用代号”作为前缀。prefix属性的值可以是任意的,但不能和其它taglib指令中的prefix属性值重复,而且需要遵循XML名称空间的命名约定。

自定义标签的格式

空标签

<prefix:tagname />            // 格式1

<prefix:tagname></prefix:tagname>       // 格式2

带标签体的标签

<prefix:tagname>body</prefix:name>

带属性的标签

<prefix:tagname  attrname1 = "attrvalue1" [attrname2 = "attrvalue2" …]>
[body]
</prefix:tagname>

嵌套标签

<prefix:tagname>
<prefix:nestedtagname>
[body]
</prefix:nestedtagname>
</prefix:tagname>

传统标签

实现Tag接口的标签称为传统标签

Tag接口

是所有传统标签的父接口,它定义了四个int类型的静态常量和六个抽象方法。

定义了JSP页面与标签处理器之间的通信规则,当JSP容器将JSP页面翻译成Servlet源文件时,如果遇到JSP标签,会创建标签处理器类的实例对象,然后依次调用标签处理器的setPageContext()方法、setParent()方法、doStartTag()方法、doEndTag()方法和release()方法,因此,在实现Tag接口时,需要对这些抽象方法进行实现。

静态常量

EVAL_BODY_INCLUDE

doStartTag()方法的返回值,表示标签体会被执行

SKIP_BODY

doStartTag()方法的返回值,表示标签体不被执行

EVAL_PAGE

doEndTag()方法的返回值,表示标签后面余下的JSP页面继续执行

SKIP_PAGE

doEndTag()方法的返回值,表示标签后面余下的JSP页面不被执行

抽象方法

void setPageContext(PageContext pc)

JSP容器实例化标签处理器后,调用setPageContext()方法将JSP页面的内置对象pageContext对象传递给标签处理器,标签处理器可以通过pageContext对象与JSP页面进行通信

void setParent(Tag t)

调用setPageContext()方法后,JSP容器会调用setParent()方法将当前标签的父标签处理器对象传递给当前标签处理器,如果当前标签没有父标签,则传递给setParent()方法的参数为null

Tag getParent()

返回当前标签的父标签处理器对象,如果当前标签没有父标签则返回null

int doStartTag()

当JSP容器解析到自定义标签的开始标签时,会调用doStartTag()方法,该方法可以返回EVAL_BODY_INCLUDE和SKIP_BODY两个常量,如果使用Tag的子接口BodyTag,还可以使用BodyTag.EVAL_BODY_BUFFERED常量。

int doEndTag()

当JSP容器解析到自定义标签的结束标签时,会调用doEndTag()方法,该方法可以返回EVAL_PAGE和SKIP_PAGE两个常量

void release()

JSP容器在标签处理器对象被作为垃圾回收之前调用release()方法,以便释放标签处理器所占用的资源

IterationTag接口

对标签体的内容进行重复处理

它继承自Tag接口,在Tag接口基础上新增了一个EVAL_BODY_AGAIN常量和一个doAfterBody()方法

EVAL_BODY_AGAIN常量

是doAfterBody()方法的返回值,如果doAfterBody()方法返回该常量,JSP容器会把标签体的内容重复执行一次。

doAfterBody()方法

JSP容器在每次执行完标签体后会调用doAfterBody()方法,该方法可以返回常量SKIP_BODY和EVAL_BODY_AGAIN。如果方法返回SKIP_BODY常量,JSP容器会去执行代表结束标签的doEndTag()方法,如果返回EVAL_BODY_AGAIN,则重复执行标签体。

BodyTag接口

对标签体的内容进行处理以后再向浏览器输出

它继承自IterationTag接口,在IterationTag接口基础上新增了两个方法和一个静态常量

EVAL_BODY_B9UFFERED常量

如果标签处理器类实现了BodyTag接口,它的doStartTag()方法除了可以返回SKIP_BODY和EVAL_BODY_INCLUDE常量之外,还可以返回EVAL_BODY_BUFFERED常量。

  当doStartTag()方法返回EVAL_BODY_BUFFERED常量时,JSP容器将会创建一个javax.servlet.jsp.tagext.BodyContent对象,使用该对象来执行标签体。

setBodyContent(BodyContent b)方法

当且仅当doStartTag()方法返回EVAL_BODY_BUFFERED常量时,JSP容器才会调用setBodyContent()方法,通过该方法将BodyContent对象传递给标签处理器类使用。

doInitBody()方法

JSP容器在调用setBodyContent()方法后会调用doInitBody()方法来完成一些初始化工作,该方法的调用在标签体执行之前。其中,最重要的是setBodyContent()方法。

BodyContent类

是JspWriter类的子类,它在JspWriter的基础上增加了一个用于存储数据的缓冲区,当调用BodyContent对象的方法写数据时,数据将被写入到BodyContent内部的缓冲区中。

当标签处理器类的doStartTag()方法返回EVAL_BODY_BUFFERED常量时,JSP容器会创建一个BodyContent对象,然后调用该对象的write()方法将标签体的内容写入BodyContent对象的缓冲区中。

在BodyContent类中定义了一些用于访问缓冲区内容的方法

String getString()

以字符串的形式返回BodyContent对象缓冲区中保存的数据

Reader getReader()

返回一个关联BodyContent对象缓冲区中数据的Reader对象,通过Reader对象可以读取缓冲区中的数据

void clearBody()

用于清空BodyContent对象缓冲区中的内容

JspWriter getEnclosingWriter()

用于返回BodyContent对象中关联的JspWriter对象。当JSP容器创建BodyContent对象后,PageContext对象中的“out”属性不再指向JSP的隐式对象,而是指向新创建的BodyContent对象。同时,在BodyContent对象中会用一个JspWriter类型的成员变量enclosingWriter记住原来的隐式对象,getEnclosingWriter()方法返回的就是原始的JSP隐式对象

writerOut(Writer out)

用于将BodyContent对象中的内容写入到指定的输出流

简单标签

实现SimpleTag接口的标签称为简单标签

由于传统标签在使用三个标签接口来完成不同的功能时,显得过于繁琐,不利于标签技术的推广。

SimpleTag接口与传统标签接口最大的区别在于:SimpleTag接口中只定义了一个用于处理标签逻辑的doTag方法,该方法用于取代传统标签接口中定义的doStartTag()、doEndTag()和doAfterBody()等方法。

  doTag()方法在JSP引擎执行自定义标签时调用,并且只被调用一次,那些使用传统标签接口所能完成的功能,都在doTag()方法体内完成。

简单标签API

SimpleTag接口

是所有简单标签处理器的父接口,它共定义了5个方法

void setJspContext(JspContext pc)

用于将JSP页面的内置对象pageContext对象传递给标签处理器,标签处理器可以通过pageContext对象与JSP页面进行通信。JSPContext类是PageContext类的父类,其中定义了一些不依赖于Servlet运行环境的方法,setJspContext()方法接收的参数类型为JspContext,是为了便于将简单标签扩展应用到非Servlet运行环境中

void setParent(JspTag parent)

用于将当前标签的父标签处理器对象传递给当前标签处理器,如果当前标签没有父标签,JSP容器不会调用这个方法

JspTag getParent()

返回当前标签的父标签处理器对象,如果当前标签没有父标签则返回null

void setJspBody(JspFragment jspBody)

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

void doTag()

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

JspFragment类

它的实例对象代表JSP页面中一段JSP片段,但是这段JSP片段中不能包含JSP脚本元素

JSP容器在处理简单标签的标签体时,会把标签体内容用一个JspFragment对象表示,并调用标签处理器对象的setJspBody()方法将JspFragment对象传递给标签处理器对象,标签开发者可以根据需要调用JspFragment对象的方法来决定是否输出标签体、或者循环多次输出标签体等

两个方法

JspContext getJspContext()

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

void invoke(Writer out)

用于将标签体内容写入到指定的输出流对象out 中,如果调用该方法时传入的参数为null,JSP容器会将标签内容写入到JspContext.getOut()方法返回的输出流对象中。

SimpleTagSupport类

为了简化简单标签处理器的编写

该类实现了SimpleTag接口,它内部使用成员变量jspContext和jspBody引用了JSP容器传入的JspContext对象和JspFragment对象,并且提供了两个方法来返回这两个对象的引用

JspContext getJspContext()

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

JspFragment getJspFragment()

用于返回代表标签体的JspFragment对象

控制是否执行标签体内容

简单标签使用doTag()方法完成判断,如果用户登录,则显示用户名称,如果用户没有登录,则可以抛出javax.servlet.jsp.SkipPageException异常,用于通知JSP容器不再执行标签体内容,这等效于在传统标签的doEndTag()方法中返回SKIP_PAGE常量。

控制是否执行JSP页面的内容

假设一个网站要求只能通过本网站中的超链接来访问某些JSP页面时,如果直接访问这些JSP页面或者通过非本网站的超链接来访问这些JSP页面,那么被访问的JSP页面应该停止执行其中的内容,此现象称为防盗链。

简单标签的属性

如果多个JSP页面都需要防盗链功能,则需要将用户的访问请求重定向到不同的页面。

  这时,为了提高标签的灵活性和复用性,在JSP页面使用自定义标签时,可以通过设置属性为标签处理器传递参数信息。

例如,可以为标签增加一个url属性,通过该属性指定重定向的页面

    要想为自定义标签设置属性,通常需要完成两件任务,具体如下:

1、在标签处理器类中,为每一个属性定义对应的成员变量并定义setter()方法

自定义标签每个属性都必须按照JavaBean的属性定义方式,默认情况下,自定义标签的属性值为静态文本,当setter()方法的参数为String类型时,JSP容器会直接将属性值作为一个字符串传递给该方法。如果setter()方法中的参数类型为基本数据类型,JSP容器在调用setter()方法之前会先将属性值进行转换。

例如在JSP页面中使用了如下所示的标签:

而标签处理器类中定义的setter方法如下所示:

public void setAttr(int attr)

当JSP容器在处理attr属性时,会先调用Integer. value("123")方法将字符串“123”转换为整数123,之后再作为参数传递给标签处理器类的setAttr()方法。

2、在TLD文件中声明每个标签的属性信息

在TLD文件中,标签有一个子元素用于描述自定义标签的属性,自定义标签的每个属性都必须要有一个对应的元素

在元素中还包含了一些子元素

description

用于描述属性的描述信息

name

用于指定属性的名称,属性名大小写敏感,且不能以jsp、_jsp、java、和sun开头

required

用于指定在JSP页面调用自定义标签时是否必须设置这个属性。其取值包括true和false,true表示必须设置,false表示设不设置均可。默认值为false

rtexprvalue

rtexprvalue是runtime expression value(运行时表达式)的简称,用于指定属性的值为静态还是动态。其取值包括true和false,true表示属性值可以为一个动态元素,比如一个脚本表达式<%=value%>,false表示属性值只能为静态文本值,比如“abc”。默认值为false

type

用于指定属性值的类型

子元素用于指定属性的名称,其值必须进行设置,而且属性名称一定要和jsp页面中自定义标签属性名一致,其它的子元素则可以设置也可以不用设置。

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线
下一篇
HTML&amp;CSS精选笔记_浮动与定位 2022-09-30 14:16:55