Java ---自定义标签

     本篇文章介绍自定义标签,可能在工作中很少涉及到自己来定义一个标签库,因为我们基本上都是使用的大神写的标签库,基本上直接使用即可,但是从自身的发展来看,通往高级程序员的道路上,开发框架就需要大量的使用到标签库技术。本文将从以下几个方面介绍自定义标签库的基本知识点:

  • 背景以及作用
  • 开发简单的标签
  • 开发带属性的标签
  • 开发带标签体的标签
  • 以页面片段为属性的标签
  • 具有动态属性的标签

一、标签库有什么作用      自定义标签库是一种优秀的表现层技术,之前介绍的MVC模式,我们使用jsp作为表现层,但是jsp语法嵌套在html页面,美工还是很难直接参与开发,并且jsp脚本和html代码耦合在一起,维护成本较高。我们能不能开发一套和html风格类似并且能完成jsp脚本功能的标签来解决这种低效的协作方式呢?于是标签库就诞生了。

这是Java中标签规范的继承体系,实现Tag接口的我们叫做传统式标签库开发,这种开发模式略显发复杂,基本已经被SimpleTag式的简单式开发标签库给取代了。Java中提供了一个默认的实现类SimpleTagSupport来实现自定义标签,我们只要继承此类即可。

二、开发一个最简单的标签库      开发一个自定义标签库的过程如下:

  • 开发自定义标签处理类
  • 创建*.tld文件,每个此文件对应一个标签库,标签库中可以由多个标签
  • 在jsp页面使用标签

首先我们先从自定义标签处理类开始,正如上文所说,这个类只有继承了SimpleTagSupport这个类可以省去省去重写SimpleTag接口中的一些方法。我们说个doTag()这个方法很重要,这个方法类似于我么main方法一样,当jsp页面加载到我们定义的标签的时候就会过来调用这个方法。

public class MyTag extends SimpleTagSupport {

    @Override
    public void doTag() throws JspException, IOException {
        getJspContext().getOut().write("hello walker");
    }
}

这是一个简单的标签处理类,具体的细节暂时不用关心,只需要知道,它负责向jsp页面输出字符串即可。下面我们看看第二步,创建*tld文件。这个文件我们没有必要重新写一遍,到Tomcat服务器上的webapps/examples/WEB-INF/jsp2中复制一个过来,修改名字存放到我们的项目中WEB-INF的任意子路径下。删除一些标签成如下内容:

我们看到这是一个XML文件,根元素为taglib,而taglib主要有以下几个子元素:

  • description //描述信息
  • tlib-version //指定标签库的版本号,基本不用我们操心
  • short-name //指定标签库的短名字,也是没什么用
  • uri //这是一个重要的子元素,是该标签库的唯一标识
  • tag //看名字就知道,这是定义标签的子元素,很重要

     对于taglib这个根元素,我们主要关心他下面的uri和tag两个子元素,一个标签库可以由多个标签,也就是可以有多个tag标签。关于tag标签,主要有以下几个子元素:

  • description //描述信息
  • name //该标签的唯一标识,很重要
  • tag-class //指定了处理该标签的类,也就是使用该标签谁给我返回结果
  • body-content //标签体,后面详说,很重要
  • attribute //属性,后面介绍,很重要

对于以上标签大家可能已经知道什么意思,但是具体用在什么地方可能不清楚,本小节的最后会综合三个步骤自定义一个简单的标签。接下来介绍在jsp页面是如何使用标签。      使用标签库也是有两个步骤,首先导入标签库,然后引用标签。我们使用taglib编译指令导入标签库,具体格式如下:

<%@ taglib uri="tld文件中指定的唯一标识" prefix="指定标签前缀"%>

我们看到这个导入标签库的编译指令主要有两个属性,一个是用于定位我们已经写好的标签库,定位的方法就是读取每个tld文件中的URI元素的值,prefix用于指定我们使用标签时的前缀,等用的时候就很容易理解了,现在解释反而不容易说清楚。我们使用标签的格式如下:

<刚刚指定的前缀 :标签名 />

标签名就是我们标签库中每个tag都会有的name的值,这指定了该语句是引用的那个标签。下面我们通过具体的例子直观感受下。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="mytid" prefix="mytags"%>
<html>
  <head>
    <title></title>
  </head>
  <body>
    <mytags:hello />
  </body>
</html>
<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>A tag library exercising SimpleTag handlers.</description>
    <tlib-version>1.0</tlib-version>
    <short-name>SimpleTagLibrary</short-name>
    <uri>mytid</uri>

    <tag>
        <description>Outputs a colored tile</description>
        <name>hello</name>
        <tag-class>Test.MyTag</tag-class>
        <body-content>empty</body-content>
    </tag>

</taglib>
public class MyTag extends SimpleTagSupport {

    @Override
    public void doTag() throws JspException, IOException {
        getJspContext().getOut().write("hello walker");
    }
}

结果如下:

     这就完成了一个最简单的标签库的定义和使用的过程,首先我们在index.jsp页面通过URI引入mytag标签库,指定了使用该标签库的前缀为mytags,然后<mytags:hello />引用name为hello的tag标签,然而在加载这条语句的时候会通过我们的tag中指定的处理类,找到它并执行,最后通过此标签处理类想我们的jsp页面输出了一个字符串。以上就是一个最简单的自定义标签的过程,为了更好的理解后续的较复杂的自定义标签方式,上述内容值得感受体会。

三、开发带属性的标签      假如我们通过拦截器获取了从数据库查出来的一个结果集,我们此处希望调用标签来将结果集以表格的形式输出来,此时我们的这个结果集又该如何传到标签处理类中呢?这时我们可以使用属性。具体看代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="mytid" prefix="mytag"%>
<html>
  <head>
    <title></title>
  </head>
  <body>
  <%
    HashMap<String,Integer> maps = new HashMap<String, Integer>();
    maps.put("李四",53);
    maps.put("张三",23);
    maps.put("walker",22);
    pageContext.setAttribute("map",maps);
  %>
      <table>
        <mytag:hello map="map"/>
      </table>
  </body>
</html>
<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>A tag library exercising SimpleTag handlers.</description>
    <tlib-version>1.0</tlib-version>
    <short-name>SimpleTagLibrary</short-name>
    <uri>mytid</uri>

    <tag>
        <description>Outputs a colored tile</description>
        <name>hello</name>
        <tag-class>Test.MyTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>map</name>
            <required>true</required>
            <fragment>true</fragment>
        </attribute>
    </tag>

</taglib>
public class MyTag extends SimpleTagSupport {

    private String map;
    public String getMap(){
        return this.map;
    }
    public void setMap(String map){
        this.map = map;
    }
    @Override
    public void doTag() throws JspException, IOException {
        HashMap<String,Integer> maps = (HashMap<String,Integer>)(getJspContext().getAttribute(map));
        Object[] array = maps.keySet().toArray();

        for (String str : maps.keySet()){
            getJspContext().getOut().write("<tr>");
            getJspContext().getOut().write("<td>");
            getJspContext().getOut().write(str);
            getJspContext().getOut().write("</td>");
            getJspContext().getOut().write("<td>");
            getJspContext().getOut().write(""+maps.get(str));
            getJspContext().getOut().write("</td>");
            getJspContext().getOut().write("</tr>");
        }
    }
}

我们首先先从index.jsp页面看起,首先我们定义了一个HashMap用来存放一个简单的个人信息,键为姓名值为年龄。最后我们设置共享范围为当前page。然后<mytag:hello map="map"/>,这里的map=“map”,第一个map是属性名,第二个只是一个字符串。下面进入到tld页面看,这个页面基本没有什么改动,只是多了个attribute元素,attribute中有几个子元素,第一个是name指定这个属性的唯一标识,第二个required指定该属性是否是必须属性。第三个fragment指定该属性是否支持jsp脚本。主要关心name这个元素。这个值和jsp页面调用标签时使用的属性名必须一样,并且这个属性值还必须和标签处理类中的私有属性名一样,这就是为了jsp页面的属性值能够自动的传入到标签处理类的属性中,我们看这个标签处理类      这个类定义了私有属性map,和我们的tld文件中的属性名是一致的。getJspContext().getAttribute(map),首先是获得了调用该标签的jsp页面的pageContext,这就是方法getJspContext的返回值,因为我们在jsp页面设置了一个共享数据(maps),于是我们同名名字获取该对象,这里的map就是我们的私有属性,他的值被自动赋值了,具体的值就是jsp页面传入的参数。后面的代码就很简单了,循环输出数据到jsp页面上。      稍微理一下思路,这种带属性的标签使用其实和无属性差不多,都是先引入了标签库,加载标签的的时候通过URI找到对应的标签库,只不过这次将一个字符串赋值给了tld中attribute元素中名为map的属性,然后跳向对应的标签处理类,顺便把map属性的值自动赋值处理类中的私有属性,然后执行输出代码。其中需要注意的是属性名一定要统一,另外,如果标签的属性值是8种基本数据类型,那么在JSP页面在传递字符串时,JSP引擎会自动转换成相应的类型,但如果标签的属性值是复合数据类型,那么JSP引擎是无法自动转换的。对于传递非基本数据类型的操作,后续文章会介绍。

     为了篇幅不过于长,还剩下的内容留在下篇,如有错误,望指出!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏快乐八哥

jQuery.unique引发一个血案

项目开发过程中,PM说系统只要在一个特定的浏览器中运行就好,但是在其他的浏览器中不能出现逻辑的错误,所以在开发过程中,前端和后台选择是Chrome浏览器,没有仔...

1788
来自专栏pangguoming

vue-自定义组件传值

项目中,我们经常会遇到自定义组件传值的问题,方法很多种,但是原理很简单,下述文档总结实际项目中使用的传值方式。

771
来自专栏GreenLeaves

JS框架设计之加载器所在路径的探知一模块加载系统

1、要加载一个模块,我们需要一个URL作为加载地址,一个script作为加载媒介,但用户在require是都用ID,我们需要一个将ID转换为URL的方法,思路很...

1855
来自专栏木子昭的博客

模拟Vue数据的双向绑定

Vue的数据双向绑定功能一直为人称道, Vue数据的双向数据绑定主要依赖了Object.defineProperty,这里尝试用最简单的代码, 实现数据的双向...

3285
来自专栏知道一点点

走进AngularJs(二) ng模板中常用指令的使用方式

  通过使用模板,我们可以把model和controller中的数据组装起来呈现给浏览器,还可以通过数据绑定,实时更新视图,让我们的页面变成动态的。ng的模板真...

852
来自专栏软件开发

前端MVC Vue2学习总结(三)——模板语法、过滤器、计算属性、观察者、Class 与 Style 绑定

Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML ,...

52010
来自专栏互联网杂技

编码规范

不要在自闭合(self-closing)元素的尾部添加斜线 -- HTML5 规范中明确说明这是可选的。 不要省略可选的结束标签(closing tag)(例如...

3237
来自专栏前端学习心得

Vue2.0学习(四)--组件的继承与扩展

本文将介绍vue2.0中的组件的继承与扩展,主要分享slot、mixins/extends和extend的用法。

831
来自专栏AndroidTv

View.animate()动画ViewPropertyAnimator原理解析

这次想来讲讲 View.animate(),这是一种超好用的动画实现方式,用这种方式来实现常用的动画效果非常方便,但在某些场景下会有一个坑,所以这次就来梳理一下...

3795
来自专栏大数据钻研

献给前端的小伙伴,祝大家面试顺利!

HTML相关问题 1.XHTML和HTML有什么区别 HTML是一种基本的WEB网页设计语言,XHTML是一个基于XML的置标语言 最主要的不同: XHTM...

2725

扫码关注云+社区