簡(jiǎn)單擴(kuò)展讓beetl HTML標(biāo)簽支持父子嵌套

字號(hào):


    默認(rèn)情況下,Beetl的html標(biāo)簽并不支持父子嵌套,就像類似jsp標(biāo)簽?zāi)菢樱笜?biāo)簽需要知道子標(biāo)簽的信息,子標(biāo)簽也需要知道父標(biāo)簽信息。但是beetl只需要簡(jiǎn)單擴(kuò)展,就能完成嵌套標(biāo)簽支持。
    首先看一個(gè)最終的使用效果,實(shí)現(xiàn)倆個(gè)html標(biāo)簽table.tag,tr.tag.可以在頁(yè)面上這么用:
    <#table data ="${userList}">
    <#tr name="name"> 名稱 </#tr>
    </#table>
    在閱讀table.tag,tr.tag之前,先看看如何擴(kuò)展html標(biāo)簽
    首先,需要擴(kuò)展 HTMLTagSupportWrapper,這個(gè)類是html標(biāo)簽實(shí)現(xiàn)類,我們可以擴(kuò)展此類來(lái)定制化需求,然后重新注冊(cè)覆蓋。因此實(shí)現(xiàn)類
    public class HTMLNestTagSupportWrapper extends HTMLTagSupportWrapper{
    public void render(){....}
    }
    然后在配置文件配置TAG.htmltag= bingo.util.HTMLNestTagSupportWrapper 就可以生效。
    HTMLNestTagSupportWrapper用到了TagNestContext類,這個(gè)類其實(shí)就是一個(gè)樹(shù)形結(jié)構(gòu),記錄了parent的Context,記錄了當(dāng)前tag信息,以及記錄了子tag的Context,這樣,每個(gè)tag都可以訪問(wèn)父tag或者子tag:代碼如下
    public class TagNestContext {
    private Tag tag = null;
    private TagNestContext parent = null;
    private List<TagNestContext> children = null;
    public Tag getTag() {
    return tag;
    }
    public void setTag(Tag para) {
    this.tag = para;
    }
    public TagNestContext getParent() {
    return parent;
    }
    public void setParent(TagNestContext parent) {
    this.parent = parent;
    }
    public List<TagNestContext> getChildren() {
    if(children==null) children = new ArrayList<TagNestContext>();
    return children;
    }
    public void setChildren(List<TagNestContext> children) {
    this.children = children;
    }
    }
    回頭在看看 HTMLNestTagSupportWrapper實(shí)現(xiàn)
    public void render()
    {
    HttpServletRequest request = (HttpServletRequest)this.ctx.getGlobal("request");
    TagNestContext tnc = (TagNestContext)request.getAttribute("tagContext");
    if(tnc==null){
    tnc = new TagNestContext();
    tnc.setTag(this);
    request.setAttribute("tagContext", tnc);
    super.render();
    request.removeAttribute("tagContext");
    }else{
    TagNestContext child = new TagNestContext();
    child.setParent(tnc);
    child.setTag(this);
    tnc.getChildren().add(child);
    request.setAttribute("tagContext", child);
    super.render();
    //重新設(shè)置
    request.setAttribute("tagContext", child.getParent());
    }
    }
    public String getTagName(){
    return (String)this.args[0];
    }
    public Object get(String attr){
    Map map = (Map)this.args[1];
    return map.get(attr);
    }
    如上代碼所示,但渲染某個(gè)htmltag前(調(diào)用super.render()前),可以從request里獲取NestContext,如果沒(méi)有,生成一個(gè)新的NestContext。如果已經(jīng)存在。則將當(dāng)前NestContext加入到父NestContext。渲染完畢后,需要重置NestContext。
    最后看一下tr.tag如何實(shí)現(xiàn),tr僅僅實(shí)現(xiàn)了生成表頭
    <tr>${tagBody}</tr>
    table.tag 則要麻煩點(diǎn),需要知道有多少個(gè)tr,然后輸出數(shù)據(jù),內(nèi)容如下:
    <table>
    ${tagBody}
    <% for(var item in data){%>
    <tr>
    <%
    var tag = getTagContext();
    var children = tag.children;
    for(var tdTagCtx in children){
    print("<td>");
    var tdTag = tdTagCtx.tag;
    var name = tdTag.tagName;
    var value = item[name];
    print(value);
    println("</td>");
    }
    %>
    </tr>
    <%} %>
    </table>
    etTagContext 是一個(gè)注冊(cè)方法,獲取當(dāng)前context.可以自行開(kāi)發(fā)一個(gè)