• JSP2.2自定义标签、EL函数


    简介
    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>
  • 相关阅读:
    VS2015 调试中断点突然失效的解决办法、VS调试时关闭调试让浏览器继续保留页面
    Postman调用WebService,包括头验证部分
    C# 正则表达式大全
    Webservice超时问题
    C# DateTime的 ParseExact和 TryParseExact 使用说明
    4、QT分析之调试跟踪系统
    5、QT分析之网络编程
    QIODevice (Qt中所有 I/O devices 的基类,QFile,QBuffer,QTcpSocket等)
    Qt 菜鸟的坑 QAbstractSocket::isValid()
    qt之QAbstractSocket
  • 原文地址:https://www.cnblogs.com/gjb724332682/p/9586179.html
Copyright © 2020-2023  润新知