javaweb学习总结(二十四)——jsp传统标签开发

技术标签: jsp传统标签  javaweb

一、标签技术的API

1.1、标签技术的API类继承关系

  

二、标签API简单介绍

2.1、JspTag接口

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

2.2、Tag接口

  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页面中位于自定义标签的结束标记后面的内容。

2.3、IterationTag接口

  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接口将简化开发工作。

2.4、BodyTag接口

  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接口将简化开发工作。

2.5、 SimpleTag接口

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

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

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

  下图列举了Tag接口、IterationTag接口和BodyTag接口中的主要方法及它们分别可以返回的返回值的说明。

  

三、开发传统标签实现页面逻辑

  开发人员在编写Jsp页面时,经常还需要在页面中引入一些逻辑,例如:

  • 控制jsp页面某一部分内容是否执行。
  • 控制整个jsp页面是否执行。
  • 控制jsp页面内容重复执行。
  • 修改jsp页面内容输出。

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

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

  编写一个类实现tag接口,控制doStartTag()方法的返回值,如果这个方法返回EVAL_BODY_INCLUDE,则执行标签体,如果返回SKIP_BODY,则不执行标签体。

  SUN公司针对tag接口提供了一个默认的实现类TagSupport,TagSupport类中实现了tag接口的所有方法,因此我们可以编写一个类继承TagSupport类,然后再重写doStartTag方法。

示例代码如下:

TagDemo1.java

复制代码
 1 package me.gacl.web.tag;
 2 
 3 import javax.servlet.jsp.JspException;
 4 import javax.servlet.jsp.tagext.Tag;
 5 import javax.servlet.jsp.tagext.TagSupport;
 6 
 7 /**
 8  * @author gacl
 9  * TagSupport类实现了Tag接口,TagDemo1继承TagSupport类
10  * 
11  */
12 public class TagDemo1 extends TagSupport {
13 
14     /* 重写doStartTag方法,控制标签体是否执行
15      * @see javax.servlet.jsp.tagext.TagSupport#doStartTag()
16      */
17     @Override
18     public int doStartTag() throws JspException {
19         //如果这个方法返回EVAL_BODY_INCLUDE,则执行标签体,如果返回SKIP_BODY,则不执行标签体
20         //return Tag.EVAL_BODY_INCLUDE;
21         return Tag.SKIP_BODY;
22     }
23 }
复制代码

  在WEB-INF目录下的tld文件中添加对该标签处理类的描述,如下:

1 <tag>
2         <name>demo1</name>
3         <tag-class>me.gacl.web.tag.TagDemo1</tag-class>
4         <!--demo1标签有标签体,所以这里的body-content设置为JSP-->
5         <body-content>JSP</body-content>
6 </tag>

  在jsp页面中导入并使用自定义标签,如下:

复制代码
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <%--在jsp页面中导入自定义标签库 --%>
 3 <%@taglib uri="/gacl" prefix="gacl" %>
 4 <!DOCTYPE HTML>
 5 <html>
 6   <head>
 7     <title>控制标签体是否执行</title>
 8   </head>
 9   
10   <body>
11   <%--在jsp页面中使用自定义标签 demo1标签是带有标签体的,标签体的内容是"孤傲苍狼"这几个字符串--%>
12     <gacl:demo1>
13         孤傲苍狼
14     </gacl:demo1>
15   </body>
16 </html>
复制代码

  运行效果如下:

 

3.2、控制整个jsp页面是否执行

  编写一个类实现tag接口,控制doEndTag()方法的返回值,如果这个方法返回EVAL_PAGE,则执行标签余下的jsp页面,如果返回SKIP_PAGE,则不执行余下的jsp。

示例代码如下:

TagDemo2.java

复制代码
 1 package me.gacl.web.tag;
 2 
 3 import javax.servlet.jsp.JspException;
 4 import javax.servlet.jsp.tagext.Tag;
 5 import javax.servlet.jsp.tagext.TagSupport;
 6 
 7 /**
 8  * @author gacl
 9  * TagSupport类实现了Tag接口,TagDemo2继承TagSupport类
10  */
11 public class TagDemo2 extends TagSupport{
12 
13     /* 重写doEndTag方法,控制jsp页面是否执行
14      * @see javax.servlet.jsp.tagext.TagSupport#doEndTag()
15      */
16     @Override
17     public int doEndTag() throws JspException {
18         //如果这个方法返回EVAL_PAGE,则执行标签余下的jsp页面,如果返回SKIP_PAGE,则不执行余下的jsp
19         return Tag.SKIP_PAGE;
20         //return Tag.EVAL_PAGE;
21     }
22 
23     
24 }
复制代码

  在WEB-INF目录下的tld文件中添加对该标签处理类的描述,如下:

1 <tag>
2         <name>demo2</name>
3         <tag-class>me.gacl.web.tag.TagDemo2</tag-class>
4         <!--demo2标签没有标签体,所以这里的body-content设置为empty-->
5         <body-content>empty</body-content>
6 </tag>

  在jsp页面中导入并使用自定义标签,如下:

复制代码
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <%--在jsp页面中导入自定义标签库 --%>
 3 <%@taglib uri="/gacl" prefix="gacl" %>
 4 <!DOCTYPE HTML>
 5 <html>
 6   <head>
 7     <title>控制jsp页面是否执行</title>
 8   </head>
 9   
10   <body>
11          <h1>jsp页面的内容1</h1>
12          <%--在jsp页面中使用自定义标签 demo2标签是不带标签体的--%>
13          <gacl:demo2/>
14          <h1>jsp页面的内容2</h1>
15   </body>
16 </html>
复制代码

  运行效果如下:

 

3.3、控制jsp页面内容重复执行

  编写一个类实现Iterationtag接口,控制doAfterBody()方法的返回值,如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体,依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重复执行。

示例代码如下:

TagDemo3.java

复制代码
 1 package me.gacl.web.tag;
 2 
 3 import javax.servlet.jsp.JspException;
 4 import javax.servlet.jsp.tagext.IterationTag;
 5 import javax.servlet.jsp.tagext.Tag;
 6 import javax.servlet.jsp.tagext.TagSupport;
 7 
 8 public class TagDemo3 extends TagSupport {
 9 
10     int x = 5;
11     @Override
12     public int doStartTag() throws JspException {
13         return Tag.EVAL_BODY_INCLUDE;
14     }
15     
16     /* 控制doAfterBody()方法的返回值,
17      * 如果这个方法返回EVAL_BODY_AGAIN, 则web服务器又执行一次标签体,
18      * 依次类推,一直执行到doAfterBody方法返回SKIP_BODY,则标签体才不会重复执行。
19      * @see javax.servlet.jsp.tagext.TagSupport#doAfterBody()
20      */
21     @Override
22     public int doAfterBody() throws JspException {
23         x--;
24         if(x>0){
25             return IterationTag.EVAL_BODY_AGAIN;
26         }else{
27             return IterationTag.SKIP_BODY;
28         }
29     }
30 
31 }
复制代码

  在WEB-INF目录下的tld文件中添加对该标签处理类的描述,如下:

1 <tag>
2         <name>demo3</name>
3         <tag-class>me.gacl.web.tag.TagDemo3</tag-class>
4         <!--demo3标签有标签体,所以这里的body-content设置为JSP-->
5         <body-content>JSP</body-content>
6 </tag>

  在jsp页面中导入并使用自定义标签,如下:

复制代码
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <%--在jsp页面中导入自定义标签库 --%>
 3 <%@taglib uri="/gacl" prefix="gacl" %>
 4 <!DOCTYPE HTML>
 5 <html>
 6   <head>
 7     <title>控制页面内容重复执行5次</title>
 8   </head>
 9   
10   <body>
11   <%--在jsp页面中使用自定义标签 demo3标签--%>
12       <gacl:demo3>
13           <h3>jsp页面的内容</h3>
14       </gacl:demo3>
15   </body>
16 </html>
复制代码

  运行效果如下:

  

3.4、修改jsp页面内容输出

  编写一个类实现BodyTag接口,控制doStartTag()方法返回EVAL_BODY_BUFFERED,则web服务器会创建BodyContent对象捕获标签体,然后在doEndTag()方法体内,得到代表标签体的bodyContent对象,从而就可以对标签体进行修改操作。

  SUN公司针对BodyTag接口提供了一个默认的实现类BodyTagSupport,BodyTagSupport类中实现了BodyTag接口的所有方法,因此我们可以编写一个类继承BodyTagSupport类,然后再根据需要重写doStartTag方法和doEndTag()方法。

示例代码如下:

TagDemo4.java

复制代码
 1 package me.gacl.web.tag;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.jsp.JspException;
 6 import javax.servlet.jsp.tagext.BodyContent;
 7 import javax.servlet.jsp.tagext.BodyTag;
 8 import javax.servlet.jsp.tagext.BodyTagSupport;
 9 import javax.servlet.jsp.tagext.Tag;
10 
11 /**
12  * @author gacl
13  * BodyTagSupport类实现了BodyTag接口接口,TagDemo4继承 BodyTagSupport类
14  */
15 public class TagDemo4 extends BodyTagSupport {
16 
17     /* 控制doStartTag()方法返回EVAL_BODY_BUFFERED
18      * @see javax.servlet.jsp.tagext.BodyTagSupport#doStartTag()
19      */
20     @Override
21     public int doStartTag() throws JspException {
22         return BodyTag.EVAL_BODY_BUFFERED;
23     }
24     
25     @Override
26     public int doEndTag() throws JspException {
27         
28         //this.getBodyContent()得到代表标签体的bodyContent对象
29         BodyContent bodyContent = this.getBodyContent();
30         //拿到标签体
31         String content = bodyContent.getString();
32         //修改标签体里面的内容,将标签体的内容转换成大写
33         String result = content.toUpperCase();
34         try {
35             //输出修改后的内容
36             this.pageContext.getOut().write(result);
37         } catch (IOException e) {
38             throw new RuntimeException(e);
39         }
40         
41         return Tag.EVAL_PAGE;
42     }
43 }
复制代码

  在WEB-INF目录下的tld文件中添加对该标签处理类的描述,如下:

1 <tag>
2         <name>demo4</name>
3         <tag-class>me.gacl.web.tag.TagDemo4</tag-class>
4         <!--demo4标签有标签体,所以这里的body-content设置为JSP-->
5         <body-content>JSP</body-content>
6 </tag>

  在jsp页面中导入并使用自定义标签,如下:

复制代码
 1 <%@ page language="java" pageEncoding="UTF-8"%>
 2 <%--在jsp页面中导入自定义标签库 --%>
 3 <%@taglib uri="/gacl" prefix="gacl" %>
 4 <!DOCTYPE HTML>
 5 <html>
 6   <head>
 7     <title>修改jsp页面内容输出</title>
 8   </head>
 9   
10   <body>
11   <%--在jsp页面中使用自定义标签 demo4标签--%>
12       <gacl:demo4>
13           <h3>xdp_gacl</h3>
14       </gacl:demo4>
15   </body>
16 </html>
复制代码

  运行效果如下:

  

四、jsp传统标签开发总结

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

来源:网络


智能推荐

JavaWeb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册

一、Servlet+JSP+JavaBean开发模式(MVC)介绍   Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp负责数据显示,javabean负责封装数据。 Servlet+JSP+JavaBean模式程序各个模块之间层次清晰,web开发推荐采用此种模式。   这里以一个最常用的用户登录注册程序来讲解Ser...

JavaWeb学习总结—jsp

二 Jsp 1)Jsp和Servlet很相似,最终编译成的.java文件也含有类似于init,destroy,service的方法,这在项目部署后的work文件夹下可以看到; 2)Jsp的语法是<%%>,中间可以写java代码,也可以写字符串,字符串要带等号,如<%="哈哈"%>; 3)Jsp的注释语法是<%--  --%>,使用J...

java基础学习总结(二十四):slf4j作用及其实现原理

简单回顾门面模式 slf4j是门面模式的典型应用,因此在讲slf4j前,我们先简单回顾一下门面模式, 门面模式,其核心为外部与一个子系统的通信必须通过一个统一的外观对象进行,使得子系统更易于使用。用一张图来表示门面模式的结构为:   门面模式的核心为Facade即门面对象,门面对象核心为几个点: 大致上来看,对门面模式的回顾到这里就可以了,开始接下来对SLF4J的学习。 知道所有子角色的...

Python学习的第二十四天(总结之前飞机大战的操作)

一 游戏循环外,初始化相关对象 创建屏幕对象 创建屏幕对象 创建背景图片对象 背景图片 创建游戏角色图片对象 我方飞机 创建时钟对象 二 游戏循环内,游戏的主逻辑 先修改图片对象的坐标 如何修改图片对象的坐标了 当前的图片对象象,把坐标,保存在了一个矩形对象中 通过矩形对象.x可以得到x坐标数据 如果 矩形对象.x = n 就可以修改数据 坐标怎么修改? 这需要根据需求了 可按照情况来处理坐标的修...

二十四

java基础1 1— java的技术内容 分三个部分:JDK,JRE,JVM JDK是java开发人员使用的,可以开发并运行Java程序,其中包含了JRE和JVM JRE是java程序运行环境,计算机安装后可以运行java程序 JVM是java虚拟机,通过JVM可以实现java跨平台运行。 2---- dos命令行 运行:Windows键+R cmd:进入doc命令行 验证环境配置:j...

猜你喜欢

windows内核开发学习笔记二十四:windows内核架构

从上图上可以看出,windows内核主要层次划分为三个层次,以及windows子系统、文件系统、网络、设备驱动程序等几个部分。  硬件抽象层(Hardware Abstraction Layer,简称HAL):主要是把所有与硬件相关联的代码隔离到一个专门模块中,从而使上面的层次尽可能做到独立于硬件平台。 内核层或微内核层(micro-kernel):位于HAL硬件抽象层之上,主要包含了基...

SQL2005学习(二十四),Select用法四

在Where之句中,如果需要确定表达式的取值是否属于某一列表值之一时,可以使用关键字IN或者NOT IN来限定查询条件,其语法格式如下。 Where Expression [Not] In Value_list,其中NOT是可选值,而Value_list表示列表值,当值不止一个时需要用括号括起来,各列表值用逗号分开。 如下图,有一张学生信息表,总共有232行   现在我要在学生信息表中查...

快学Big Data -- Spark SQL总结(二十四)

Spark  SQL 总结 概述 Spark  Sql 是用来处理结构化数据的一个模块,它提供了一个编程抽象叫做DataFrame并且作为分布式SQL查询引擎的作用。 特点 spark  sql 要比hive执行的速度要快,原因在于spark sql不用通过mapreduce来执行程序,减少了执行的复杂性。 Spark sql 可以将数据转化为RDD(内存中),大大提...

spring总结(二十四)--注释的方式配置事务

目录   说明  1、本文代码  2、事务简介 3、简单理解事务 代码前期准备 用注释的方式使用事务 配置ApplicationContext 添加注解 说明  1、本文代码         可以参考来自spring总结(二十三)--使用JdbcTemplate和JdbcDaoSupport。    ...

原型对象,原型链

函数都有prototype属性,它指向原型对象。 实例对象有__proto__属性,它指向对象原型 每一个原型对象都有constructor输赢,指向构造函数,每一个原型对象又具有__proto__属性,这个指向Object.prototype.在这里插入图片描述...

问答精选

Correctly formatting GCM notifications?

I'm currently trying out the google cloud messaging service with its sample application "Guestbook." https://developers.google.com/cloud/samples/mbs/ I'm attempting to send notifications tha...

Are there any performance benefits of using Asynchronous functions over Synchronous in Node Js?

Now I came across an article that distinguishes between an Asynchronous function and Synchronous functions. From my understanding of the different examples and explanations, synchronous functions are ...

Python: Costing calculator output

Good day all I'm busy creating a small costing calculator for the signage department. I'm not getting the calculator to output the amount. Brief Description: You enter the height and width and then wh...

Flask-SQLAlchemy - model has no attribute 'foreign_keys'

I have 3 models created with Flask-SQLalchemy: User, Role, UserRole role.py: user.py: user_role.py: If I try (in the console) to get all users via User.query.all() I get AttributeError: 'NoneType' obj...

Seeding many PRNGs, then having to seed them again, what is a good quality approach?

I have many particles that follow an stochastic process in parallel. For each particle, there is a PRNG associated to it. The simulation must go through many repetitions to get average results. For ea...

相关问题

相关文章

热门文章

推荐文章

相关标签

推荐问答