|            
执行模板    这里所讨论的模板将在三种定制标签下执行: 
    Template: insert 
    Template: put 
    Template: get 
    insert 标签中包含一个模板,但是在包含之前,put 标签存储有一些信息——name, URI和Boolean 值(用来指定将内容是包含还是直接显示)——关于模板所包含的内容。在template:get中包含(或显示)了指定的内容,随后将访问这些信息。 
    template:put 把Bean 存储在请求区域(但并不直接存储),因为如果两个模板使用了相同的内容名,一个嵌套模板就将覆盖封装模板中的内容。 
    为了保证每一个模板能够只存取它自己的信息,template:insert 保留了一个hashtable堆栈。每一个insert 开始标签建立一个 hashtable并把它放入堆栈。封装的put 标签建立bean并把它们保存到最近建立的hashtable中。随后,在被包含模板中的 get 标签访问hashtable中的bean。图 4 显示了堆栈是如何被保留的。 
 
    图 4. 在请求区域存储模板参数 点击放大(24 KB) 
    在图 4中每一个模板访问正确的页脚、footer.html 和footer_2.html。如果 bean被直接存储在请求区域,图 4中的step 5将覆盖在step 2中指定的footer bean。 
  模板标签执行    接下来我们将分析三个模板标签的执行: insert, put和get。我们先从图 5开始。这个图表说明了当一个模板被使用时,insert和put标签事件的执行顺序。 
 
    图 5. put和insert 标签执行顺序 点击放大(24 KB) 
    如果一个模板堆栈已经不存在,insert 开始标签就会建立一个并把它放置到请求区域。随后一个hashtable也被建立并放到堆栈中。 
    每一个 put 开始标签建立一个PageParameter bean,并存储在由封装的insert标签建立的hashtable中。 
    插入 end 标签包含了这个模板。这个模板使用get标签来访问由put标签建立的bean。在模板被处理以后,由insert 开始标签建立的hashtable就从堆栈中清除。 
    图 6显示template:get的顺序图表。 
 
    图 6. get标签的顺序图表 点击放大(11 KB) 
  模板标签列表    标签handler很简单。在例 3.a中列出了Insert标签类——标签handler。 
    例 3.a. InsertTag.java 
    packagetags.templates; 
    import java.util.Hashtable; 
    import java.util.Stack; 
    import javax.servlet.jsp.JspException; 
    import javax.servlet.jsp.PageContext; 
    import javax.servlet.jsp.tagext.TagSupport; 
    public class InserttagextendstagSupport { 
     private Stringtemplate; 
     private Stack stack; 
     // setter method fortemplate 属性 
     public void setTemplate(Stringtemplate) { 
       this.template =template; 
     } 
     public int doStartTag() throws JspException { 
       stack = getStack(); // obtain a reference to thetemplate stack 
       stack.push(new Hashtable()); // push new hashtable onto stack 
       return EVAL_BODY_INCLUDE; // pass tagbody through unchanged 
     } 
     public int doEndTag() throws JspException { 
       try { 
         pageContext.include(template); // includetemplate 
       } 
       catch(Exception ex) { // IOException or ServletException 
         throw new JspException(ex.getMessage()); // recast exception 
       } 
       stack.pop(); // pop hashtable off stack 
       return EVAL_PAGE; // evaluate the rest of the page after the tag 
     } 
     // taghandlers should always implement release() because 
     // handlers can be reused by the JSP container 
     public void release() { 
       template = null; 
       stack = null; 
     } 
     public Stack getStack() { 
       // try to get stack from request scope 
       Stack s = (Stack)pageContext.get属性( 
                "template-stack", 
                PageContext.REQUEST_SCOPE); 
       // if the stack's not present, create a new one和 
       // put it into request scope 
       if(s == null) { 
         s = new Stack(); 
         pageContext.set属性("template-stack", s, 
                PageContext.REQUEST_SCOPE); 
       } 
       return s; 
     } 
    } 
    例 3.b 列出了 Put标签类和标签handler: 
    例 3.b. PutTag.java 
    packagetags.templates; 
    import java.util.Hashtable; 
    import java.util.Stack; 
    import javax.servlet.jsp.JspException; 
    import javax.servlet.jsp.tagext.TagSupport; 
    import beans.templates.PageParameter; 
    public class PuttagextendstagSupport { 
     private String name, content, direct="false"; 
     // setter methods for Put tag attributes 
     public void setName(String s) { name = s; } 
     public void setContent(String s) {content = s; } 
     public void setDirect(String s) { direct = s; } 
     public int doStartTag() throws JspException { 
       // obtain a reference to enclosing insert tag 
       Inserttagparent = (InsertTag)getAncestor( 
                   "tags.templates.InsertTag"); 
       // puttags must be enclosed in an insert tag 
       if(parent == null) 
         throw new JspException("PutTag.doStartTag(): " + 
                    "No Inserttagancestor"); 
       // gettemplate stack from insert tag 
       Stacktemplate_stack = parent.getStack(); 
       //template stack should never be null 
       if(template_stack == null) 
         throw new JspException("PutTag: notemplate stack"); 
       // peek at hashtable on the stack 
       Hashtable params = (Hashtable)template_stack.peek(); 
       // hashtable should never be null either 
       if(params == null) 
         throw new JspException("PutTag: no hashtable"); 
       // put a new PageParameter in the hashtable 
       params.put(name, new PageParameter(content, direct)); 
       return SKIP_BODY; // not interested in tagbody, if present 
     } 
     // taghandlers should always implement release() because 
     // handlers can be reused by the JSP container 
     public void release() { 
       name = content = direct = null; 
     } 
     // convenience method for finding ancestor names with 
     // a specific class name 
     privatetagSupport getAncestor(String className) 
                     throws JspException { 
       Class klass = null; // can't name variable "class" 
       try { 
         klass = Class.forName(className); 
       } 
       catch(ClassNotFoundException ex) { 
         throw new JspException(ex.getMessage()); 
       } 
       return (TagSupport)findAncestorWithClass(this, klass); 
     } 
    } 
    PutTag.doStarttag建立了一个 PageParameter bean – 在例 3.c中列出——然后存储到请求区域。 
    例 3.c. PageParameter.java 
    package beans.templates; 
    public class PageParameter { 
     private String content, direct; 
     public void setContent(String s) {content = s; } 
     public void setDirect(String s) { direct = s; } 
     public String getContent() { return content;} 
     public boolean isDirect() { return Boolean.valueOf(direct).booleanValue(); } 
     public PageParameter(String content, String direct) { 
       this.content = content; 
       this.direct = direct; 
     } 
    } 
    PageParameter将作为简单的占位符使用。我们来看一看例 3.d中的Gettag类和tag handler: 
    例 3.d. GetTag.java 
    packagetags.templates; 
    import java.util.Hashtable; 
    import java.util.Stack; 
    import javax.servlet.jsp.JspException; 
    import javax.servlet.jsp.PageContext; 
    import javax.servlet.jsp.tagext.TagSupport; 
    import beans.templates.PageParameter; 
    public class GettagextendstagSupport { 
     private String name; 
     // setter method for name attribute 
     public void setName(String name) { 
       this.name = name; 
     } 
     public int doStartTag() throws JspException { 
       // obtain reference totemplate stack 
       Stack stack = (Stack)pageContext.get attribute ( 
           "template-stack", PageContext.REQUEST_SCOPE); 
       // stack should not be null 
       if(stack == null) 
         throw new JspException("GetTag.doStartTag(): " + 
                     "NO STACK"); 
       // peek at hashtable 
       Hashtable params = (Hashtable)stack.peek(); 
       // hashtable should not be null 
       if(params == null) 
         throw new JspException("GetTag.doStartTag(): " + 
                     "NO HASHTABLE"); 
       // get page parameter from hashtable 
       PageParameter param = (PageParameter)params.get(name); 
       if(param != null) { 
         String content = param.getContent(); 
         if(param.isDirect()) { 
          // print content if direct attribute is true 
          try { 
           pageContext.getOut().print(content); 
          } 
          catch(java.io.IOException ex) { 
           throw new JspException(ex.getMessage()); 
          } 
         } 
         else { 
          // include content if direct attribute is false 
          try { 
           pageContext.getOut().flush(); 
           pageContext.include(content); 
          } 
          catch(Exception ex) { 
           throw new JspException(ex.getMessage()); 
          } 
         } 
       } 
       return SKIP_BODY; // not interested in tagbody, if present 
     } 
     // taghandlers should always implement release() because 
     // handlers can be reused by the JSP container 
     public void release() { 
       name = null; 
     } 
    } 
    GetTag.doStartTag从请求区域返回了页面参数bean并从bean中获得了content和direct 属性。然后,内容可以根据direct属性值选择是被包含还是显示。 
  结论    模板是一种简单而有非常有用的概念。模板的封装布局能够对布局改变的影响达到最小化。而且模板能够根据用户的不同来区分不同的内容,它还能够嵌套到其他的模板和JSP页面中。 
    <全文完> 
 
   
 |