PETSTORE原始碼追蹤記(二)- Model篇 前冒 在傳統的Java網頁應用系統( Web Application Solution),通常以JSP或 Servlet透過JDBC連結資料庫’用 JavaBean來封裝資料’最後組成HIML回應 ( response)給使用者’主要以這四種Java技術來建構動態網頁系統’這樣的方式 在JSP規格中稱爲 ModelⅠ·適用於較小型丶簡單的系統。若我們要架構大型企 業應用網頁系統’必須要能易於雜護丶容易擴充ν所以Java倡導將 Model(資料 模型)丶ⅵiew畫面展現)及 Controll!流程控制)三者獨立·即所謂的MvC模式 ( Design pattern),又稱鳥 Model2 上一期我們探討了 Petstore的 Controll(流程控制)及View畫面展現)部份 我們可以利用上一期所介貂的架構來建構流程控制與畫面展現獨立的網頁應用 系锍( Web application)’如此的架構雖然很有彈性但只能建構靜態的網頁系統 目前一般較大型的網站都是動態網頁系統’動態網頁內容通常來自資料庫·讀取 資料庫丶封裝資料’這就是 Model(資料模型)肭主要工作 寵物目錄 現在讓我們來探索 Petstore是如何處理Moel(資料模型)部份·以首頁的左 邊的寵物目錄爲例它的主要功用在於提供使用者 Petstore所販賣的寵物種類(圖 -)’若使用者點選其中一類’畫面則會切換列岀該種類之所有寵物(圖二)
PETSTORE 原始碼追蹤記(二)-Model 篇 前言 在傳統的 Java 網頁應用系統(Web Application Solution),通常以 JSP 或 Servlet 透過 JDBC 連結資料庫,用 JavaBean 來封裝資料,最後組成 HTML 回應 (response)給使用者,主要以這四種 Java 技術來建構動態網頁系統,這樣的方式 在 JSP 規格中稱為 Model 1,適用於較小型、簡單的系統。若我們要架構大型企 業應用網頁系統,必須要能易於維護、容易擴充,所以 Java 倡導將 Model(資料 模型)、View(畫面展現) 及 Controll(流程控制)三者獨立,即所謂的 MVC 模式 (Design Pattern),又稱為 Model 2。 上一期我們探討了 Petstore 的 Controll(流程控制)及 View(畫面展現)部份, 我們可以利用上一期所介紹的架構來建構流程控制與畫面展現獨立的網頁應用 系統(Web Application),如此的架構雖然很有彈性,但只能建構靜態的網頁系統, 目前一般較大型的網站都是動態網頁系統,動態網頁內容通常來自資料庫。謮取 資料庫、封裝資料,這就是 Model(資料模型)的主要工作。 寵物目錄 現在讓我們來探索 Petstore 是如何處理 Model(資料模型)部份,以首頁的左 邊的寵物目錄為例,它的主要功用在於提供使用者 Petstore 所販賣的寵物種類(圖 一),若使用者點選其中一類,畫面則會切換列出該種類之所有寵物(圖二):
W上mt日tP:M2 Intemet Explorer 榕案①编国检我的最要⑤工且①就明 中上一真·→,岱现国我的最爱守媒體3日 辆址①)t0pthr 移至連结4x JavaTM Pet Store J2EE BluePrints Sample Application Account I CartI Sign in Birds 厂圈近滿内部路 圖一 箱①际板现①我的爱(工具①D明 中上一页·→·的△按国我的船守媒替(马回日 址圈h →移至 JavaTM Pet Store J2EE BluePrints Sample Applicati Account I Cart Sonin Products for this Category mazon Parrot Great companion for up to 75 years Reptiles Great stress reliever The Java Pet Store Demo is a fictional sample application from the Java BluePrints for the Enterprise. For more information, wsn the Jaa BluePnnis for the Enterprise RePRints for the 22001 Sun Microsystems Inc. All rights nsE I aa Sofware Sun Microsystems 圖二
圖一 圖二
構成這段功能的程式碼在 Petstore homelsrclapps'petstorelsrcldocrootlsidebar jsp( Petstore home即我們安裝 Petstore之目錄) <%( page content Type="text/html; charset=UTF-8%> <9@ taglib prefix=c"uri="/WEB-INF/c tld"%> <% taglib uri="/WEB-INF/waftags tld"prefix=waf"%> <waf cache name="sidebar en US"scope="context"duration=300000> sp use bea d="catalog class="com.sun j2ee blueprints. catalog. client. Catalog Helper scope="session"> <c: set value="en US"target="s(catalog) "property="locale" <c: set value="5"target=$(catalog)"property=count"> <c set value="0"target=$(catalog)"property="start"> <table border="0"width=100% cellpadding="1"cellspacing="0"> <td bgcolor="#336666 class=petstore title "align="center> <font color="#FFFFFF">Pets</font> </td> <td bgcolor=#336666"> <table border="0"width=100%"cellpadding="5"cellspacing=1"> <td bgcolor"#FFFFFF"class="petstore> <c: for Each var="item"items="S(catalog. categories. list)"> <a href="category. screen? category id=<c out value="$ item id "/> <c out value="S item name)"A </c forEach
構成這段功能的程式碼在 Petstore_home\src\apps\petstore\src\docroot\sidebar.jsp(Petstore_home 即我們安裝 Petstore 之目錄)。 sidebar.jsp <%@ page contentType="text/html;charset=UTF-8" %> <%@ taglib prefix="c" uri="/WEB-INF/c.tld" %> <%@ taglib uri="/WEB-INF/waftags.tld" prefix="waf" %> <waf:cache name="sidebar_en_US" scope="context" duration="300000"> <jsp:useBean id="catalog" class="com.sun.j2ee.blueprints.catalog.client.CatalogHelper" scope="session"/> <c:set value="en_US" target="${catalog}" property="locale"/> <c:set value="5" target="${catalog}" property="count"/> <c:set value="0" target="${catalog}" property="start"/> <table border="0" width="100%" cellpadding="1" cellspacing="0"> <tr> <td bgcolor="#336666" class="petstore_title" align="center"> <font color="#FFFFFF">Pets</font> </td> </tr> <tr> <td bgcolor="#336666"> <table border="0" width="100%" cellpadding="5" cellspacing="1"> <tr> <td bgcolor="#FFFFFF" class="petstore"> <c:forEach var="item" items="${catalog.categories.list}" > <a href="category.screen?category_id=<c:out value="${item.id}" />"> <c:out value="${item.name}" /> </a> <br> </c:forEach> </td>
td> </tr> </table> </waf: cache> 快取自訂標籤 首先看到它使用兩組自訂標籤( Custom Tag) <% taglib prefix="c"uri="/WEB-INF/c tld"%> <%@a taglib uri="/WEB-INF/waftags tld"prefix="waf"%> 第一組是2002年6月 Release的JsTL1.0 JSP Standard Tag Library),它是 由JCP通過標凖的自訂標籤,已包含在 JWSDP1.0裡面·想要多了解它’可至 http:/iava.sun.com/products/isp/istl/ http:/jakarta.apacheorg/taglibs/index.html ctld及相關Jar檔的位置在 Petstore home\srcllibljstl 第二組是 Petstore自己定義的自訂標籤, waftage:tld的位置在 Petstore home\srclwafsrc\docrootWEB-INF 接下來我們看到 <waf cache name="sidebar en US"scope="context" duration=300000"> 它的功用是做網頁快取用,屬性name指定名稱; Scope指定範圍," contextˆ爲整 個 web server丶其他值尙有 session"' request'"page"; duration是指定保留時 間·單位駑毫秒( millisecond)使用時它會先比對當初網頁存λ時間與系統時間 若未超過則直接從指定範圍中取岀網頁內容回應給使用者否則繼續執行標籤裡 面內容’最後再將新內容存入指定範圍’程式碼在 Petstore homelsrclwaftsrclviewltaglibslcom\sunj2eelblueprintstaglibssmartl CacheT ag java 程式碼節錄如下 public int doStartTag( throws Jsp Tag Exception HttpservletrEquest req ((httP servletreqUest)page Context getrequesTo); key =req getRequestURLO toString +'#'+name ? req. getQueryStringO
</tr> </table> </td> </tr> </table> </waf:cache> 快取自訂標籤 首先看到它使用兩組自訂標籤(Custom Tag): <%@ taglib prefix="c" uri="/WEB-INF/c.tld" %> <%@ taglib uri="/WEB-INF/waftags.tld" prefix="waf" %> 第一組是 2002 年 6 月 Release 的 JSTL 1.0(JSP Standard Tag Library),它是 由 JCP 通過標準的自訂標籤,已包含在 JWSDP1.0 裡面,想要多了解它,可至 http://java.sun.com/products/jsp/jstl/ http://jakarta.apache.org/taglibs/index.html c.tld 及相關 Jar 檔的位置在 Petstore_home\src\lib\jstl。 第二組是 Petstore 自己定義的自訂標籤,waftags.tld 的位置在 Petstore_home\src\waf\src\docroot\WEB-INF。 接下來我們看到: <waf:cache name="sidebar_en_US" scope="context" duration="300000"> 它的功用是做網頁快取用,屬性 name 指定名稱;scope 指定範圍,”context”為整 個 web server、其他值尚有”session”、”request”、”page”;duration 是指定保留時 間,單位為毫秒(millisecond),使用時它會先比對當初網頁存入時間與系統時間, 若未超過則直接從指定範圍中取出網頁內容回應給使用者,否則繼續執行標籤裡 面內容,最後再將新內容存入指定範圍,程式碼在: Petstore_home\src\waf\src\view\taglibs\com\sun\j2ee\blueprints\taglibs\smart\CacheT ag.java 程式碼節錄如下: public int doStartTag() throws JspTagException { HttpServletRequest req = ((HttpServletRequest) pageContext.getRequest()); key = req.getRequestURL().toString() + '#' + name + '?' + req.getQueryString();
∥從指定範圍取出網頁內容·本例範圍是 context if ( "context".equals(scope))i entry=(Entry) page Context. getServletContext( getAttribute(key) else if ("session.equals(scope))i entry =(Entry) page Context getSession().getAttribute(key) else if("request"equals(scope))( entry =(Entry) page Context. getRequesto) getAttribute(key); else if("page".equals(scope))( entry =(Entry) page Context. getAttribute(key) ∥判斷網頁內容是否過期 if(entry != null & entry is Expired)( entry= null 若過期則續執行標籤裡面內容·否則接略過 return(entry ==null)? EVAL BODY BUFFERED: SKIP BODY public int doEndTago throws Jsp Tag Exception ∥若過期則將網頁內容存入指定範圍 if(entry ==null)( Body Content bc- get Body Contento if (bc I= null)i String content=bc. getStringO entry =new Entry(content, duration); ∥本例範圍是? context if ("context".equals(scope))( page Context. getServletContexto setAttribute(key, entry ) else if ("session".equals(scope))( page Context. getSession(). setAttribute(key, entry) else if("request"equals(scope))( page Context. getRequesto) setAttribute(key, entry)
//從指定範圍取出網頁內容,本例範圍是”context” if ("context".equals(scope)) { entry = (Entry) pageContext.getServletContext().getAttribute(key); } else if ("session".equals(scope)) { entry = (Entry) pageContext.getSession().getAttribute(key); } else if ("request".equals(scope)) { entry = (Entry) pageContext.getRequest().getAttribute(key); } else if ("page".equals(scope)) { entry = (Entry) pageContext.getAttribute(key); } //判斷網頁內容是否過期 if (entry != null && entry.isExpired()) { entry = null; } //若過期則繼續執行標籤裡面內容,否則直接略過 return (entry == null) ? EVAL_BODY_BUFFERED : SKIP_BODY; } public int doEndTag() throws JspTagException { //若過期則將網頁內容存入指定範圍 if (entry == null) { BodyContent bc = getBodyContent(); if (bc != null) { String content = bc.getString(); entry = new Entry(content, duration); //本例範圍是”context” if ("context".equals(scope)) { pageContext.getServletContext().setAttribute(key, entry); } else if ("session".equals(scope)) { pageContext.getSession().setAttribute(key, entry); } else if ("request".equals(scope)) { pageContext.getRequest().setAttribute(key, entry);