当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>

上面的内容就可以创建一个基本功能的自定义标签了~

学到了很多东西,但还是要感谢文章原作者:https://www.cnblogs.com/vmax-tam/p/4145334.html

What You Want,Time Will Give You!

JavaWeb之 JSP:自定义标签的创建和使用的更多相关文章

  1. JavaWeb基础—JSP自定义标签入门

    自定义标签的作用:替换JSP页面的java代码 步骤:1.标签处理类(标签是一个对象,那也就需要先有类) 2.tld文件 它是一个xml(可以向c标签里借),一般放到WEB-INF下,不让客户端浏览器 ...

  2. JSP自定义标签开发入门

    一般情况下开发jsp自定义标签需要引用以下两个包 import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; 首先我们需要大致了解开发 ...

  3. jsp自定义标签分析

    jsp自定义标签的优势体现在于jsp页面上面减少了java代码. jsp自定义标签有三大部分组成,首先是类继承TagSupport,实现doStartTag方法. public int doStart ...

  4. JSP自定义标签库

    总所周知,JSP自定义标签库,主要是为了去掉JSP页面中的JAVA语句 此处以格式化输出时间戳为指定日期格式为例,简单介绍下JSP自定义标签的过程. 编写标签处理类(可继承自javax.servlet ...

  5. JSP自定义标签开发入门《转》

    JSP自定义标签开发入门 一般情况下开发jsp自定义标签需要引用以下两个包 import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; ...

  6. Rhythmk 一步一步学 JAVA(7): jsp 自定义标签

    1.实现Tag接口: TagSupport类实现了Tag接口,为我们提供了4个重要的方法(见表6-5). 1.1. TagSupport类中的常用方法           int doStartTag ...

  7. 【转】Jsp自定义标签详解

    一.前言 原本是打算研究EXtremeComponents这个jsp标签插件,因为这个是自定义的标签,且自身对jsp的自定义标签并不是非常熟悉,所以就打算继续进行扫盲,开始学习并且整理Jsp自定义标签 ...

  8. 【转】JSP自定义标签

    转载自:http://www.cnblogs.com/edwardlauxh/archive/2010/05/20/1918587.html tld标签的描述文件 标签的描述文件是一个描述整个标签库标 ...

  9. 1.4(学习笔记)JSP自定义标签

    一.JSP自定义标签 JSP自定义标签,可以通过实现Tag接口.继承TagSupport类来设置标签功能. 后续通过配置文件将标签和具体的实现类关联. 二.自定义第一个标签(实现Tag接口) 自定义标 ...

随机推荐

  1. 不显示TensorFlow加速指令警告

    vim ~/.bashrc 在打开的文件中追加: export TF_CPP_MIN_LOG_LEVEL= 最后再执行 source ~/.bashrc

  2. WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable Exception in thread "main" java.io.IOException: No FileSystem for sc F

    1.执行脚本程序报如下所示的错误: [hadoop@slaver1 script_hadoop]$ hadoop jar web_click_mr_hive.jar com.bie.hive.mr.C ...

  3. golang ffmpeg 做网络直播

    最近在公司做在线视频转码的工作,研究了下ffmpeg 最后直接研究了下网络直播,我是在我自己的mac 上面测试的,效果,还可以,先看看效果图吧 ffmpeg 我是通过brew安装 的,这步就略了 VL ...

  4. linux改权限

    改变文件夹本身权限,不改动子文件(夹) chmod 600 my/ 改变文件夹及子目录下所有文件(夹)权限 chmod -R 777 my/ 统一修改 cd my 修改文件夹权限为755 find - ...

  5. 求自然数幂和 B - The Sum of the k-th Powers CodeForces - 622F

    题解: 很多方法 斯特林数推导略麻烦但是不依赖于模数 代码: 拉格朗日插值 由于可以证明这是个K+1次多项式于是可以直接用插值 #include <bits/stdc++.h> using ...

  6. Coolpy网络部署说明(宽带互联网)

    本文将介绍Coolpy第二种方案的网络部署方法.以方便大家学习如何让coolpy设备部署到相应的应用场景中.本例将以水星MW310R无线路由器作为演示路由器. 1.硬件连接部分: coolpy设备=& ...

  7. net core体系-web应用程序-4asp.net core2.0 项目实战(1)-5项目数据库操作封装操作-EF框架

    EF框架有三种基本的方式:DB First(数据库优先),Model First(模型优先),Code First(代码优先). Entity Framework4.1之前EF支持“Database  ...

  8. mariadb-主主

    互为主从:两个节点各自都要开启binlog和relay log: 这样可能会产生以下问题: 1.数据不一致: 2.自动增长id:(能不用最好不用) 定义一个节点使用奇数id auto_incremen ...

  9. maven私服nexus(三)

    将项目中的第三方jar包上传至maven私服中 上传jar包到maven私服 在你使用的maven配置文件settings中加上如下信息 代表你访问的账号密码 <servers> < ...

  10. yield与yield from

    yield 通过yield返回的是一个生成器,yield既可以产出值又可以生成值,yield可以用next()来启动生成器,同时可以用send向生成器传递值:在初次启动生成器时,需调用next()或s ...