zoukankan      html  css  js  c++  java
  • JSP2 的自定义标签

    在 JSP 中开发标签库只需如下几个步骤

    1、开发自定义标签处理类

    2、建立一个 *.tld 文件,每个 *.tld 文件对应一个标签库,每个标签库可包含多个标签

    3、在 JSP 文件中使用自定义标签

    开发自定义标签类

    在 JSP 页面使用一个简单的标签时,底层实际上由标签处理类提供支持,从而可以通过简单的标签来封装复杂的功能。

    自定义标签类应该继承一个父类:javax.servlet.jsp.tagext.SimpleTagSupport,除此之外,JSP 自定义标签还有如下要求:

    1、如果标签类包含属性,每个属性都有对应的 getter 和 setter 方法

    2、重写 doTag() 方法,这个方法负责生成页面内容

    下面开发一个最简单的自定义标签:

    HelloWorldTag.java

    package com.baiguiren;
    
    import java.io.IOException;
    import java.util.Date;
    
    import javax.servlet.*;
    
    public class HelloWorldTag extends SimpleTagSupport
    {
        // 重写 doTag() 方法,该方法为标签生成页面内容
        public void doTag() throws JspException, IOException {
            // 获取页面输出流,并输出字符串
            getJspContext().getOut().write("Hello World! " + new Date());
        }
    }
    

      

    建立 TLD 文件

    TLD 是 Tag Library Definition 的缩写,即标签库定义,文件的后缀是 tld,每个 TLD 文件对应一个标签库,一个标签库中可包含多个标签。TLD 文件也称为标签库定义文件。

    标签库定义文件的根元素是 tablib,他可以包含多个 tag 子元素,每个 tag 子元素都定义一个标签。通常可以到 web 容器下复制一个标签库定义文件,并在此基础上修改即可。

    <?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">
    
        <tlib-version>1.0</tlib-version>
        <short-name>mytaglib</short-name>
        <uri>http://localhost:8080/jsp/mytaglib</uri>
    
        <!-- 定义第一个标签 -->
        <tag>
            <description>输出 Hello, World</description>
            <!-- 定义标签名 -->
            <name>helloWorld</name>
            <!-- 定义标签处理类 -->
            <tag-class>com.baiguiren.HelloWorldTag</tag-class>
            <!-- 定义标签体为空 -->
            <body-content>empty</body-content>
        </tag>
        
    </taglib>
    

      

    上面的标签库定义文件也是一个标准的 XML 文件,该 XML 文件的根元素是 taglib 元素,因此每次编写标签库定义文件时都直接添加该元素即可。

    taglib 下有如下三个子元素:

    1、tlib-version:指定该标签库实现的版本,这是一个作为标识的内部版本号,对程序没有太大的作用。

    2、short-name:该标签库的默认短名,该名称通常也没有太大的用处。

    3、uri:这个属性非常重要,它指定该标签库的 URI,相当于指定该标签库的唯一标识。JSP 页面中使用该标签库时就是根据该 URI 属性来定位标签库的。

    除此之外,taglib 元素下可以包含多个 tag 元素,每个 tag 元素定义一个标签,tag 元素下允许出现如下常用子元素。

    name:该标签的名称,这个子元素很重要,JSP 页面中就是根据该名称来使用此标签的。

    tag-class:指定标签的处理类,它指定了标签由哪个标签处理类来处理。

    body-content:这个子元素指定标签体内容,该子元素可以是以下几个:

    1、tagdependent:指定标签处理类自己负责处理标签体

    2、empty:指定该标签只能作为空标签使用

    3、scriptless:指定该标签的标签体可以是静态 HTML 元素、表达式语言,但不允许出现 JSP 脚本。

    4、JSP:指定该标签的标签体可以使用 JSP 脚本(JSP2 规范不再推荐使用 JSP)

    dynamic-attributes:指定该标签是否支持动态属性。只有当定义动态属性标签时才需要该子元素。

    定义了上面的标签库定义文件后,将标签库文件放在 Web 应用的 WEB-INF 路径或任意子路径下,Java Web 规范会自动加载该文件,则该文件定义的标签库也将生效。

    使用标签库

    在 JSP 页面中确定指定的标签需要两点:

    1、标签库 URI:确定使用哪个标签库

    2、标签名:确定使用哪个标签

    使用标签库分成以下两个步骤:

    1、导入标签库:使用 taglib 编译指令导入标签库,就是将该标签库和指定前缀关联起来。

    2、使用标签:在 JSP 页面中使用自定义标签。

    taglib 的语法格式如下:

    <%@ taglib uri="tagliburi" prefix="tagPrefix" %>

    其中 uri 属性指定标签库的 URI,这个 URI 可以确定一个标签库。而 prefix 属性指定标签库前缀,即所有使用该前缀的标签将由此标签库处理。

    使用标签的语法格式如下:

    <tagPrefix:tagName tagAttribute="tagValue" ...>
    <tagBody />
    </tagPrefix:tagName>
    

      

    如果该标签没有标签体,则可以使用如下的语法格式:

    <tagPrefix:tagName tagAttribute="tagValue" .../>
    

      

    上面使用标签的语法里都包含了设置属性值,前面介绍的 HelloWorldTag 标签没有任何属性,所以使用该标签只需用 <myTag:helloWorld/> 即可。其中 mytag 是 taglib 指令为标签库指定的前缀,而 helloWorld 是标签名。

    mytaglib.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">
    
        <tlib-version>1.0</tlib-version>
        <short-name>mytaglib</short-name>
        <uri>/mytaglib</uri>
    
        <!-- 定义第一个标签 -->
        <tag>
            <description>输出 Hello, World</description>
            <!-- 定义标签名 -->
            <name>helloWorld</name>
            <!-- 定义标签处理类 -->
            <tag-class>com.baiguiren.HelloWorldTag</tag-class>
            <!-- 定义标签体为空 -->
            <body-content>empty</body-content>
        </tag>
        
    </taglib>
    

      

    hello-world-tag.jsp

    <%@ page contentType="text/html; charset=UTF-8" %>
    <%@ taglib uri="/WEB-INF/mytaglib.tld" prefix="mytag" %>
    
    <html>
        <head>
            <title>hello world tag</title>
        </head>
        <body>
    <!-- 使用标签,其中 mytag 是标签前缀,根据 taglib 的编译指令,mytag 前缀将由 URI 为 http://localhost:8080/jsp/mytaglib 的标签库处理 -->
    <mytag:helloWorld/><br/>
        </body>
    </html>
    

      

    带属性的标签

    带属性的标签必须为每个属性提供对应的 setter 和 getter 方法。

    定义标签

    <!-- 带属性标签 -->
        <tag>
            <name>query</name>
            <tag-class>com.baiguiren.QueryTag</tag-class>
            <body-content>empty</body-content>
    
            <!-- 配置属性: driver -->
            <attribute>
                <name>driver</name>
                <required>true</required>
                <fragment>true</fragment>
            </attribute>
            <!-- 配置属性:url -->
            <attribute>
                <name>url</name>
                <required>true</required>
                <fragment>true</fragment>
            </attribute>
            <!-- 配置属性:user -->
            <attribute>
                <name>user</name>
                <required>true</required>
                <fragment>true</fragment>
            </attribute>
            <!-- 配置属性:pass -->
            <attribute>
                <name>pass</name>
                <required>true</required>
                <fragment>true</fragment>
            </attribute>
            <!-- 配置属性:sql -->
            <attribute>
                <name>sql</name>
                <required>true</required>
                <fragment>true</fragment>
            </attribute>
        </tag>
    

      

    标签处理类 QueryTag.java

    package com.baiguiren;
    
    import java.io.IOException;
    import java.io.Writer;
    import java.util.Date;
    import java.sql.*;
    
    import javax.servlet.*;
    import javax.servlet.jsp.*;
    import javax.servlet.jsp.tagext.*;
    
    public class QueryTag extends SimpleTagSupport
    {
        // 定义成员变量来代表标签的属性
        private String driver;
        private String url;
        private String user;
        private String pass;
        private String sql;
    
        // 执行数据库访问的对象
        private Connection connection = null;
        private Statement statement = null;
        private ResultSet resultSet = null;
        private ResultSetMetaData resultSetMetaData = null;
    
        // 下面是各成员属性的 setter 和 getter 方法
        public void setDriver(String driver) {
            this.driver = driver;
        }
    
        public String getDriver() {
            return this.driver;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public String getUrl() {
            return this.url;
        }
    
        public void setUser(String user) {
            this.user = user;
        }
    
        public String getUser() {
            return this.user;
        }
    
        public void setPass(String pass) {
            this.pass = pass;
        }
    
        public String getPass() {
            return this.pass;
        }
    
        public void setSql(String sql) {
            this.sql = sql;
        }
    
        public String getSql() {
            return this.sql;
        }
    
        // 重写 doTag() 方法,该方法为标签生成页面内容
        public void doTag() throws JspException, IOException
        {
            try {
                // 注册驱动
                Class.forName(driver);
                // 获取数据库连接
                connection = DriverManager.getConnection(url, user, pass);
                // 创建 Statement 对象
                statement = connection.createStatement();
                // 执行查询
                resultSet = statement.executeQuery(sql);
                resultSetMetaData = resultSet.getMetaData();
                // 获取列数目
                int columnCount = resultSetMetaData.getColumnCount();
                // 获取页面输出流
                Writer out = getJspContext().getOut();
                // 在页面输出表格
                out.write("<table border='1' width='400'>");
                // 遍历结果集
                while (resultSet.next()) {
                    out.write("<br>");
                    // 逐列输出查询到的数据
                    for (int i = 1; i <= columnCount; i ++) {
                        out.write("<td>");
                        out.write(resultSet.getString(i));
                        out.write("</td>");
                    }
                    out.write("</tr>");
                }
            } catch (ClassNotFoundException classNotFoundException) {
                classNotFoundException.printStackTrace();
                throw new JspException("自定义标签错误" + classNotFoundException.getMessage());
            } catch (SQLException sqlException) {
                sqlException.printStackTrace();
                throw new JspException("SQL错误" + sqlException.getMessage());
            } finally {
                // 关闭结果集
                try {
                    if (resultSet != null) 
                        resultSet.close();
                    if (statement != null)
                        statement.close();
                    if (connection != null)
                        connection.close();
                } catch (SQLException sqlException2) {
                    sqlException2.printStackTrace();
                }
            }
        }
    }
    

      

    使用标签 query-tag.jsp

    <%@ page contentType="text/html; charset=UTF-8" %>
    <%@ taglib uri="/WEB-INF/mytaglib.tld" prefix="mytag" %>
    
    <html>
        <head>
            <title>query tag</title>
        </head>
        <body>
    
    <mytag:query
        driver="com.mysql.jdbc.Driver"
        url="jdbc:mysql://localhost:3306/jsp"
        user="root"
        pass="root"
        sql="select * from person"
         /><br/>
    
        </body>
    </html>
    

      

    该标签的输出内容依然由 doTag 方法决定,该方法会根据属性值进行查询,并将查询结果集输出到当前页面。

    对于有属性的标签,需要为 <tag.../> 元素增加 <attribute.../> 子元素,每个 attribute 子元素定义一个标签属性。

    <attribute.../> 子元素通常还需要指定如下几个子元素:

    1、name:设置属性名,子元素的值是字符串内容

    2、required:设置该属性是否为必需属性,该子元素的值是 true 或 false

    3、fragment:设置该属性是否支持 JSP 脚、表达式等动态内容,子元素的值为 true 或 false。

    带标签体的标签

    带标签体的标签,可以在标签内嵌入其他内容(包括静态的 HTML 和 动态的 JSP 内容),通常用于完成一些逻辑运算。

    标签配置

    <!-- 迭代标签 -->
        <tag>
            <name>iterator</name>
            <tag-class>com.baiguiren.IteratorTag</tag-class>
            <!-- 定义标签体不允许出现 JSP 脚本 -->
            <body-content>scriptless</body-content>
    
            <!-- 配置标签属性:collection -->
            <attribute>
                <name>collection</name>
                <required>true</required>
                <fragment>true</fragment>
            </attribute>
            <!-- 配置标签属性:item -->
            <attribute>
                <name>item</name>
                <required>true</required>
                <fragment>true</fragment>
            </attribute>
        </tag>
    

      

    iterator-tag.jsp

    <%@ page contentType="text/html; charset=UTF-8" %>
    <%@ page import="java.util.*" %>
    <%@ taglib uri="/WEB-INF/mytaglib.tld" prefix="mytag" %>
    
    <html>
        <head>
            <title>iterator tag</title>
        </head>
        <body>
    <%
    // 创建一个 List 对象
    List<String> a = new ArrayList<String>();
    a.add("string 1");
    a.add("string 2");
    a.add("string 3");
    // 将 List 对象放入 page 范围内
    pageContext.setAttribute("a", a);
    %>
    <table border='1' width='400'>
    <!-- 使用迭代器标签,对 a 集合进行迭代 -->
    <mytag:iterator collection="a" item="item">
        <tr>
            <td>${pageScope.item}</td>
        </tr>
    </mytag:iterator>
    </table>
        </body>
    </html>
    

      

    IteratorTag.java

    package com.baiguiren;
    
    import java.io.IOException;
    import java.io.Writer;
    import java.util.Collection;
    import java.util.Date;
    import java.sql.*;
    
    import javax.servlet.*;
    import javax.servlet.jsp.*;
    import javax.servlet.jsp.tagext.*;
    
    public class IteratorTag extends SimpleTagSupport
    {
        // 标签属性,用于指定需要被迭代的集合
        private String collection;
        // 标签属性,指定迭代集合元素,为集合元素指定的名称
        private String item;
    
        public void setCollection(String collection) {
            this.collection = collection;
        }
    
        public String getCollection() {
            return this.collection;
        }
    
        public void setItem(String item) {
            this.item = item;
        }
    
        public String getItem() {
            return this.item;
        }
    
        // 标签的处理方法,在标签处理类只需要重写 doTag() 方法
        public void doTag() throws JspException, IOException
        {
            // 从 page scope 中取出名为 collection 的集合
            Collection itemList = (Collection)getJspContext().getAttribute(collection);
            // 遍历集合
            for (Object s : itemList) {
                // 将集合的元素设置到 page 范围内
                getJspContext().setAttribute(item, s);
                // 输出标签体(body-content)
                getJspBody().invoke(null);
            }
        }
    }
    

      

    上面的标签处理类先从 page 范围内取出指定名称的 Collection 对象,然后遍历 Collection 对象的元素,每次遍历都调用了 getJspBody() 方法,该方法返回该标签所包含的标签体:JspFragment 对象,执行该对象的 invoke() 方法,即可输出该标签的标签体内容。该标签的作用是:遍历指定集合,每遍历一个集合元素,即输出标签体一次。

    因为该标签的标签体不为空,配置该标签时指定 body-content 为 scriptless。

    实际上 JSTL 标签库提供了一套功能非常强大的标签,例如普通的输出标签,还有用于分支判断的标签等,JSTL 都有非常完善的实现。

    以页面片段作为属性的标签

    JSP2 规范的自定义标签还允许直接将一段 "页面片段" 作为属性,这种方式给自定义标签提供了更大的灵活性。

    以 "页面片段" 为属性的标签与普通标签区别不大,只有两个简单的改变。

    1、标签处理类中定义类型为 JspFragment 的属性,该属性代表了 "页面片段"

    2、使用标签库时,通过 <jsp:attribute .../> 动作指令为标签的属性指定值。

    <!-- 以页面片段作为属性的标签 -->
        <tag>
            <!-- 定义标签名 -->
            <name>fragment</name>
            <!-- 定义标签处理类 -->
            <tag-class>com.baiguiren.FragmentTag</tag-class>
            <!-- 指定该标签不支持标签体 -->
            <body-content>empty</body-content>
            <!-- 定义标签属性:fragment -->
            <attribute>
                <name>jspFragment</name>
                <required>true</required>
                <fragment>true</fragment>
            </attribute>
        </tag>
    

      

    fragment.jsp

    <%@ page contentType="text/html; charset=UTF-8" %>
    <%@ taglib uri="/WEB-INF/mytaglib.tld" prefix="mytag" %>
    
    <html>
        <head>
            <title>fragment tag</title>
        </head>
        <body>
            <h2>下面显示的是自定义标签中的内容</h2>
            <mytag:fragment>
                <jsp:attribute name="jspFragment">
                    <%-- 使用 jsp:attribute 标签传入 fragment 参数 --%>
                    <!-- 下面是动态的 JSP 页面内容 -->
                    <mytag:helloWorld/>
                </jsp:attribute>
            </mytag:fragment>
            <br/>
            <mytag:fragment>
                <jsp:attribute name="jspFragment">
                    <!-- 下面是动态的 JSP 页面片段 -->
                    ${pageContext.request.remoteAddr}
                </jsp:attribute>
            </mytag:fragment>
        </body>
    </html>
    

      

    FragmentTag.java

    package com.baiguiren;
    
    import java.io.IOException;
    import java.io.Writer;
    import java.util.Collection;
    import java.util.Date;
    import java.sql.*;
    
    import javax.servlet.*;
    import javax.servlet.jsp.*;
    import javax.servlet.jsp.tagext.*;
    
    public class FragmentTag extends SimpleTagSupport
    {
        private JspFragment jspFragment;
    
        public void setJspFragment(JspFragment jspFragment) {
            this.jspFragment = jspFragment;
        }
    
        public JspFragment getJspFragment() {
            return this.jspFragment;
        }
    
        public void doTag() throws JspException, IOException {
            JspWriter out = getJspContext().getOut();
            out.println("<div style='padding: 10px; border: 1px solid black; border-radius: 20px;'>");
            out.println("<h3>下面是动态传入的 JSP 片段</h3>");
            // 调用、输出 "页面片段"
            jspFragment.invoke(null);
            out.println("</div>");
        }
    }
    

      

    注意:taglib 里面配置的 attribute 一定要和 jsp 里面 jsp:attribute 的 名字一样,例如上面都是 jspFragment,否则会导致莫名其妙的错误。

    动态属性的标签

    动态属性比普通标签多了如下两个额外要求。

    1、标签处理类还需要实现 DynamicAttributes 接口

    2、配置标签时通过 <dynamic-attributes .../> 子元素指定该标签支持动态属性。

    配置:

    <!-- 定义接受动态属性的标签 -->
        <tag>
            <name>dynaAttr</name>
            <tag-class>com.baiguiren.DynamicAttributesTag</tag-class>
            <body-content>empty</body-content>
            <dynamic-attributes>true</dynamic-attributes>
        </tag>
    

      

    dynamic-attributes.jsp

    <%@ page contentType="text/html; charset=UTF-8" %>
    <%@ taglib uri="/WEB-INF/mytaglib.tld" prefix="mytag" %>
    
    <html>
        <head>
            <title>支持动态属性的自定义标签</title>
        </head>
        <body>
            <h2>下面显示的是自定义标签中的内容</h2>
    
            <h4>指定两个属性</h4>
            <mytag:dynaAttr name="name" age="24" /><br/>
    
            <h4>指定四个属性</h4>
            <mytag:dynaAttr name="jsp" age="12" job="developer" experience="5" />
        </body>
    </html>
    

      

    DynamicAttributesTag.japackage com.baiguiren;

    import java.io.IOException;
    import java.io.Writer;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Date;
    import java.sql.*;
    
    import javax.servlet.*;
    import javax.servlet.jsp.*;
    import javax.servlet.jsp.tagext.*;
    
    public class DynamicAttributesTag extends SimpleTagSupport
        implements DynamicAttributes
    {
        // 保存每个属性名的集合
        private ArrayList<String> keys = new ArrayList<String>();
        // 保存每个属性值的集合
        private ArrayList<Object> values = new ArrayList<Object>();
    
        public void doTag() throws JspException, IOException
        {
            JspWriter out = getJspContext().getOut();
            // 此处只是简单地输出每个属性
            out.println("<ol>");
            for (int i = 0; i < keys.size(); i++) {
                String key = keys.get(i);
                Object value = values.get(i);
                out.println("<li>" + key + "=" + value + "</li>");
            }
            out.println("</ol>");
        }
    
        @Override
        public void setDynamicAttribute(String uri, String localName, Object value)
            throws JspException
        {
            // 添加属性名
            keys.add(localName);
            // 添加属性值
            values.add(value);
        }
    }

     

  • 相关阅读:
    水平居中、垂直居中,总有一款适合你的
    HTML利用posotion属性定位 小技巧
    angular2 如何使用websocket
    angular2 引入jquery
    HTML+CSS学习笔记
    用eclipse 搭建struts2环境
    html对URL传参数进行解析
    angular2上传图片
    当div元素内的内容超出其宽度时,自动隐藏超出的内容
    关于引用对象的使用的一点小理解
  • 原文地址:https://www.cnblogs.com/eleven24/p/8644007.html
Copyright © 2011-2022 走看看