现在的位置: 首页 > 综合 > 正文

JSP设计模式基础:View Helper模式——学习如何使用View Helper模式使得Model数据适应表现层的需要(3)

2013年06月07日 ⁄ 综合 ⁄ 共 9332字 ⁄ 字号 评论关闭
 
创建菜单
在某些情况下,动态的产生菜单或集合链接是很有用的。控制器执行相应的动作,这些动作轮流产生一系列的链接项。使用Helper的View产生格式化的链接来存储在Model里。
例如,View可能是一个JSP页面,这个页面需要显示为一个给定的产品显示附加项的菜单。这是一个解释你为什么需要动态显示菜单的一个例子。用户可能会点击公司目录的某一个产品,希望能看到他们所选择的产品的附加项的列表。在View里,应用从数据库里取出来产品的必要信息,并且把产品的附加项作为一些链接来显示。
在这个例子里,你可以跳过链接产生环节,而仅仅提供一个静态的Model以供页面有显示。Model是一个包含有超链接的Hashtable的JavaBean。这个Hashtable的key为要显示的超链接名称,value为超链接。你将取得超链接通过用逗号隔开的list,并且把它插入到标签内部。如下所示,显示了一个静态Model的样子:
Listing 6. MenuModel.java
 
 
package jspbook.ch08.beans;
 
import java.io.Serializable;
 
import java.util.Hashtable;
import java.util.Enumeration;
 
public class MenuModel implements Serializable {
 
 
   Hashtable links = new Hashtable();
 
   String list = "";
 
   public MenuModel()
   {
      /* Initialize model with sample values */
      links.put("Fold-away Keyboard", "/Controller?action=display&item=101");
      links.put("Standard Leather Case", "/Controller?action=display&item=102");
      links.put("Deluxe 3-Pocket Case", "/Controller?action=display&item=103");
      links.put("Travel Cable", "/Controller?action=display&item=104");
      links.put("Stylus Pack", "/Controller?action=display&item=105");
      links.put("8MB Backup Module", "/Controller?action=display&item=106");
   }
 
   /* Accessor Methods */
   public void setList (String _list)
   {
      this.list = _list;
  }
   public String getList ()
   {
      StringBuffer csvList = new StringBuffer();
 
      /* Transform hashtable into comma-separated list */
      Enumeration enum = links.keys();
      while (enum.hasMoreElements()) {
         String linkName = (String) enum.nextElement();
         String linkURL = (String) links.get(linkName);
         csvList.append(linkName).append(",").append(linkURL).append("/n");
      }
 
      return csvList.toString();
   }
}
 
 
你将使用到的Helper是一个继承了BodyTagSupport 的定制标签,这样的话,它能够执行存储在标签的start和end方法之间的body内容。标签需要读取链接项目列表,输出一个超链接的列表。它做这些工作是在doAfterBody()里面,循环读取body内容的每一行,解析出链接名和链接URL。注意到,如果从Model里取得的值在body内容之后有空白的话,一般这样是为了保证页面的格式统一,使得一个额外的空白行会被读入。你必须检测它们。如下所示,是你的Helper的代码的大致样子:
Listing 7. MenuTag.java
 
 
package jspbook.ch08;
 
 
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.JspTagException;
 
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.BodyContent;
 
import java.io.BufferedReader;
import java.io.IOException;
 
import java.util.StringTokenizer;
 
public class MenuTag extends BodyTagSupport {
 
   /* Tag Attributes */
   protected String links;
 
   /* Process Tag Body */
   public int doAfterBody() throws JspTagException {
      try {
         BodyContent body = getBodyContent();
         JspWriter out = body.getEnclosingWriter();
         /* Parse records and output as list of hyperlinks */
         BufferedReader contentReader = new BufferedReader(body.getReader());
         String record = "";
         while ((record = contentReader.readLine()) != null) {
            StringTokenizer st = new StringTokenizer(record, ",");
 
            while (st.hasMoreTokens()) {
               String linkName = st.nextToken();
 
               if(!linkName.trim().equals("")){
                  String linkURL = st.nextToken();
 
                  out.println("<a href='" + linkURL + "'>");
                  out.println(linkName + "</a>");
                  out.println("<br/><br/>");
               }
            }
         }
      }
      catch (IOException e) {
         throw new JspTagException(e.toString());
 
      }
      return SKIP_BODY;
   }
 
   /* Process End Tag */
   public int doEndTag() throws JspTagException {
      return EVAL_PAGE;
   }
 
   /* Attribute Accessor Methods */
   public String getLinks ()
  {
      return this.links;
   }
 
   public void setLinks (String _links)
   {
      this.links = _links;
   }
}
在JSP页面里使用这个标签相当简单,就像预想的一样。一旦你想显示超链接列表,你就可以插入一个定制标签来为你做这件事。在标签体内部,你放置了一个小的EL代码片断来链接项列表的分割符。因为你要在标签体内部执行你的代码,你必须使用一个包含jsp名称的值的<bodycontent>标签在标签库描述符文件里声明该标签。如下所示,是在helpers.tld 文件的一个完整的标签库描述符和为JSP页面而使用的代码:
<tag>
   <name>MenuTag</name>
   <tag-class>jspbook.ch08.MenuTag</tag-class>
   <body-content>jsp</body-content>
</tag>
如下所示,是menuHelper.jsp文件。通过使用MenuModel JavaBean的getList()方法,我们取得了MenuTag 的菜单项。标签处理器解析这些菜单项并且输出一个超链接的列表(结果看文件下面的图)。
Listing 8. menuHelper.jsp
 
 
<%-- Declare tag that we'll use as our helper --%>
<%@ taglib uri="/helpers" prefix="helpers" %>
 
<html>
   <head>
      <title>Product Accessories</title>
   </head>
 
   <body>
 
      <font/>
 
      <%-- Declare bean that will act as our model --%>
      <jsp:useBean id="myBean" class="jspbook.ch08.beans.MenuModel"/>
 
      <%-- Display Product Accessory Links (using helper) --%>
      <center>
 
         <b>Product Accessories for: Deluxe PDA</b>
 
         <br/><br/>
 
         <helpers:MenuTag>
            ${myBean.list}
         </helpers:MenuTag>
 
      </center>
   </body>
</html>
 
 
 
 
 
创建习惯列表格式
大多数WEB应用的一个公共元素是经常分组一些相关项并把它们做成一个列表。标准的HTML列表元素,使用 <ul>标签,通过一个标准的列表来显示数据列。使用一个适当的Helper能够使你定制列表显示的方式。在这个例子中,你将创建一个Helper,通过三种不同的列表类型的选择来将列表项转化成所需要的格式。如下是标签的描述符:
<tag>
   <name>ListTag</name>
   <tag-class>jspbook.ch08.ListTag</tag-class>
   <body-content>jsp</body-content>
   <attribute>
      <name>format</name>
      <required>yes</required>
      <rtexprvalue>true</rtexprvalue>
   </attribute>
</tag>
和FormatTag 一样,标签的代码定义了一个format 属性;运行body内容和MenuTag 的body所做的事情大同小异。需要着重指出的是,有很多方法来格式化一个列表。在这个例子中,你仅仅将列表项的距离加倍,并且提供了一个buttets选择。如下所示,是标签的代码:
Listing 9. ListTag.java
 
 
package jspbook.ch08;
 
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.JspTagException;
 
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.BodyContent;
 
import java.io.BufferedReader;
import java.io.IOException;
 
public class ListTag extends BodyTagSupport {
 
   /* Tag Attributes */
   protected String format;
 
   /* Static Constants */
   private final static String BULLET_ORB = "orb";
   private final static String BULLET_PLUS = "plus";
   private final static String BULLET_ARROW = "arrow";
 
   /* Process Tag Body */
   public int doAfterBody() throws JspTagException {
      try {
         BodyContent body = getBodyContent();
         JspWriter out = body.getEnclosingWriter();
 
         /* Parse records and output as formatted list */
         BufferedReader contentReader = new BufferedReader(body.getReader());
         String record = "";
         while ((record = contentReader.readLine()) != null) {
            if (record.trim().length() > 0) {
               out.println(formatListItem(record.trim()));
            }
         }
 
      }
      catch (IOException e) {
         throw new JspTagException(e.toString());
      }
      return SKIP_BODY;
    }
 
   /* Process End Tag */
   public int doEndTag() throws JspTagException {
      return EVAL_PAGE;
   }
   private String formatListItem (String _input)
   {
      StringBuffer listItem = new StringBuffer();
 
      /* Double-space the list */
      listItem.append("<br/><br/>");
 
      if(format.equals(BULLET_ORB)) {
         listItem.append("<img src='/jspBook/images/orb.gif'/>");
      } else if (format.equals(BULLET_PLUS)) {
         listItem.append("<img src='/jspBook/images/plus.gif'/>");
      } else if (format.equals(BULLET_ARROW)) {
         listItem.append("<img src='/jspBook/images/arrow.gif'/>");
      }
 
      listItem.append(" ").append(_input);
 
 
      return listItem.toString();
   }
 
   /* Attribute Accessor Methods */
   public String getFormat ()
   {
      return this.format;
   }
 
   public void setFormat (String _format)
   {
      this.format = _format;
   }
}
在这例子中,和你在前面例子中所做的一样,你可以使用一个JavaBean来传递Model。你可能已经学会了如何使用Helper将Model的数据处理后传送给表现层。所以,在这个例子里,你只需要在JSP页面使用硬编码那些列表数据,并且把它们放在标签体内,而不是使用真实的Model数据。
如下是JSP代码,它的后面是运行结果:
Listing 10. listHelper.jsp
 
 
<%-- Declare tag that we'll use as our helper --%>
<%@ taglib uri="/helpers" prefix="helpers" %>
 
<html>
   <head>
      <title>List Examples</title>
   </head>
   <body>
 
      <font/>
 
      <center>
 
         <h1>List Examples</h1>
 
         <table width="650">
            <tr>
               <td valign="top" width="150">
                  <helpers:ListTag format="orb">
                     High Card
                     Pair
                     Two Pair
                     Three of a Kind
                     Straight
                     Flush
                     Full House
                     Four of a Kind
                     Straight Flush
                     Royal Flush
                  </helpers:ListTag>
               </td>
               <td valign="top" width="150">
                  <helpers:ListTag format="plus">
                     Milwaukee Bucks
                     Detroit Pistons
                     Toronto Raptors
                     Indiana Pacers
                     Charlotte Hornets
                     Cleveland Cavaliers
                     Atlanta Hawks
                     Chicago Bulls
                  </helpers:ListTag>
               </td>
               <td valign="top" width="300">
                  <helpers:ListTag format="arrow">
                     Chapter 1 - The History of Cheese
                     Chapter 2 - The Many Faces of Cheese
                     Chapter 3 - Love and Cheese
                     Chapter 4 - Not Just for Mice
                     Chapter 5 - So You're a Cheesehead...
                     Chapter 6 - The Perfect Cheese
                     Chapter 7 - Cheddar Is Better
                     Chapter 8 - The Big Cheese
                  </helpers:ListTag>
               </td>
            </tr>
         </table>
      </center>
   </body>
</html>
 
 
小结
这个模式用来作为应用在JSP和Servlet的J2EE的表现层模式的结束。当这些模式结合起来使用的时候,它们会为企业级的WEB应用提供一个非常强大的请求处理开发框架。
 
关于作者
Andrew Patzer是一个位于Midwest的一家咨询公司的WEB架构师。他的第一本书,《专业Java服务器编程》,是第一本关于J2EE技术方面的畅销书。Patzer现在是一个领先的保险业的应用服务提供商的一个关键的系统架构师。他直接参与设计和构建了作为公司主要产品的J2EE开发框架的工作。在最近几年里,Patzer为本地用户和国家级会议提交了好几种关于J2EE的方案。
 
索引
本文是Andrew Patze和别人的合著:《JSP设计模式基础》的第二章的节选。该书由Matthew Moodie编辑(Apress, 2004; ISBN: 1590594118)。
http://www.apress.com/book/bookDisplay.html?bID=348
想学习更多的有关模式的知识,请浏览JavaWorld的设计模式专题。
http://www.javaworld.com/channel_content/jw-patterns-index.shtml
想学习更多的有关JSP的知识,请浏览JavaWorld的JavaServer Pages (JSP)专题。
http://www.javaworld.com/channel_content/jw-jsp-index.shtml?
您也可以在JavaWorld的相关专题搜索有关JavaBean的知识。
http://www.javaworld.com/channel_content/jw-javabeans-index.shtml
 

抱歉!评论已关闭.