(十三)自定义JSTL标签
前面的博客,我们讲过了 自定义
el函数;
讲一个 自定义标签技术 ;
目录
自定义标签
自定义标签 主要用于移除JSP页面中的java代码 ;
要使用自定义标签移除JSP页面中的java代码,只需要完成以下两个步骤:
- 编写一个实现
Tag接口的Java类,把页面java代码移到这个java类中(标签处理器类) - 编写标签库描述符
(tld)文件,在tld文件中把标签处理器描述成一个标签 ;(tld文件,一般放在WEB-INF下面)
快速入门:使用标签输出客户机IP
分析自定义标签的执行流程 :
Tag接口的方法都是由服务器调用的,但是在调用dostartTag的时候,会先调用接口的setPageContext()方法,因此,我们可以得到pageContext对象;
自定义标签运行原理 :
当浏览器,访问web服务器的jsp页面时,遇到自定义标签;
- 首先实例化出一个自定义标签类的对象
- 利用
Tag接口中的setPageContext方法,将页面的pageContext对象传递给处理器类的对象; - 再调用
setParent方法,如果标签有父标签,则将父标签对象作为参数,传递进去;如果没有父标签,则参数为null; - 上述工作完成以后,自定义标签类对象,相当于完成初始化操作了,这时候服务器开始执行标签,遇到开始标签,就执行
doStartTag方法 ; - 如果标签有标签体,服务器一般会执行标签体 ;
- 执行到标签结束符,就会调用
doEndTag方法; - 整个标签执行完毕以后,服务器一般会调用
release方法,释放标签工作时锁占用的资源 ;
工作原理的源码:
从源码,我们可以看出,release方法并没有得到执行,服务器把自定义标签对象,放到了缓存中,便于下次访问;
就像servlet对象一样,一直驻留在服务器内存中,直到服务器关闭 ;
其中tld文件,服务器会把WEB-INF下面的tld文件,全部加载到内存中,保存到一个Map集合中,其中键就是jsp文件中的uri ;
案列:使用标签输出客户机IP
我们新建一个java类,让它继承 TagSupport 类;重写我们需要的方法 ,这里我们仅仅需要重写 doStartTag 方法;
public class ViewTag extends TagSupport {
// @Override
public int doStartTag() throws JspException {
// 利用pageContext对象,获取request
HttpServletRequest request = (HttpServletRequest) this.pageContext.getRequest();
String ip = request.getRemoteAddr() ;
JspWriter out = this.pageContext.getOut() ;
try {
out.write(ip);
} catch (IOException e) {
throw new RuntimeException(e);
}
return super.doStartTag();
}
}
然后我们需要写一个 TLD 文件 ;
如何编写TLD文件?!
笔者也不会写,但是笔者会抄啊! (具体怎么抄,看笔者博客 怎么抄tld文件(可以点击))
下面是我打开的 c.tld 的部分代码
我们怎么写 TLD 文件,就这些代码,稍微改吧改吧,就是我们自己的 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>JSTL 1.1 core library</description>
<display-name>JSTL core</display-name>
<tlib-version>1.1</tlib-version>
<!-- 这里我们要改下,改成我们自己的简化名,比如笔者,改成了自己的名字缩写 -->
<!-- <short-name>c</short-name> -->
<short-name>yaz</short-name>
<!-- 这里我们也要改下,改成我们自己的uri,比如笔者,改成了自己的网址,随便写一个也行 -->
<!-- <uri>http://ijava.xin./jsp/jstl/core</uri> -->
<uri>http://ijava.xin</uri>
<!-- 这是一大堆描述信息,直接删掉就好了
<validator>
<description>
Provides core validation features for JSTL tags.
</description>
<validator-class>
org.apache.taglibs.standard.tlv.JstlCoreTLV
</validator-class>
</validator>
-->
<!-- 下面是一个例子,如何描述EL函数 -->
<tag>
<!-- 描述这个标签是干嘛的;我们直接删掉
<description>
Catches any Throwable that occurs in its body and optionally
exposes it.
</description>
-->
<!-- 标签名字,如果你定义的标签有属性,就写;没属性就不需要写下面的那些 -->
<name>catch</name>
<!-- 标签方法来源的类,要写完整类名,留着 -->
<tag-class>org.apache.taglibs.standard.tag.common.core.CatchTag</tag-class>
<!-- 是否有标签体,没有的话就写empty,有的话,就写上标签体是啥,留着 -->
<body-content>JSP</body-content>
<!-- 标签属性,留着 -->
<attribute>
<!-- 还是描述信息,删掉删掉
<description>
Name of the exported scoped variable for the
exception thrown from a nested action. The type of the
scoped variable is the type of the exception thrown.
</description>
-->
<!-- 属性名字,留着 -->
<name>var</name>
<!-- 是否是必备属性,必备属性就写true,写了true的属性,就必须写上值了,留着 -->
<required>false</required>
<!-- 全称是 run time expression alue 翻译为 '运行时表达式',表示是否支持运行时赋值 ,留着 -->
<!-- 如果是 true 就表示属性支持动态赋值 -->
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
在编写完毕 tld 文件,然后在JSP页面中引入我们的标签库,就可以用我们自定义的标签了 ;
关于标签处理器类的方法
这个类里面的方法。并不是向我们上面举的例子那么简单的;上面只是简单的重写了 doStartTag 方法;
下面,我讲下,什么时候该重写什么方法 ;
获取标签体
为了获取到标签体,我们需要覆写
doStarTag()方法,改变其返回值为EVAL_BODY_BUFFERED;这样标签体就会被当做对象,保存在该标签器类对象中 ; 然后在doEndTag()里面用java代码完成逻辑 ;实例:
将标签体转成大写字母@Override
public int doStartTag() throws JspException {
return BodyTagSupport.EVAL_BODY_BUFFERED ;
} @Override
public int doEndTag() throws JspException {
// 获取标签体
BodyContent bodyContent = this.getBodyContent() ;
String content = bodyContent.getString() ;
content = content.toUpperCase() ;
try {
this.pageContext.getOut().write(content);
} catch (IOException e) {
throw new RuntimeException(e) ;
}
return super.doEndTag();
}doAfterBody()为了控制显示次数,需要利用到
doAfterBody()这个方法在执行完标签体以后以及执行doEndTag()方法之前得到调用 ;为了确保执行标签体,我们也还需要覆写
doStarTag()方法,改变其返回值;实例:
控制标签体显示次数int i = 5 ;
@Override
public int doStartTag() throws JspException {
return Tag.EVAL_BODY_INCLUDE;
} @Override
public int doAfterBody() throws JspException {
if (i-- > 0 ){
return TagSupport.EVAL_BODY_AGAIN;
}else {
i = 5 ;
return TagSupport.SKIP_BODY ;
} }控制标签体是否显示取决于d*
oStarTag()*方法的方法值
EVAL_BODY_INCLUDE包含标签体的意思,会显示标签体 ;而SKIP_BODY跳过标签体
@Override
public int doStartTag() throws JspException {
return Tag.SKIP_BODY;
}
是否显示页面主要是利用
doEndTag()方法的返回值 ;
SKIP_PAGE代表后续的jsp页面的内容,不再进行处理,也就是不会显示;
@Override
public int doEndTag() throws JspException {
return Tag.SKIP_PAGE;
}
自定义标签功能扩展
控制
JSP页面中某一部分的内容是否显示;利用是否显示标签体的技术,即可完成 ;
控制整个页面是否显示;
做法:在整个页面的外部套个自定义标签,和上面一样 ;
控制重复输出页面内容
重写
doAfterBody()即可;修改
jsp页面内容输出 ;获取代表标签体的对象,对其进行改写,再利用
out对象输出 ;
传统标签
上面我们学的自定义标签技术,属于 传统标签;需要实现的方法比较多,需要我们自己去记忆;
看下面的图, 左边的是JSP2.0的技术,实现不同的功能需要实现不同的接口;同一个接口中还要选择重写哪些方法
可以明显的看出来,传统标签 很烦 ,需要我们记住的东西太多了;说实话,笔者在这篇博客的时候,早就忘记了上面的那些知识,也是根据当年的笔记 ,写的这个博客 ;
简单标签
现在我们学习 简单标签 ,让标签处理器类 继承 SimpleTagSupport 接口;
简单标签中最重要的两个方法:dotag()、setJSPBody();
setJSPBody() 方法,在服务器执行标签的时候调用,将标签体作为对象传给自定义标签类对象;
doTag() 方法,服务器执行标签,都会调用这个方法;我们对标签的处理逻辑,都写在这个方法里面 ;
是否显示标签体
比如,我们想不显示标签体,那么,在这个方法中,就不做任何操作;反之,想显示标签体,就在方法中,获取标签体输出;
@Override
public void doTag() throws JspException, IOException {
//只有doTag方法里面,什么都不做,就不会显示标签体
}
控制显示样式
我们需要获取到标签体的字符串形式;
获取方法:将标签体输送到StringWriter流的缓冲区中,从缓冲区中获取标签体的内容,从而修改样式 ;
@Override
public void doTag() throws JspException, IOException {
// 获取标签体
JspFragment jspFragment = this.getJspBody();
// 将标签体输送到流的缓冲区中
StringWriter stringWriter = new StringWriter();
// 这个方法很重要,负责将标签体输送到特定的流里面;
jspFragment.invoke(stringWriter);
// 获取缓冲区中的内容
String s = stringWriter.toString();
s = s.toUpperCase();
this.getJspContext().getOut().write(s);
}
上面代码中最重要的一个方法:jspFragment.invoke(stringWriter);
参数用于指定将JspFragment对象的执行结果写入到哪个输出流对象中,如果传递给参数的值为 null,则将执行结果写入到 JspContext.getOut()方法返回的输出流 out 对象中。(简而言之,可以理解为写给浏览器)
是否显示页面
不显示页面:在
doTage方法中,抛出SkipPageException()异常,方法抛出这个异常,服务器,就不会再计算剩下的JSP页面了;@Override
public void doTag() throws JspException, IOException {
throw new SkipPageException() ;
}
配置简单标签
配置简单标签的时候,配置标签体的时候,需要注意,不能写JSP了,改写为scriptless;Sun公司的意思是:以后 脚本表达式 也不要出现在JSP里面了,统统用标签代替 ;
<tag>
<name>....</name>
<tag-class>xxxx.....</tag-class>
<!-- 传统标签是写JSP,简单标签写 scriptless-->
<body-content>scriptless</body-content>
</tag>
与传统标签不同的是,简单标签执行结束以后,创建的对象,并不会像传统标签那样驻留在服务器内存中,而是被垃圾回收器回收掉 ;
开发带属性的标签
要想让一个自定义标签具有属性,通常需要完成两个任务:
- 在标签处理器中编写
每个属性对应的setter方法 - 在
tld文件中描述标签的属性
为自定义标签定义属性的时候,每个属性都必须按照JavaBean的属性命名方式,在标签处理器中定义属性名对应的setter方法,用来接收JSP页面调用自定义标签时传递进来的属性值。
例如,属性uri,在标签处理器类中就要定义相应的 setUri(String uri)方法。
在标签处理器中定义响应的set方法后,JSP引擎在解析执行开始标签前,也就是doStarTag()方法前,会调用set属性方法,为标签设置属性;
(十三)自定义JSTL标签的更多相关文章
- 自定义JSTL标签和函数库
一.自定义JSTL标签 1.编写标签处理类: (1)实现 SimpleTag 接口,通过 setJspContext()方法可以获取到 jspContext 对象,实际上也是 pageContext ...
- 如何自定义JSTL标签与SpringMVC 标签的属性中套JSTL标签报错的解决方法
如何自定义JSTL标签 1.创建一个类,从SimpleTagSupport继承 A) 通过继承可以获得当前JSP页面上的对象,如JspContext I) 实际上可以强转为PageContext II ...
- 自定义EL函数、自定义JSTL标签
自定义EL函数 1.做一个类(静态) package com.maya.el; public class ELBiaoDaoShi { public static String TiHuan(Stri ...
- 自定义jstl标签库
开发环境:Spring+SpringMVC +Maven +Mybatis JSTL 标签库的配置: 导入对应的 jstl.jar 和 standard.jar ,我使用的配置如下: <prop ...
- 自定义jstl标签*
原文链接:https://www.it610.com/article/442039.htm 步骤如下: 1.写tld文档:用来指定标签的名字,标签库等. 2.写标签处理器类. 3.配置到web.xml ...
- 自定义jstl标签开发
从jsp1.1开始就可以在jsp页面中使用自定义标签了,使用自定义标签不但可以实现代码重用,而且可以使jsp代码更简洁.Jsp2.0的标签扩展API中又增加了SimpleTag接口和其实现类Simpl ...
- EL表达式、JSTL标签库
一.EL(Expression Language)表达式 语法结构:${var} 若要停用对EL表达式的评估的话,需要使用page指令将isELIgnored属性值设为true: <%@ pag ...
- JSP学习笔记(3)——JSTL 标签库
JSP Standard Tag Lib,名为JSP标准标签库,设计的目的主要用来方便我们将数据输出,而不是使用JSP中的语法<% %> <%= %> <%! %> ...
- 12 自定义标签/JSTL标签库/web国际化/java web之设计模式和案例
EL应用 自定义一个标签,实现两个字符串的相加 1回顾 1.1servlet生命周期 init(ServletConfig) service ...
随机推荐
- 总结js常用的dom操作(js的dom操作API)
转载:https://www.haorooms.com/post/js_dom_api 前言 很多同学用惯了jquery操作dom,让他们用js操作的时候,常常力不从心,本文总结了常用的js的dom操 ...
- Flask上下文源码分析(二)
前面第一篇主要记录了Flask框架,从http请求发起,到返回响应,发生在server和app直接的过程. 里面有说到,Flask框架有设计了两种上下文,即应用上下文和请求上下文 官方文档里是说先理解 ...
- python 可执行
py2exe使用方法 py2exe作者:zzj 日期:2006-07-05字体大小: 小 中 大 一.简介 py2exe是一个将python脚本转换成windows上的可独立执行的可执行程序(*.ex ...
- LiquiBase实战总结
LiquiBase概述 Liquibase是一个用于跟踪.管理和应用数据库变化的开源的数据库重构工具.它将所有数据库的变化(包括结构和数据)都保存在XML文件中,便于版本控制. Liquibase具备 ...
- SQL-W3School-测验:SQL 测验
ylbtech-SQL-W3School-测验:SQL 测验 1.返回顶部 1. 您可以通过 W3SCHOOL 的测验程序来测试您的 SQL 技能. 关于本测验 本测验包含 20 道题,每道题的最长答 ...
- spring的事务是什么?与数据库的事务是否一样
spring的事务是什么?与数据库的事务是否一样 先说一下什么是事务,事务:是对数据库的一些列操作. 之前一直觉得事务只针对于数据库当中,5种隔离级别,7种传播行为,后来才发现这是针对Spring的, ...
- starUML建模C++【逆向工程】
1.下载starUML 2.打开starUML,选择default approach 3.添加 Profile,把C++添加进去 4.在右侧的工程上点右键—[C++]—-[Reverse Engine ...
- 【创业】2B创业历程
http://www.woshipm.com/chuangye/2800111.html http://www.woshipm.com/chuangye/2803240.html http://www ...
- (八)Centos之文件搜索命令locate
一.文件搜索命令locate locate优点是 搜索速度快 ,缺点是只能按文件名搜索: 1.1 新建一个文件 1.2 更新数据库 locate命令搜索的是 /var/lib/mlocate 下的 ...
- 【Leetcode_easy】788. Rotated Digits
problem 788. Rotated Digits solution1: class Solution { public: int rotatedDigits(int N) { ; ; i< ...