[中文版]執行個體講解JSP Model 2體繫結構(探索MVC設計模式)–2

來源:互聯網
上載者:User

理解“音樂無國界”

  “音樂無國界”的主介面是JSP頁 Eshop.jsp(見代碼清單1)。你會注意到,這個頁面幾乎只作為專門的使用者介面,不承擔任何處理任務――是一個最理想的JSP方案。另外,請注意另一個JSP頁Cart.jsp(見代碼清單2)被Eshop.jsp通過指令<jsp:include page="Cart.jsp" flush="true" />包含於其中。

  代碼清單1:EShop.jsp

<%@ page session="true" %><html><head><title>Music Without Borders</title></head><body bgcolor="#33CCFF"><font face="Times New Roman,Times" size="+3">Music Without Borders</font><hr><center><form name="shoppingForm" action="/examples/servlet/ShoppingServlet" method="POST"><b>CD:</b><select name="CD"><option>Yuan | The Guo Brothers | China | $14.95</option><option>Drums of Passion | Babatunde Olatunji | Nigeria | $16.95</option><option>Kaira | Tounami Diabate| Mali | $16.95</option><option>The Lion is Loose | Eliades Ochoa | Cuba | $13.95</option><option>Dance the Devil Away | Outback | Australia | $14.95</option><option>Record of Changes | Samulnori | Korea | $12.95</option><option>Djelika | Tounami Diabate | Mali | $14.95</option><option>Rapture | Nusrat Fateh Ali Khan | Pakistan | $12.95</option><option>Cesaria Evora | Cesaria Evora | Cape Verde | $16.95</option><option>Ibuki | Kodo | Japan | $13.95</option></select><b>Quantity:</b><input type="text" name="qty" SIZE="3" value="1"><input type="hidden" name="action" value="ADD"><input type="submit" name="Submit" value="Add to Cart"></form></center><jsp:include page="Cart.jsp" flush="true" /></body></html>

  代碼清單2:Cart.jsp

<%@ page session="true" import="java.util.*, shopping.CD" %><%Vector buylist = (Vector)session.getValue("shopping.shoppingcart");if (buylist != null && (buylist.size() > 0)) {%><center><table border="0" cellpadding="0" width="100%" bgcolor="#FFFFFF"><tr><td><b>ALBUM</b></td><td><b>ARTIST</b></td><td><b>COUNTRY</b></td><td><b>PRICE</b></td><td><b>QUANTITY</b></td><td></td></tr><%for (int index = 0; index< buylist.size(); index++) {CD anOrder = (CD)buylist.elementAt(index);%><tr><td><b><%= anOrder.getAlbum() %></b></td><td><b><%= anOrder.getArtist() %></b></td><td><b><%= anOrder.getCountry() %></b></td><td><b><%= anOrder.getPrice() %></b></td><td><b><%= anOrder.getQuantity() %></b></td><td><form name="deleteForm" action="/examples/servlet/ShoppingServlet" method="POST"><input type="submit" value="Delete"><input type="hidden" name= "delindex" value='<%= index %>'><input type="hidden" name="action" value="DELETE"></form></td></tr><% } %></table><form name="checkoutForm" action="/examples/servlet/ShoppingServlet" method="POST"><input type="hidden" name="action" value="CHECKOUT"><input type="submit" name="Checkout" value="Checkout"></form></center><% } %>

  這裡,Cart.jsp操縱著基於會話的購物車的表達,在MVC體系中,購物車就充當Model的角色。

  觀察Cart.jsp開頭處的指令碼片段:

<%Vector buylist = (Vector)session.getValue("shopping.shoppingcart");if (buylist != null && (buylist.size() > 0)) {%>

  這段指令碼主要是從會話中取出購物車。如果購物車是空的或尚未建立,則它什麼都不顯示;因此,當使用者第一次訪問這個應用程式時,呈現給他的視圖3所示:

  圖3:音樂無國界,主視圖

  圖中按鈕文字:放入購物車

  如果購物車不為空白,則選中的物品被依次從購物車中取出,如下面的指令碼片段所示:

<%for (int index = 0; index< buylist.size(); index++) {CD anOrder = (CD)buylist.elementAt(index);%>

  描述物品的變數一旦被建立,就會被用JSP運算式直接嵌入靜態HTML模板中去。圖4顯示了當使用者向購物車中放入一些物品後的視圖。

  圖4:音樂無國界,購物車視圖

  圖中文字:Music Without Borders:音樂無國界;Quantity:數量;ALBUM:唱片;ARTIST:演唱者;COUNTRY:國家;PRICE:價格;Delete:刪除;Checkout:結帳。

  這裡需要注意的重要一點是,在Eshop.jsp和Cart.jsp中實現的對所有動作的處理都由一個Servlet——ShoppingServlet.java控制,如代碼清單3所示:

  代碼清單3:ShoppingServlet.java

import java.util.*;import java.io.*;import javax.servlet.*;import javax.servlet.http.*;import shopping.CD;public class ShoppingServlet extends HttpServlet {public void init(ServletConfig conf) throws ServletException {super.init(conf);}public void doPost (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {HttpSession session = req.getSession(false);if (session == null) {res.sendRedirect("error.html");}Vector buylist = (Vector)session.getValue("shopping.shoppingcart");String action = req.getParameter("action");if (!action.equals("CHECKOUT")) {if (action.equals("DELETE")) {String del = req.getParameter("delindex");int d = (new Integer(del)).intValue();buylist.removeElementAt(d);} else if (action.equals("ADD")) {//以前是否購買了同樣的CD?boolean match = false;CD aCD = getCD(req);if (buylist == null) {//將第一張CD放入購物車buylist = new Vector(); //第一份定單buylist.addElement(aCD);} else {// 不是第一次購買for (int i = 0; i < buylist.size(); i++) {CD cd = (CD)buylist.elementAt(i);if (cd.getAlbum().equals(aCD.getAlbum())) {cd.setQuantity(cd.getQuantity() + aCD.getQuantity());buylist.setElementAt(cd, i);match = true;} //if name matches結束} // for迴圈結束if (!match)buylist.addElement(aCD);}}session.putValue("shopping.shoppingcart", buylist);String url = "/jsp/shopping/EShop.jsp";ServletContext sc = getServletContext();RequestDispatcher rd = sc.getRequestDispatcher(url);rd.forward(req, res);} else if (action.equals("CHECKOUT")) {float total = 0;for (int i = 0; i < buylist.size(); i++) {CD anOrder = (CD)buylist.elementAt(i);float price = anOrder.getPrice();int qty = anOrder.getQuantity();total += (price * qty);}total += 0.005;String amount = new Float(total).toString();int n = amount.indexOf('.');amount = amount.substring(0, n + 3);req.setAttribute("amount", amount);String url = "/jsp/shopping/Checkout.jsp";ServletContext sc = getServletContext();RequestDispatcher rd = sc.getRequestDispatcher(url);rd.forward(req, res);}}private CD getCD(HttpServletRequest req) {//想象一下如果這些都在一個指令碼片段中會有多麼難看String myCd = req.getParameter("CD");String qty = req.getParameter("qty");StringTokenizer t = new StringTokenizer(myCd, "|");String album = t.nextToken();String artist = t.nextToken();String country = t.nextToken();String price = t.nextToken();price = price.replace('$', ' ').trim();CD cd = new CD();cd.setAlbum(album);cd.setArtist(artist);cd.setCountry(country);cd.setPrice((new Float(price)).floatValue());cd.setQuantity((new Integer(qty)).intValue());return cd;}}

  每次使用者在Eshop.jsp頁內加入一件物品,頁面就向控制Servlet發送一個請求。由Servlet依次決定適當的動作,然後處理要加入的物品的請求參數。然後它例示一個新的CD Bean(見代碼清單4)表示所選物品,並在會話內更新購物車對象。

  代碼清單4:CD.java

package shopping;public class CD {String album;String artist;String country;float price;int quantity;public CD() {album = "";artist = "";country = "";price = 0;quantity = 0;}public void setAlbum(String title) {album = title;}public String getAlbum() {return album;}public void setArtist(String group) {artist = group;}public String getArtist() {return artist;}public void setCountry(String cty) {country = cty;}public String getCountry() {return country;}public void setPrice(float p) {price = p;}public float getPrice() {return price;}public void setQuantity(int q) {quantity = q;}public int getQuantity() {return quantity;}}

  注意:我們在Servlet中包括了附加的智能,這樣一來它就能明白,如果一個原先加入過的CD被再次選中,它只需在購物車中為這個CD Bean增加計數就可以了。這個控制Servlet也能處理在Cart.jsp中被觸發的動作,比如使用者從購物車中刪除物品或結帳。注意觀察,控制Servlet一直在完全掌握著對資源的支配權,它決定在對特定動作的響應中調用哪些資源。例如,購物車狀態的改動,如添加或刪除,會使控制Servlet把處理過的請求送至Eshop.jsp頁。這促使該頁重新顯示主視圖,這時購物車中顯示的資料已被更新。如果使用者決定結帳,這個請求在處理後被送至Checkout.jsp頁(見代碼清單5),通過如下所示的發送器實現:

String url = "/jsp/shopping/Checkout.jsp";ServletContext sc = getServletContext();RequestDispatcher rd = sc.getRequestDispatcher(url);rd.forward(req, res);

  代碼清單5:Checkout.jsp

<%@ page session="true" import="java.util.*, shopping.CD" %><html><head><title>Music Without Borders Checkout</title></head><body bgcolor="#33CCFF"><font face="Times New Roman,Times" size="+3">Music Without Borders Checkout</font><hr><center><table border="0" cellpadding="0" width="100%" bgcolor="#FFFFFF"><tr><td><b>ALBUM</b></td><td><b>ARTIST</b></td><td><b>COUNTRY</b></td><td><b>PRICE</b></td><td><b>QUANTITY</b></td><td></td></tr><%Vector buylist = (Vector)session.getValue("shopping.shoppingcart");String amount = (String)request.getAttribute("amount");for (int i = 0; i < buylist.size(); i++) {CD anOrder = (CD)buylist.elementAt(i);%><tr><td><b><%= anOrder.getAlbum() %></b></td><td><b><%= anOrder.getArtist() %></b></td><td><b><%= anOrder.getCountry() %></b></td><td><b><%= anOrder.getPrice() %></b></td><td><b><%= anOrder.getQuantity() %></b></td></tr><%}session.invalidate();%><tr><td></td><td></td><td><b>TOTAL</b></td><td><b>$<%= amount %></b></td><td></td></tr></table><a href="/examples/jsp/shopping/EShop.jsp">Shop some more!</a></center></body></html>

  Checkout.jsp僅從會話中取出購物車和所有請求的總數,然後顯示所選的物品及總價格。圖5顯示了結帳時用戶端的視圖。一旦使用者結帳,那麼及時去除會話對象很重要。照顧到這一點,在頁面最後需要有一個session.invalidate()調用。這一處理是必要的,原有有兩個:第一,如果會話不被終止,使用者的購物車就不會重新初始化,當他沒有結帳而試圖開始新一輪購物的時候,他的購物車中仍將保留著他已購買的那些物品。第二,如果使用者未結帳就離開了,那麼這個會話對象不會作廢,仍將佔用寶貴的系統資源直到它到期。由於預設的會話有效期間是30分鐘,所以在高負荷的系統上,這種情況會使系統資源迅速耗盡。我們當然知道一個應用程式將系統資源耗盡意味著什麼!

  圖5:音樂無國界,結帳視圖

  圖中文字同圖4。

  注意,在這個例子中所有的資源分派都是基於會話的,因為這個模型就是存於會話內的。所以,你必須確保控制Servlet不被使用者訪問,即使是意外的訪問也不允許。要解決這一問題,可以在控制Servlet檢查到一個非法訪問時自動轉向重新導向錯誤頁面。(見代碼清單6)

  代碼清單6:error.html

<html><body><h1>Sorry, there was an unrecoverable error!<br>Please try<a href="/examples/jsp/shopping/EShop.jsp">again</a>.</h1></body></html>

配置“音樂無國界”

  我假定你使用的是Sun公司最新版本的JavaServer Web Development Kit(Java伺服器網頁開發套件-JSWDK)來舉例說明。假設此伺服器安裝在\jswdk-1.0.1目錄下——這是在Windows中它的預設安裝路徑,“音樂無國界”應用程式的檔案應如下配置:

  • 在 \jswdk-1.0.1\examples\jsp目錄下建立shopping目錄
  • 複製Eshop.jsp到\jswdk-1.0.1\examples\jsp\shopping
  • 複製Cart.jsp到\jswdk-1.0.1\examples\jsp\shopping
  • 複製Check.jsp到\jswdk-1.0.1\examples\jsp\shopping
  • 鍵入javac *.java編譯.java檔案
  • 複製 ShoppingServlet.class到 \jswdk-1.0.1\webpages\Web-Inf\servlets
  • 在\jswdk-1.0.1\examples\Web-Inf\jsp\beans目錄下建立shopping目錄
  • 複製CD.class到\jswdk-1.0.1\examples\Web-Inf\jsp\beans\shopping
  • 複製error.html到\jswdk-1.0.1\webpages
  • 伺服器一旦啟動,你就可以使用http://localhost:8080/examples/jsp/shopping/EShop.jsp訪問這個應用程式

權衡JSP與Servlets

  在這個例子中,我們仔細考察了JSP Model 2提供的控制水準和靈活性。特別地,我們看到了如何挖掘Servlets和JSP的最佳特性,在最大程度上分離內容和表達。正確運用Model 2體繫結構,可以把所有處理邏輯集中於控制Servlet中,讓JSP頁只負責表達或視圖。然而,使用Model 2的弊端是它很複雜。因此,在簡單的應用中Model 1或許更合適。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.