简介
JSTL是一个JSP标准标签库,可以解决大部分问题,但是如果我们需要一些更特殊的功能,就需要自定义类似JSTL中标签的标签。如果EL表达式无法满足我们的需求,我们也可以自定义EL函数。
tld后缀的文件为标签库描述符,它是一个XML格式的文件,顾名思义,就是用来描述标签库的文件,编写自定义标签和EL函数时都需要用到。
 
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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<!--标签库描述-->
<description>测试标签库</description>
<!--标签版版本-->
<tlib-version>1.0</tlib-version>
<!--标签库名称-->
<short-name>testTagLibrary</short-name>
<!--定义一个唯一标识当前版本标签库的公开的URI,taglib指令的uri属性必须等于该值。
如果没有将标签处理器和tld文件打成jar包,那么taglib指令的uri属性的值也可以本文件的相对路径,如/WEB-INF/test.tld-->
<uri>http://test/tag-library.com</uri>
 
<tag>
<!--标签描述-->
<description>经典标签库</description>
<!--标签的名称,引用标签时使用-->
<name>classic</name>
<!--标签处理器的完全限定类名,不能放到默认包下-->
<tag-class>com.ClassicCustomTag</tag-class>
<!--
指定标签有效的body类型。
JSP容器使用此值来验证标签body类型是否正确,并通过页面组合工具帮助页面作者提供有效的标签body。
tagdependent:标签的body由标签处理器解析,可以是另外一种语言,如SQL。
JSP:标签body可以包含jsp的语法,如jsp脚本元素,使用简单标签处理器不能设置为该值。
empty:标签body必须为空。
scriptless:标签body可以是静态HTML元素,EL表达式,jsp动作元素,但不允许出现jsp脚本元素
-->
<body-content>JSP</body-content>
<!--标签的属性-->
<attribute>
<!--属性描述-->
<description>权限</description>
<!--属性的名称-->
<name>permission</name>
<!--true/yes表示必须,false/no表示可选-->
<required>true</required>
<!--true/yes表示属性值支持jsp脚本元素和EL表达式,false/no表示不支持-->
<rtexprvalue>true</rtexprvalue>
<!--属性值的类型,如果rtexprvalue为false/no,则该值永远为java.lang.String-->
<type>java.lang.String</type>
</attribute>
</tag>
 
<!--用于提供标签库中要暴露给EL的每个函数的信息-->
<function>
<!--函数的唯一名称-->
<name>customPrint</name>
<!--函数的完全限定类名,不能放到默认包下,该类包含实现该函数的静态方法-->
<function-class>com.CustomElFunction</function-class>
<!--实现该函数的静态方法的签名,可以使用基本数据类型以及void。
如java.lang.String nickName(java.lang.String,int)-->
<function-signature>java.lang.String print(java.lang.String)</function-signature>
</function>
</taglib>
 
自定义标签
创建自定义标签分为两个步骤,编写标签处理器和注册标签。标签处理器在JSP2.0之后新增了一种实现方式。注册标签就是在tld文件中描述标签,并且把tld文件放到WEB-INF目录下。如果把标签处理器和tld文件打成jar包,那么tld文件应该放在jar包的META-INF目录下。
 
JSP2.0之前
JSP2.0之前的标签处理器要实现Tag、IterationTag、BodyTag等接口,称为典型标签处理器。
 
TagSupport
标签处理器继承TagSupport类,然后重写doStartTag、doAfterBody、doEndTag方法既可。
如果标签有属性,那么需要在标签处理器中定义该属性。
doStartTag方法是Tag接口定义的,在处理开始标签时调用,返回Tag.EVAL_BODY_INCLUDE表示执行标签body,返回Tag.SKIP_BODY表示不执行标签body。
doEndTag方法是Tag接口定义的,在处理结束标签时调用,返回Tag.EVAL_PAGE表示执行页面的剩余部分,返回Tag.SKIP_PAGE表示不执行页面的剩余部分。
doAfterBody是IterationTag接口定义的,在处理完标签body后调用,返回IterationTag.EVAL_BODY_AGAIN表示再次执行标签body,返回Tag.SKIP_BODY表示不再执行标签body。
执行顺序为,doStartTag->body->doAfterBody->doEndTag。
下面为一个简单的例子。
 
ClassicCustomTag.java
package com;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
 
public class ClassicCustomTag extends TagSupport {
 
private String permission;
 
public String getPermission() {
return permission;
}
 
public void setPermission(String permission) {
this.permission = permission;
}
 
@Override
public int doStartTag() throws JspException {
if ("query".equals(permission) || "add".equals(permission)
|| "delete".equals(permission) || "edit".equals(permission)) {
return SKIP_BODY;
} else {
return EVAL_BODY_INCLUDE;
}
}
 
@Override
public int doAfterBody() throws JspException {
return super.doAfterBody();
}
 
@Override
public int doEndTag() throws JspException {
return super.doEndTag();
}
}
 
test.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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<description>测试标签库</description>
<tlib-version>1.0</tlib-version>
<short-name>testTagLibrary</short-name>
<uri>http://test/tag-library.com</uri>
 
<tag>
<description>经典标签库</description>
<name>classic</name>
<tag-class>com.ClassicCustomTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<description>权限</description>
<name>permission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
</tag>
</taglib>
 
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://test/tag-library.com" prefix="test" %>
<html>
<head>
<title>index</title>
</head>
<body>
<div>
<button onclick="alert(this.innerHTML);" <test:classic permission="query">disabled title="没有权限" </test:classic>>查询
</button>
</div>
<div>
<button onclick="alert(this.innerHTML);" <test:classic permission="edit">disabled title="没有权限" </test:classic>>编辑
</button>
</div>
 
<div>
<button onclick="alert(this.innerHTML);" <test:classic permission="export">disabled title="没有权限" </test:classic>>导出
</button>
</div>
</body>
</html>
 
BodyTagSupport
如果标签处理类需要和标签body交互如读取、重写标签body,那么需要继承BodyTagSupport类,BodyTagSupport继承了TagSupport,因此可以实现TagSupport的全部功能,因此可以重写doStartTag、doAfterBody、doEndTag,还可以重写getBodyContent、doInitBody。
此时doStartTag应该返回BodyTag.EVAL_BODY_BUFFERED,表示申请缓冲区,由setBodyContent方法得到的BodyContent对象来处理标签的body,否则getBodyContent返回null。body.getEnclosingWriter可以返回一个JspWriter对象,用于将响应发送到客户端。
doInitBody方法表示准备执行标签body时调用。
执行顺序为,doStartTag->doInitBody->body->doAfterBody->doEndTag。
下面为一个简单的例子。
 
ClassicCustomBodyTag.java
package com;
 
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
 
public class ClassicCustomBodyTag extends BodyTagSupport {
 
private String permission;
 
public String getPermission() {
return permission;
}
 
public void setPermission(String permission) {
this.permission = permission;
}
 
@Override
public int doStartTag() throws JspException {
if ("query".equals(permission) || "add".equals(permission)
|| "delete".equals(permission) || "edit".equals(permission)) {
return EVAL_BODY_BUFFERED;
} else {
return SKIP_BODY;
}
}
 
@Override
public void doInitBody() throws JspException {
 
}
 
@Override
public int doAfterBody() throws JspException {
try {
BodyContent body = getBodyContent();
System.out.println("body:" + body.getString());
if ("query".equals(permission)) {
body.getEnclosingWriter().print("查询");
} else if ("add".equals(permission)) {
body.getEnclosingWriter().print("新增");
} else if ("delete".equals(permission)) {
body.getEnclosingWriter().print("删除");
} else {
body.getEnclosingWriter().print("无");
}
} catch (Exception e) {
e.printStackTrace();
}
return super.doAfterBody();
}
 
@Override
public int doEndTag() throws JspException {
return super.doEndTag();
}
}
 
test.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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<description>测试标签库</description>
<tlib-version>1.0</tlib-version>
<short-name>testTagLibrary</short-name>
<uri>http://test/tag-library.com</uri>
 
<tag>
<description>经典标签库</description>
<name>classic</name>
<tag-class>com.ClassicCustomBodyTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<description>权限</description>
<name>permission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
</tag>
</taglib>
 
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://test/tag-library.com" prefix="test" %>
<html>
<head>
<title>index</title>
</head>
<body>
<div>
<button onclick="alert(this.innerHTML);"><test:classic permission="query">***</test:classic>
</button>
</div>
<div>
<button onclick="alert(this.innerHTML);"><test:classic permission="edit">***</test:classic>
</button>
</div>
</body>
</html>
 
JSP2.0之后
JSP2.0之后新增了SimpleTag接口,实现该接口的标签处理器称为简单标签处理器。
简单标签处理器必须有无参构造函数。JSP容器调用setJspContext方法传递JspContext对象,从JspContext对象中可以获取JspWriter,用于将响应发送到客户端。如果标签有body,JSP容器调用setJspBody方法传递JspFragment对象,如果没有body,就不会调用这个方法。最后JSP容器在标签执行时调用doTag方法,并且只调用一次。
JspFragment有两个方法,一个是获取JspContext对象,一个是执行标签body并且输出到指定的Writer。
 
SimpleTagSupport
该类实现了SimpleTag接口,可以方便开发。
下面是一个简单的例子。
 
SimpleCustomTag.java
package com;
 
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
 
public class SimpleCustomTag extends SimpleTagSupport {
 
private String permission;
 
public String getPermission() {
return permission;
}
 
public void setPermission(String permission) {
this.permission = permission;
}
 
@Override
public void doTag() throws JspException, IOException {
try {
JspContext jspContext = getJspContext();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
OutputStreamWriter outputStreamWriter=new OutputStreamWriter(byteArrayOutputStream);
getJspBody().invoke(outputStreamWriter);
outputStreamWriter.close();
System.out.println("body:" + byteArrayOutputStream.toString());
if ("query".equals(permission)) {
jspContext.getOut().print("查询");
} else if ("add".equals(permission)) {
jspContext.getOut().print("新增");
} else if ("delete".equals(permission)) {
jspContext.getOut().print("删除");
} else {
jspContext.getOut().print("无");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
 
test.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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<description>测试标签库</description>
<tlib-version>1.0</tlib-version>
<short-name>testTagLibrary</short-name>
<uri>http://test/tag-library.com</uri>
 
<tag>
<description>简单标签库</description>
<name>simple</name>
<tag-class>com.SimpleCustomTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<description>权限</description>
<name>permission</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
</tag>
</taglib>
 
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://test/tag-library.com" prefix="test" %>
<html>
<head>
<title>index</title>
</head>
<body>
<div>
<button onclick="alert(this.innerHTML);"><test:simple permission="query">***</test:simple>
</button>
</div>
<div>
<button onclick="alert(this.innerHTML);"><test:simple permission="edit">***</test:simple>
</button>
</div>
</body>
</html>
 
自定义EL函数
函数必须是静态方法。
下面为一个简单的例子。
 
CustomElFunction.java
package com;
 
public class CustomElFunction {
 
public static String print(String message) {
return "自定义打印:" + message;
}
}
 
test.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/web-jsptaglibrary_2_0.xsd"
version="2.0">
 
<description>测试标签库</description>
<tlib-version>1.0</tlib-version>
<short-name>testTagLibrary</short-name>
<uri>http://test/tag-library.com</uri>
 
<function>
<name>customPrint</name>
<function-class>com.CustomElFunction</function-class>
<function-signature>java.lang.String print(java.lang.String)</function-signature>
</function>
</taglib>
 
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://test/tag-library.com" prefix="test" %>
<html>
<head>
<title>${test:customPrint("index.jsp")}</title>
</head>
<body>
</body>
</html>

JSP2.2自定义标签、EL函数的更多相关文章

  1. JSP2的自定义标签和方法

    Jsp2的自定义标签 Jsp2 开发标签库的几个步骤: 开发自定义标签处理类. 建立一个*.tld文件,每个tld文件对应一个标签库,每个标签库可对应多个标签. 在jsp文件中使用自定义标签 空标签 ...

  2. 自定义一个EL函数

    自定义一个EL函数 一般就是一下几个步骤,顺便提供一个工作常用的 案例: 1.编写一个java类,并编写一个静态方法(必需是静态方法),如下所示: public class DateTag { pri ...

  3. Jsp2.0自定义标签(第三天)——EL表达式的使用

    1.提出问题: 我们经常会看到这样的jsp页面代码: 浏览器显示: 为什么会在页面输出:Hello World  ,${per}究竟是如何找到“Hello World”的呢? 2.分析问题: 要想解决 ...

  4. Jsp2.0自定义标签(第一天)——一个简单的例子

    今天是学习自定义标签的第一天 Jsp2.0以来,自定义标签的实现比传统标签的实现容易了很多,一般只要extends类SimpleSupport重写doTag()方法即可. 先看最简单的例子,输出一个H ...

  5. JSP2 的自定义标签

    在 JSP 中开发标签库只需如下几个步骤 1.开发自定义标签处理类 2.建立一个 *.tld 文件,每个 *.tld 文件对应一个标签库,每个标签库可包含多个标签 3.在 JSP 文件中使用自定义标签 ...

  6. Jsp2.0自定义标签(第二天)——自定义循环标签

    今天是学习自定义标签的第二天,主要是写一个自定义的循环标签. 先看效果图: 前台页面Jsp代码 <%@ page language="java" contentType=&q ...

  7. JSP2.0自定义标签

    JSP1.0中可以通过继承TagSupport或者BodyTagSupport来实现自定义的tag处理方法. JSP2.0中也支持另外一种更为简单的自定tag的方法,那就是直接讲JSP代码保存成*.t ...

  8. EL函数以及自定义标签的应用

    一.EL函数(调用普通类的静态方法) 编写步骤(自定义EL函数的编写步骤即自定义标签的编写步骤): ①编写一个普通的java类,提供一个静态方法,功能自定,例如下: package cn.wzbril ...

  9. JavaWeb(七):EL表达式、自定义标签和JSTL

    一.EL表达式 语法 el.jsp <%@page import="java.util.Date"%> <%@page import="com.atgu ...

随机推荐

  1. C#中WebService的创建、部署和调用的简单实例

    webservice 可以用于分布式应用程序之间的交互,和不同程序之间的交互. 概念性的东西就不说太多,下面开始创建一个简单的webservice的例子. 一:WebService的创建开发 先新建一 ...

  2. C++算法 线段树

    线段树这个算法,看起来非常高端,而且很有用处,所以还是讲一下下吧. 温馨提示:写线段树前请做好写码5分钟,调试一辈子的准备^-^ 啊直接步入正题…… 首先我们考虑一个题目:有一个序列,要做到单点修改单 ...

  3. Promise对象入门

    简介 promise对象可以获取异步操作的消息,提供统一的API,各个异步操作都可以用同样的方法进行处理. promise对象不受外界影响,其有三种状态:pending(进行中).fulfilled( ...

  4. 关于对MyBatis.net框架的学习笔记( MyBatis.net是一款灵活性极大,sql由开发者自行在xml中编写, 轻量的ORM映射框架). 同时避免了sql硬编码到代码中不易维护的问题...

    对于为什么要用ORM,为什么又要选择MyBatis.net,这个问题希望读者自行查找资料.这里直接贴出相关的调试笔记. 步骤1)下载与引用. http://code.google.com/p/myba ...

  5. 手摸手 Elastic Stack 使用教程 - 环境安装

    前言 在日常的开发中,会涉及到对一些中间件以及基础组件的使用,日志汇总分析.APM 监控.接口的健康检查.站内搜索,以及对于服务器.nginx.iis 等等的监控,最近的几个需求点,都和 Elasti ...

  6. 09.redis 哨兵主备切换时数据丢失的解决方案

    一.两种数据丢失的情况 1. 异步复制导致的数据丢失   因为master->slave的复制是异步的,所以可能有部分数据还没复制到slave,master就宕机了,此时这些部分数据就丢失了 2 ...

  7. 盒子上下滚动到js 底部触发的事件

    //html是用法举列子,js亲测有效(把这段js#scro加到你要滚动的盒子) <div id="scro">  <div>1</div> & ...

  8. iOS NSOperation

    iOS NSOperation 一.简介 除了,NSThread和GCD实现多线程,配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOp ...

  9. Shader 语义

    在书写HLSL shader程序时,输入和输出变量需要拥有他们 含义来表明语义.这在HLSL shader中是一个标准的做法. Vertex shader 输入语义 主顶点着色器函数(被指令 #pra ...

  10. Codeforces Round #669 (Div. 2)A-C题解

    A. Ahahahahahahahaha 题目:http://codeforces.com/contest/1407/problem/A 题解:最多进行n/2的操作次数,我们统计这n个数中1的个数,是 ...