定制自己的专属标记库

原创
2012/06/25 13:10
阅读数 222

最近朋友在自己做一个小型的ORM框架,想让我帮忙为他的数据结构定制一套专属的标记库,方便输出,看了下需求,和JSTL的forEach和out比较像。觉得比较简单,认为很快能搞定。但由于本人大三,只有一年左右的开发经验,经验不足,对定制标记库也只了解过,因此,在开发过程中遇到了很多问题。先贴上一段源码吧:

/**
 *
 * @author  张浩春 @time  2012-6-24 14:03:59
 */
public class ForEachTaglib extends BodyTagSupport {

    private List<EasyData> items;//数据来源
    private static String var;//对象名称
    private String index;//下标名称
    private static Integer i = 0;//下标

    public static Integer getI() {
        return i;
    }

    public static String getVar() {
        return var;
    }

    public void setIndex(String index) {
        this.index = index;
    }

    public void setItems(List<EasyData> items) {
        this.items = items;
    }

    public void setVar(String var) {
        ForEachTaglib.var = var;
    }

    @Override
    public int doEndTag() throws JspException {
        BodyContent body = getBodyContent();
        JspWriter out = body.getEnclosingWriter();
        String content = body.getString();
        try {
            out.println(content);//在循环结束后一次性输出内容
        } catch (IOException ex) {
            Logger.getLogger(ForEachTaglib.class.getName()).log(Level.SEVERE, null, ex);
        }
        var = null;//将变量置为空,释放空间
        return EVAL_PAGE;
    }

    @Override
    public int doAfterBody() throws JspException {
        if (items != null) {
            if (i >= items.size()) {//如果循环结束,那么必须返回SKIP_BODY常量结束循环,否则将死循环
                i = 0;
                return SKIP_BODY;
            }
            if (i == 0) {//第0将循环为空循环,需要将BODY清空
                BodyContent body = getBodyContent();
                body.clearBody();
            }
            super.pageContext.setAttribute(var, items.get(i));//将第i个对象存储到pageContext作用域下
            if (index != null && !index.equals("")) {//如果用户指定了index的变量名称,则将下标存储到pageContext用域下
                super.pageContext.setAttribute(index, i);
            }
            i++;
            return EVAL_BODY_AGAIN;
        } else {//如果数据来源为空,则跳出循环,否则会死循环导致内存溢出
            BodyContent body = getBodyContent();
            body.clearBody();
            return SKIP_BODY;
        }

    }
}

再附上<h:out>的代码吧

@Override
    public int doStartTag() throws JspException {
        if (data != null) {//如果用户指定了数据来源,那么将优先输出该数据,输出完成直接返回
            Object columnData;
            if (column.matches("^[0-9]\\d*$")) {//如果用户填写的是数字,那么将按下标输出
                try {
                    columnData = data.get(Integer.parseInt(column));
                    pageContext.getOut().println(columnData);//输出数据
                } catch (Exception e) {
                    System.out.println("Column " + column + " in the data does not exist.");
                }
            } else {
                try {
                    columnData = data.get(column);
                    pageContext.getOut().println(columnData);//按列名输出数据
                } catch (Exception e) {
                    System.out.println("Column " + column + " in the data does not exist.");
                }
            }
            return EVAL_PAGE;
        }
        if (ForEachTaglib.getVar() == null) {
            return EVAL_PAGE;
        }
        if (super.pageContext.getAttribute(ForEachTaglib.getVar()) == null) {//此次数据为空,则直接返回
            return EVAL_PAGE;
        }
        EasyData data = (EasyData) super.pageContext.getAttribute(ForEachTaglib.getVar());
        if (column != null && !column.equals("")) {
            Object columnData;
            if (column.matches("^[0-9]\\d*$")) {//如果用户填写的是数字,那么将按下标输出
                try {
                    columnData = data.get(Integer.parseInt(column));
                    pageContext.getOut().println(columnData);//输出数据
                } catch (Exception e) {
                    System.out.println("Column " + column + " in the data does not exist.");
                }
            } else {
                try {
                    columnData = data.get(column);
                    pageContext.getOut().println(columnData);//按列名输出数据
                } catch (Exception e) {
                    System.out.println("Column " + column + " in the data does not exist.");
                }
            }

        }
        return EVAL_PAGE;
    }

由于OUT标签是配合forEach一起使用的,为了方便起见,最开始out继承自forEach,正常情况下,其执行顺序应该为:

forEach:startTag

forEach:initBody

forEach:after

out:startTag

..

forEach:endTag

但实际上我的forEach:endTag却和after一起循环了,找了好久不知道为什么,改为不继承后就好了,哪位大神知道原因呢?求解释!!!

需要说明的是,在forEach中如果想循环,一定要在afterTag中返回EVAL_BODY_AGAIN.

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部