• 使用自定义标签模拟jstl的<c:for each>标签


    一.自定义标签的基本编写

    下面编写一个自定义标签,它可以输出当前的时间.

    1.编写标签类

      类可以通过继承SimpleTagSupport类实现一个标签类编写.父类为我们提供了一些编写自定义标签的快捷的成员变量.而在服务器解析到自定义标签的时候,会去寻找标签类的doTag方法(这个方法在父类中有定义),并且将这些成员变量赋值.在开发中,用的最多的成员变量有2个,代表页面上下文的JspContext和代表标签内的内容的JspFragement.JSPContext对象实际上就是一个PageContext对象,它可以获得其他jsp的八大隐式对象,和存放数据.而JspFragement对象则提供了一些快捷操作标签内部内容的方法.两个对象分别通过getJspContext和getJspBody方法获得.下面给出了输出当前时间的标签类的编写:

    public class PrintTag extends SimpleTagSupport{
    
        @Override
        public void doTag() throws JspException, IOException {
            Date date=new Date();
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            PageContext pageContext = (PageContext) getJspContext();
            pageContext.getOut().write(sdf.format(date));
        }
        
    }

      可以通过pagecontext对象获得jsp内置对象out来输出数据.doTag方法,在jsp引擎解析到标签的时候调用.

    2.创建一个配置文件,配置标签的相关属性.

      1>在WEB-INF目录下建立一个后缀名为.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>itheima</short-name>
          <!--声明在taglib上的命名空间-->
        <uri>http://www.xyy.com/tags</uri>
        
    </taglib>

      2>在<tag>里声明标签的属性.

    <tag>
            <!-- 标签名.在前缀:后面添加的字符串 -->
            <name>print</name>
            <!-- 实现该标签的类 -->
            <tag-class>com.xyy.tag.PrintTag</tag-class>
            <!-- body-content没有标签的主体内容,用empty -->
            <body-content>empty</body-content>
        </tag>

      <body-content>取值:
      empty:没有主体内容。简单和传统标签都能用。
      scriptless:给简单标签用的,说明主体内容是非脚本。(不能使用<%=%>这样的,但是EL表达式可以被正常解析)
      tagdependent:把主体内容的EL表达式当做普通字符串对待。

      3.在jsp页面用taglib引入,并且在页面中使用标签.

    二.自定义标签的执行流程

      执行流程如下图(需要注意的是标签处理类是线程安全的,每次访问带有标签的页面,标签处理类都会实例化.)

    三.采用自定义标签模拟foreach标签.

      1.首先在页面中将需要模拟的标签的基本形式编写好,页面如下:

    <%@page import="java.util.*"%>
    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ taglib uri="http://www.yunyun.com/demo" prefix="demo"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
         <%
             List<String> list=new ArrayList<String>();
             list.add( "hlhdidi");
             list.add("23岁");
             list.add("7000");
         %>
         <%
             Map<String,String> map=new HashMap<String,String>();
             map.put("name", "hlhdidi");
             map.put("age", "23岁");
             map.put("salary", "7000元");
             pageContext.setAttribute("map", map);
         %>
         <c:set value="<%=list %>" var="list" scope="request"></c:set>
        <demo:foreach items="${list }" var="item" varstatus="vs">
            ${vs.count }---${item }
        </demo:foreach>
        <demo:foreach items="${map }" var="en" varstatus="vs">
            ${vs.count }---${en.key }:${en.value }
        </demo:foreach>
    </body>
    </html>

      可以看出,标签中需要传递三个参数.分别是items,var,以及varstatus.如果需要传递参数到标签类中,只需要在标签类中声明对应的成员变量即可.jsp引擎在发现这些参数的时候,将会自动寻找标签类的相应属性并且进行赋值.可以看出items必须是Object类型,而var和varstatus由于仅仅是传入PageContext域中的值的标识,所以采用字符串类型.

      2.声明标签类.

      for each标签需要将每一个遍历到的当前对象传入pageContext域中,同时将状态信息传入pageContext域中,因此建立Status类描述状态信息,为了简便,status类只定义了一个成员变量count,记录当前的循环次数.

    public class Status implements Serializable{
        private int count;
    
        public int getCount() {
            return count;
        }
    
        public void setCount(int count) {
            this.count = count;
        }
        
    }

      由于items是Object的数据类型,因此需要对其进行类型判断,在标签类的内部采用Collection的引用进行接收标签的items传入的对象.随后在doTag方法中,将遍历的对象放入PageContext域中,随后执行展示的操作.这里采用getJspBody.invoke(null)方法.这个方法将会进行默认的标签内容展示.具体的标签类如下:

    public class SimpleForEachTag extends SimpleTagSupport{
    
        private String var;
        private String varstatus;
        private Object items;
        /*用Collection的引用是因为,需要在将items传入的时候,实行强制转换.
        如果用List或者Set来接收,那么当只能强转为List/Set.
        因为,将一个类型的对象强制转化为一个不匹配的引用会报错,所以只能用Collecion来接收*/
        private Collection list=new ArrayList();    
        
        public void setVar(String var) {
            this.var = var;
        }
        
        public void setVarstatus(String varstatus) {
            this.varstatus = varstatus;
        }
        //为了方便遍历,进行强制类型转换
        public void setItems(Object items) {
            //在这里会将items传入
            if(items instanceof List) {
                list=(List)items;
            }
            else if(items instanceof Set) {
                list=(Set)items;
            }
            else if(items instanceof Map) {
                list=((Map)items).entrySet();
            }
            else if(items instanceof Object[]) {
                list=Arrays.asList((Object[])items);
            }
        }
    
    
        @Override
        public void doTag() throws JspException, IOException {
            PageContext pageContext = (PageContext) getJspContext();
            Status status=new Status();
            int i=0;//循环次数
            if(list!=null) {
                for(Object obj:list) {
                    //放入pageContext域中
                    pageContext.setAttribute(var, obj);
                    status.setCount(++i);
                    pageContext.setAttribute(varstatus, status);
                    getJspBody().invoke(null);     //默认的输出
                }
            }
            
        }
        
    }

      3.配置标签.

      配置如下:

    <tag>
            <name>foreach</name>
            <tag-class>com.xyy.tag.SimpleForEachTag</tag-class>
            <body-content>scriptless</body-content>
            <!-- 设置属性的值 -->
            <attribute>
            <!-- 属性名 -->
                <name>items</name>
            <!-- 属性是否必须 -->
                <required>true</required>
            <!--
                     属性是否支持Java表达式/EL表达式.true为支持,false不支持
                    如果不支持的时候在设置属性时,如果写了EL表达式.会抛出异常
                 -->
                <rtexprvalue>true</rtexprvalue>
            </attribute>
            <attribute>
                <name>var</name>
                <required>true</required>
                <rtexprvalue>true</rtexprvalue>
            </attribute>
            <attribute>
                <name>varstatus</name>
                <required>true</required>
                <rtexprvalue>true</rtexprvalue>
            </attribute>
        </tag>

    四.总结

      自定义标签是一个很有用的功能,可以通过最基本的自定义标签的学习,在jsp页面中完成我们想要的功能展示.

  • 相关阅读:
    react-native window下创建Hello(解决创建一路的坑)
    vue2.0 监听滚动 锚点定位
    vue-awesome-swiper 轮播图使用
    vue和react区别
    vuex 管理状态
    vue 解决axios 跨域问题
    判断一个对象是否为空? js
    微信小程序中的自定义组件(components)
    深入理解ES6箭头函数中的this
    vue中组件的data为什么是一个函数
  • 原文地址:https://www.cnblogs.com/hlhdidi/p/6052257.html
Copyright © 2020-2023  润新知