Java ---自定义标签(二)

     上篇文章的最后,我们自定义了一个带属性的标签,并使用它完成了一个简单的案例。其实到这我们已经可以看出来,前端jsp页面只需要写一个类似html语法的标签,就可以完成将集合中的数据取出来并展示这么相对复杂的操作。这就是我们使用标签的意义。接着上篇文章,我们看看怎么自定义一个带有标签体的标签。

一、开发带标签体的标签      我们可以利用标签体来简化我们上一个案例中的标签处理类。

<%@ 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">
            <tr>
              <td>${name}</td>
              <td>${age}</td>
            </tr>
        </mytag:hello>
      </table>
  </body>
</html>
<tag>
        <description>Outputs a colored tile</description>
        <name>hello</name>
        <tag-class>Test.MyTag</tag-class>
        <body-content>scriptless</body-content>
        <attribute>
            <name>map</name>
            <required>false</required>
            <fragment>true</fragment>
        </attribute>
    </tag>
public void doTag() throws JspException, IOException {
        HashMap<String,Integer> maps = (HashMap<String,Integer>)(getJspContext().getAttribute(map));
        for (String str : maps.keySet()){
            getJspContext().setAttribute("name",str);
            getJspContext().setAttribute("age",maps.get(str));
            getJspBody().invoke(null);

        }
    }

有些并没有改动的代码没有列出,只展示了关键的代码块。首先看jsp页面,有标签体的标签使用的时候是需要有开始标签和结束标签的,这一点是和html很像的。至于td元素中的内容,这是一个EL表达式,不知道的朋友可以快速百度下,这里的意思就是在当前页面寻找共享数据名为name和age的数据,找到就获取其值,否则为“”,非null。tld文件中的改动不多,就是将body-content的值改动成scriptless,这表示标签体可以是静态的html,但是不能是jsp脚本。而我们之前一直是empty,它指定该标签是没有标签体的。      接下来看看我们标签处理类的改动,原先冗长的输出代码,被替换成以下三条语句:

getJspContext().setAttribute("name",str);
getJspContext().setAttribute("age",maps.get(str));
getJspBody().invoke(null);

前面两条语句很简单,在jsp页面设置page范围内的共享数据,主要是提供我们的标签中EL表达式使用。getJspBody()表示获取整个标签体的所有内容,返回的是一个fragment对象,这个对象的一个方法invoke就是用于输出整个内容到jsp页面,如果参数为null表示直接输出,还可以使用Writer作为参数传入,意思是将标签体的内容全部输入到这个字符流中,然后你可以通过一些操作,再次使用write方法输出到jsp页面。也就是说,如果对于标签体中的数据内容需要做一些判断操作的话,可以传递一个writer流,处理完成之后可以再次输出到页面上。

二、开发以页面片段为属性的标签      我们的attribute可以上八种数据类型,因为jsp引擎是可以为我们自动转换并自动赋值到我们标签处理类的私有属性中,但是对于之外的类型都是不可以直接操作的,我们首先看如何以页面片段作为属性,传递。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="mytid" prefix="mytag"%>
<html>
  <head>
    <title></title>
  </head>
  <body>
      <mytag:hello>
          <jsp:attribute name="map">
              <h1>hello</h1>
          </jsp:attribute>
      </mytag:hello>
  </body>
</html>

我们使用jsp:attribute这个动作指令来完成给属性赋值上页面片段,name的值对应于tld中的属性name值。

<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>false</required>
            <fragment>true</fragment>
        </attribute>
    </tag>

对于jsp页面以页面片段作为属性传入的参数,我们在标签处理类中是需要定义私有属性来接受的,在jsp中将页面片段定义为jspfregment类型,于是我们定义私有属性。

public class MyTag extends SimpleTagSupport {

    private JspFragment map;
    public JspFragment getMap(){
        return this.map;
    }
    public void setMap(JspFragment map){
        this.map = map;
    }
    @Override
    public void doTag() throws JspException, IOException {
        map.invoke(null);
    }
}

调用JspFragment 的invoke方法可以直接输出其中的内容。结果如下:

     稍微小结一下,之前我们传递属性值的时候是在标签名的后面添加属性名和属性值,但那时的属性值只限于字符串,你不能传递别的类型的内容。此处我们为了能够传递页面片段,通过jsp:attribute动作指令来给我们的属性赋值,而这个值的内容就是一个页面片段。上文中我们在介绍自定义标签体的时候,我们说可以使用getJspBody可以获得标签体的内容,其实这个方法返回的也是一个fregment,所以我们可以调用invoke方法输出标签体内容。

三、开发动态属性标签      在我们之前介绍的内容中,传递的属性个数都是固定的,但是在实际开发中往往又会遇到有些参数必须传入有些选择性的传入,这样每个人传递的属性的个数都是不一样的,服务器端该如何处理呢?我们可以使用动态属性标签,使用此标签之前,我们的标签处理类就必须要继承接口DynamicAttributes,这个接口中就只有一个方法,setDynamicAttribute这个方法就是来完成动态的给我们传递的属性赋值。这是第一点,第二点就是需要在tld文件中配置一条语句,表名这个tag是支持动态属性的。下面是demo:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="mytid" prefix="mytag"%>
<html>
  <head>
    <title></title>
  </head>
  <body>
      <mytag:hello name="张三" age="23"/><hr/>
      <mytag:hello name="张三" age="23" student="ok"/><hr/>
      <mytag:hello name="张三" age="23" walker="yam"/>
  </body>
</html>
<tag>
        <description>Outputs a colored tile</description>
        <name>hello</name>
        <tag-class>Test.MyTag</tag-class>
        <body-content>scriptless</body-content>
        <dynamic-attributes>true</dynamic-attributes>
    </tag>
public class MyTag extends SimpleTagSupport implements DynamicAttributes{
    private ArrayList<String> keys = new ArrayList<String>();
    private ArrayList<Object> values = new ArrayList<Object>();

    @Override
    public void doTag() throws JspException, IOException {
        for(int i=0;i<keys.size();i++){
            getJspContext().getOut().write(""+keys.get(i)+values.get(i));
        }
    }
    @Override
    public void setDynamicAttribute(String var1, String var2, Object var3) throws JspException{
            keys.add(var2);
            values.add(var3);
    }
}

做一点解释,setDynamicAttribute这个方法中有三个参数,我们通常只使用后面两个参数,一个代表属性名,一个代表属性值。那么第一个参数表示什么意思呢?官方解释是:

uri - -the namespace of the attribute, or null if in the default namespace.

这是该属性的命名空间,如果没有显式指定就是null。我们暂时可以不用关心。

     最后还是要强调一点,属性的的只能使基本的数据类型,对于一些复杂的类型 ,例如Date,等,建议将该对象置于本页共享范围,然后标签处理类可以直接获取并做相应的处理。

     自定义标签介绍完了,如有错误,望指出!

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏互联网杂技

SpringBoot ( 四 ) :thymeleaf 使用详解

简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。相较与其他的模板引擎,它有如下三个极吸...

1103
来自专栏marsggbo

python编码问题之\"encode\"&\"decode\"

python encode decode 编码 decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode(‘gb2312’),表...

1789
来自专栏LanceToBigData

SpringBoot(四)之thymeleaf的使用

这篇文章将更加全面详细的介绍thymeleaf的使用。thymeleaf 是新一代的模板引擎,在spring4.0中推荐使用thymeleaf来做前端模版引擎。...

36410
来自专栏互联网杂技

js事件

1.document.write(""); 输出语句 2.JS中的注释为// 3.传统的HTML文档顺序是:document->html->(head,body...

33211
来自专栏崔庆才的专栏

Javascript调试命令——你只会Console.log() ?

Console 对象提供对浏览器控制台的接入(如:Firefox 的 Web Console)。不同浏览器上它的工作方式是不一样的,但这里会介绍一些大都会提供的...

2884
来自专栏求索之路

MVVM架构篇之databinding源码解析

databinding是google去年发布的一个库,它支持在xml中写表达式使得viewModel中的数据能够绑定到view中,目前已经支持双向绑定,也就是...

2114
来自专栏Android随笔

Android开发实践

网上大部分命名规范文章里,并不是以模块名开头的,可能是习惯不一样,也有可能我的做法是错误的。希望您能及时指正,谢谢! 把模块名称放在最前面,再配合Androi...

633
来自专栏王肖的UT

GLSL-语法基础

1506
来自专栏有趣的django

7.python常用模块

time模块 常用表示时间方式: 时间戳,格式化的时间字符串,元组(struct_time) UTC(Coordinated Universal Time,世界...

35210
来自专栏一个爱瞎折腾的程序猿

nodejs常用代码片段

调用:node index.js --target test 接收:const config=loadConifg(['target'],'--') //co...

672

扫码关注云+社区