[转]JSP自定义标签
当jsp的内置标签和jstl标签库内的标签都满足不了需求,这时候就需要开发者自定义标签。
自定义标签
下面我们先来开发一个自定义标签,然后再说它的原理吧!
自定义标签的开发步骤
步骤一
编写一个普通的java类,继承TagSupport类~
- package com.vmaxtam.dotest;
- import javax.servlet.jsp.tagext.TagSupport;
- public class MyTagTest extends TagSupport {
- }
步骤二
重写父类的setPageContext方法,用于得到当前jsp页面的pageContext对象。
- public class MyTagTest extends TagSupport {
- private PageContext pageContext;
- @Override
- public void setPageContext(PageContext pageContext) {
- this.pageContext=pageContext;
- }
- }
步骤三
重写父类的doStartTag方法,里面写上你定义的标签的java操作,这里我定义的标签用作向浏览器输出一大段信息:
- @Override
- public int doStartTag() throws JspException {
- try {
- pageContext.getResponse().getWriter().write("这是我写的一大段信息:ABCDEFGHIJKLMNOPQRSTUVWXYZ");
- } catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
- return super.doStartTag();
- }
这样就完成一个标签处理程序了~别着急,写完程序我们还需要注册它。
步骤四
在你的web应用目录下,找到WEB-INF文件夹,在里面新建一个tld类型的文件
然后再里面注册你的标签吧:
- <?xml version="1.0" encoding="ISO-8859-1" ?>
- <!DOCTYPE taglib
- PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
- "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
- <taglib>
- <tlib-version>1.0</tlib-version><!-- 代表标签库的版本号 -->
- <jsp-version>1.2</jsp-version><!-- 代表jsp的版本 -->
- <short-name>mtt</short-name><!-- 你的标签库的简称 -->
- <uri>http://vmaxtam.com/mytag</uri><!-- 你标签库的引用uri -->
- <tag>
- <name>mytah</name><!-- 你定义的标签的名称 -->
- <tag-class>com.vmaxtam.dotest.MyTagTest</tag-class><!-- 对应的标签处理程序:包名+类名 -->
- <body-content>JSP</body-content><!-- 标签体内容的格式 -->
- </tag>
- </taglib>
如果你忘记了怎么写,可以参考jstl里的tld文件~
步骤五
你要在使用你定义的标签的jsp页面导入你的标签库!就像导入类包一样
只需在jsp页面写上下面内容:
- <%@taglib uri="http://vmaxtam.com/mytag" prefix="mmt" %>
步骤6
以上5步已经把准备工作都做好了~下面我们来使用标签吧!
- <html>
- <head>
- <title>My JSP 'testit.jsp' starting page</title>
- </head>
- <body>
- <mmt:mytag></mmt:mytag>
- </body>
- </html>
浏览器效果如下:
这样,我们就完成了一次自定义标签了,虽然我们知道步骤,但是不知道为什么这样就行,所以,下面来说一下它的原理:
自定义标签的原理
1)当服务器打开时,就会加载WEB-INF下的资源文件,包括web.xml 和 tld文件,把它们加载到内存
2)我们在浏览器输入http://localhost:8080/TestArea/testit.jsp来访问jsp页面
3)服务器读取testit.jsp里的内容,当读到
- <%@taglib uri="http://vmaxtam.com/mytag" prefix="mmt" %>
这一句的时候,就会在内存中找是否存在uri为http://vmaxtam.com/mytag的tld文件,找不到就会报错
4)继续读取jsp页面,读到<mmt:mytag>这个标签的时候,就会通过uri去找到tld文件,在tld文件中找到mytab是否被定义,是的话就得到它的tag-class的内容,然后去找到它对应的标签处理程序
5)实例化标签处理程序,利用生成的对象调用它里面的方法
这里服务器对标签处理程序里的方法也有一定的调用顺序
- A)void setPageContext(PageContext pc) --传入pageContext对象
- B)void setParent(Tag t) --如果有父标签,传入父标签对象,如果没有,则传入null
- C)int doStartTag() --开始执行标签时调用。
- D)int doEndTag() --结束标签时调用
- E)void release() --释放资源
如果你没有重写上面的方法,系统将会调用它的父类里的方法~
为什么会是这个顺序调用,是有证据的,下面我们来看看jsp被翻译为java源文件里的截取:
- private boolean _jspx_meth_itcast_005fshowIp_005f0(PageContext _jspx_page_context)
- throws Throwable {
- PageContext pageContext = _jspx_page_context;
- JspWriter out = _jspx_page_context.getOut();
- // itcast:showIp
- 1) 实例化ShowIpTag对象 gz.itcast.tag.ShowIpTag _jspx_th_itcast_005fshowIp_005f0 = (gz.itcast.tag.ShowIpTag) _005fjspx_005ftagPool_005fitcast_005fshowIp_005fnobody.get(gz.itcast.tag.ShowIpTag.class);
- 2)调用setPageContext方法_jspx_th_itcast_005fshowIp_005f0.setPageContext(_jspx_page_context);
- 3)调用setParent方法_jspx_th_itcast_005fshowIp_005f0.setParent(null);
- 4)调用doStartTag方法 int _jspx_eval_itcast_005fshowIp_005f0 = _jspx_th_itcast_005fshowIp_005f0.doStartTag();
- 5)调用doEndTag方法
if (_jspx_th_itcast_005fshowIp_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {- _005fjspx_005ftagPool_005fitcast_005fshowIp_005fnobody.reuse(_jspx_th_itcast_005fshowIp_005f0);
- return true;
- }
- _005fjspx_005ftagPool_005fitcast_005fshowIp_005fnobody.reuse(_jspx_th_itcast_005fshowIp_005f0);
- return false;
- }
控制标签体内容 与 结束标签后的内容
自定义标签可以可控制标签体内的文本 和 结束标签后的文本是否输出~
- @Override//遇到开始标签时执行的方法
- public int doStartTag() throws JspException {
- //return Tag.SKIP_BODY; //标签体内容不向浏览器输出
- return Tag.EVAL_BODY_INCLUDE;//标签体内容向浏览器输出
- }
- @Override//遇到结束标签后执行的方法
- public int doEndTag() throws JspException {
- //return Tag.EVAL_PAGE;//结束标签后的内容输出到浏览器
- return Tag.SKIP_PAGE;//结束标签后的内容不输出到浏览器
- }
那么如何重复输出标签体内的文本内容呢?TagSupper还提供了一个doAftetBody方法,我们只需要这样做:
- int i = 4;
- @Override//每输出一次标签体的内容都会调用一次这个方法
- public int doAfterBody() throws JspException {
- while(true)
- {
- if(i>0)
- {
- i--;
- return IterationTag.EVAL_BODY_AGAIN;//再执行一次便签体内的内容
- }else{
- break;
- }
- }
- return Tag.SKIP_BODY;//不输出标签体的内容
- }
以上的内容都是控制标签体的内容输出的问题,那么能不能改变标签体力的内容呢?
很可惜,用TagSupport是不行,但是我们可以用它的子类BodyTagSupport,那么久写一个类继承BodyTagSupport类吧~
- public class MyTagTest extends BodyTagSupport {
- private PageContext pageContext;
- @Override
- public void setPageContext(PageContext pageContext) {
- this.pageContext = pageContext;
- }
- @Override
- public int doStartTag() throws JspException {
- //返回BodyTag.EVAL_BODY_BUFFERED,表示输出标签体内容
- //返回Tag.SKIP_BODY,表示不输出内容
- return BodyTag.EVAL_BODY_BUFFERED;
- //return Tag.SKIP_BODY;
- }
- @Override
- public int doEndTag() throws JspException {
- //得到BodyContent对象,它包装了标签体里的内容
- BodyContent bodyContent = this.getBodyContent();
- //利用getString方法得到字符串
- String content = bodyContent.getString();
- //改变字符串内容,将小写改为大写
- String change = content.toUpperCase();
- //输出到浏览器
- try {
- this.pageContext.getResponse().getWriter().write(change);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return Tag.SKIP_PAGE;
- }
- }
以上~就是自定义标签的创建步骤会原理,还有一些标签体内容的处理方法,大家觉得容易吗?
对,十分的不容易啊,用这种方法定义的标签我们称为传统标签,所以这是一个社会问题,是时候就会有人站出来,写出一组代码来解决这个问题了,这组代码称为:简单标签
简单标签
为什么要学习传统标签
学习传统标签是为了以后维护到一些旧系统!!
简单标签比传统标签简单在标签处理器类的编写简单了!!!
简单便签的开发步骤
同样的,我们先学习简单标签的开发步骤,然后再说说它的原理
步骤一
编写标签处理器类,也就是一个普通的类,继承SimpleTagSupport类。然后重写它的doTag()方法:
- public class MySimpleTag extends SimpleTagSupport {
- @Override//当遇到标签时就会执行这个方法
- public void doTag() throws JspException, IOException {
- System.out.println("执行了简单标签里的doTag()方法~");
- }
- }
步骤二
在tld文件内注册这个标签吧~这个过程和传统标签一样
- <tag>
- <name>simpletag</name>
- <tag-class>com.vmaxtam.dotest.MySimpleTag</tag-class>
- <body-content>scriptless</body-content><!--这里要用这个处理-->
- </tag>
步骤三
在JSP文件中导入标签库(这个过程和传统标签一样)
步骤四
使用该标签(这个过程和传统标签一样)
以上就是简单标签的定义过程了,和传统标签相比,他简单就简单在不用重写很多方法。
简单标签的原理
一)和传统标签一样,得到tag-class字符串,找到标签处理程序类
二)实例化标签处理程序类
三)利用对象调用方法。。。。
和传统标签相比,简单标签调用的方法不相同:
SimpleTag接口的方法执行过程:
- 1) void setJspContext(JspContext pc) --设置pageContext对象,传入pageContext对象。JspContext是PageContext的父类。在标签处理器类中通过this.getJspContext()方法得到PageContext对象。
- 2)void setParent(JspTag parent) --传入父标签对象,如果没有父标签,则不调用次方法。通过getParent方法得到父标签对象
- 3)void setJspBody(JspFragment jspBody) --传入标签体内容。标签体内容封装到JspFragment方法中。通过getJspBody方法得到标签体内容。如果没签体,不调用次方法。
- 4)void doTag() --开始标签和结束标签都执行次方法。
为什么是这样调用方法呢,也是有证据的:

- private boolean _jspx_meth_itcast_005fsimpleDemo_005f0(PageContext _jspx_page_context)
- throws Throwable {
- PageContext pageContext = _jspx_page_context;
- JspWriter out = _jspx_page_context.getOut();
- // itcast:simpleDemo
- 1)实例化SimpleDemo对象
- gz.itcast.b_simple.SimpleDemo _jspx_th_itcast_005fsimpleDemo_005f0 = new gz.itcast.b_simple.SimpleDemo();
- org.apache.jasper.runtime.AnnotationHelper.postConstruct(_jsp_annotationprocessor, _jspx_th_itcast_005fsimpleDemo_005f0);
- 2)调用setJspContext方法,传入PageContext对象
- _jspx_th_itcast_005fsimpleDemo_005f0.setJspContext(_jspx_page_context);
- 3)调用setParent方法,如果没有父标签,不执行。
- 4)调用setJspBody方法,传入标签体内容
- _jspx_th_itcast_005fsimpleDemo_005f0.setJspBody(new Helper( 0, _jspx_page_context, _jspx_th_itcast_005fsimpleDemo_005f0, null));
- 5)调用doTag方法,执行标签
- _jspx_th_itcast_005fsimpleDemo_005f0.doTag();
- org.apache.jasper.runtime.AnnotationHelper.preDestroy(_jsp_annotationprocessor, _jspx_th_itcast_005fsimpleDemo_005f0);
- return false;
- }

控制标签体文本 与 结束标签后内容 是否输出
我们可以通过JspFragment对象来控制的~
标签体内容:
要输出: 在doTag()方法中执行jspFrament.invoke()方法
不输出: 什么都不做!!
结束标签后的内容:
要输出:什么都不做!
不输出:在doTag()方法中抛出一个SkipPageException异常~!
- @Override
- public void doTag() throws JspException, IOException {
- JspFragment jspBody = this.getJspBody();
- jspBody.invoke(null);
- throw new SkipPageException();
- }
那么如何循环输出标签体内容呢,在简单标签中实现十分简单,在doTag方法中写上
- for(int i=1;i<=5;i++){
- jspBody.invoke(null);//默认写出都浏览器
- }
改变标签体里的内容
在doTag方法中写上:
- //4.1 创建一个临时的Writer输出流(容器)
- StringWriter writer = new StringWriter();
- //4.2 把标签体内容拷贝到临时的Writer流中
- JspFragment jspBody = this.getJspBody();
- jspBody.invoke(writer);
- //4.3 从临时的Writer流中取出标签体内容
- String content = writer.toString();
- //4.4 改变标签体内容
- content = content.toUpperCase();
- //4.5 把改变后的内容写出到浏览器中
- //jspBody.invoke(null);如果这样写,那么还是输出原来的内容
- this.getJspContext().getOut().write(content);
标签体内容的输出格式
除了能设置标签体内容是否输出,还能够设置它的输出格式,那么它有什么样的输出格式呢?
可以有以下输出格式:
- JSP: 表示输出的标签体内容可以包含jsp脚本,且可以执行此脚本。此值只能用在传统标签中。
- scriptless: 表示输出的标签体内容不能包含jsp脚本,如果包含则报错。
- empty:表示没有标签体内容。即是空标签。如果不是空标签,则报错。
- tagdependent: 表示输出的标签体内容可以包含jsp脚本。但不执行jsp脚本(直接原样输出)
那么我们要在tld文件内设置文本的输出格式:
- <tag>
- <name>tagDemo</name>
- <tag-class>gz.itcast.a_tag.TagDemo1</tag-class>
- <body-content>JSP</body-content><!--在这里设置-->
- </tag>
上面都是在讨论标签体内容的输出,标签里还可以设置属性的,那么自定义标签如何定义标签的属性呢?
自定义标签的属性
这个过程我们在简单标签内实现,以下是操作步骤
步骤一
在标签处理器类内声明一个成员变量,,这个成员变量就用来接受标签属性的值,然后再标签处理器类内为这个成员变量生成一个setter方法:
- public class MySimpleTag extends SimpleTagSupport {
- private Integer num;
- public void setNum(Integer num) {
- this.num = num;
- }
步骤二
要到tld文件注册这个属性,属性药注册在响应标签的<Tag>标签内
- <tag>
- <name>simpletag</name>
- <tag-class>com.vmaxtam.dotest.MySimpleTag</tag-class>
- <body-content>scriptless</body-content>
- <attribute>
- <name>num</name> <!-- ??? -->
- <required>true</required><!-- ???????????????? -->
- <rtexprvalue>true</rtexprvalue><!-- ???????EL??? -->
- </attribute>
- </tag>
步骤三
这样就可以去使用属性了~
- <body>
- <mmt:simpletag num="1001">我是标签里的内容</mmt:simpletag>我是标签后的内容
- </body>
上面的内容就可以创建一个基本功能的自定义标签了~
[转]JSP自定义标签的更多相关文章
- JSP 自定义标签
0 标签技术的API继承体系 1 作用 jsp自定义标签用于移除页面中的java代码 2 实现 2.1 标签处理类ViewIPTag.java package com.zsm.util; import ...
- JSP自定义标签开发入门
一般情况下开发jsp自定义标签需要引用以下两个包 import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; 首先我们需要大致了解开发 ...
- 一个简单的jsp自定义标签
学到了一个简单的jsp自定义标签,后面有更多的例子,会更新出来: 例子1: 步骤: 1.编写标签实现类: 继承javax.servlet.jsp.tagext.SimpleTagSupport; 重写 ...
- jsp自定义标签分析
jsp自定义标签的优势体现在于jsp页面上面减少了java代码. jsp自定义标签有三大部分组成,首先是类继承TagSupport,实现doStartTag方法. public int doStart ...
- JSP自定义标签库
总所周知,JSP自定义标签库,主要是为了去掉JSP页面中的JAVA语句 此处以格式化输出时间戳为指定日期格式为例,简单介绍下JSP自定义标签的过程. 编写标签处理类(可继承自javax.servlet ...
- JSP自定义标签配置
JSP自定义标签配置 JSP自定义标签 <taglib> <taglib-uri>/WEB-INF/you.tld</taglib-uri> ...
- jsp 自定义标签解决jsp页面中int时间戳的时间格式化问题
jsp 自定义标签解决jsp页面中int时间戳的时间格式化问题 之前在项目中根据需求,需要自定义标签,经过查询w3c文档,自己也踩了一些坑,特此记录自定义标签的步骤,下面就以我之前的一个例子中的定义一 ...
- java JSP自定义标签
来至: http://blog.csdn.net/jiangwei0910410003/article/details/23915373 http://blog.csdn.net/jiangwei09 ...
- JSP自定义标签开发入门《转》
JSP自定义标签开发入门 一般情况下开发jsp自定义标签需要引用以下两个包 import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; ...
- 报错分析---->jsp自定义标签:类cannot be resolved to a type
这个困扰我一个晚上,仔细上网查阅发现,主要是因为jsp自定义标签要用到的这个jsp-api.jar的问题 这是我eclipes中的jar: 然而jsp-api.jar这个jar在tomcat中也有(报 ...
随机推荐
- springboot无法查询到后台的数据
问题:springbooot中,整合mybatis时,在IUserMapper接口中, @Select("select * from user where name like '%李%'&q ...
- Ansible - 配置文件
概述 再水一发 ref Ansible Configuration Settings 1. 查看 概述 查看 配置文件 的默认位置 命令 > ansible --version 结果 confi ...
- 67课 for循环1-为什么需要for循环
# include <stdio.h> int main (void) { int i; ;.//sum代表和的意思 ; i<=; ++i)//第八行代码 sum = sum + i ...
- 将项目打成war包并用tomcat部署的方法,步骤及注意点
部署的遇到第一个问题,就是tomcat和jdk的环境问题: 首先 理解为啥要关注这二者的环境呢?他们还是有关系的–tomcat 作为比较流行的java Web服务器也是用java来实现的一个比较大的软 ...
- Python实现将图片以二进制格式保存到MySQL数据库中,以及取出:
创建数据库表格式: CREATE TABLE photo ( photo_no int(6) unsigned NOT NULL auto_increment, image MEDIUMBLOB, P ...
- Wx-小程序-组件式开发之Vant
开始:https://youzan.github.io/vant-weapp/#/intro 小程序开发者工具中 -->工具栏-->构建npm 一.初始化package.json npm ...
- 在服务器CentOS7版本安装Nginx
简介 经常用使用Nginx来部署我们的网站,我的服务器是CentOS7.我不喜欢使用下载一个Nginx解压包然后解压的那种,我喜欢下面的这种. 安装 yum包管理工具是不带nginx,所以得先添加,在 ...
- UVA10600 ACM Contest and Blackout
用prim算法求最小生成树和次小生成树~ #include<cstdio> #include<algorithm> #include<cstring> using ...
- 解决IE8不兼容 background-size
IE8下,使用background-size适应盒子大小时不兼容,效果如下图: 网上找资料,说添加如下代码可以兼容IE8 filter: progid:DXImageTransform.Microso ...
- PHP的isset(),is_null,empty()你了解了没?
这几个变量判断函数在PHP开发中用的其实挺多的,而且粗看上去都差不多,但其实还是有不少的区别的,如果搞不清楚,也许就会遗留一些潜在的bug, 包括我自已也遇到过这样的坑,比如有一次我就遇到过用empt ...