Ajax实例-购物车
一、概述
1.当添加或删除商品时,购物车会立即更新数据
2.思路:
(1)建立商品类Item.java,存有商品属性name,prince,code(商品编码)等
(2)建立商品目录类Catalog.java,便于CRUD操作时,判断是否存在该品种商品
(3)建立购物车类Cart.java,保存用户已选购的商品各类及其数量,HashMap<Item,Integer>存储,提供toXml()把存储的内容拼接成xml格式。把cart对象放在session中,以保存用户在会话期间的购物数据,且方便servlet的CRUD操作,及调用toXml()返回给request
(4)建立CartServlet.java处理请求
3.类图
4.序列图
二、代码
1.Item.java
1 package developerworks.ajax.store; 2 3 import java.math.BigDecimal; 4 5 //商品 6 public class Item { 7 private String code; 8 private String name; 9 private String description; 10 private int price; 11 12 public Item(String code,String name,String description,int price) { 13 this.code=code; 14 this.name=name; 15 this.description=description; 16 this.price=price; 17 } 18 19 public String getCode() { 20 return code; 21 } 22 23 public String getName() { 24 return name; 25 } 26 27 public String getDescription() { 28 return description; 29 } 30 31 public int getPrice() { 32 return price; 33 } 34 35 public String getFormattedPrice() { 36 return "$"+new BigDecimal(price).movePointLeft(2); 37 } 38 39 public boolean equals(Object o) { 40 if (this == o) return true; 41 if (this == null) return false; 42 if (!(o instanceof Item)) return false; 43 return ((Item)o).getCode().equals(this.code); 44 } 45 }
2.Catalog.java
1 package developerworks.ajax.store; 2 3 import java.util.*; 4 5 //商品目录 6 public class Catalog { 7 8 private static Map<String,Item> items; 9 10 static { 11 items = new HashMap<String,Item>(); 12 items.put("hat001",new Item("hat001","Hat","Stylish bowler hat (SALE!)",1999)); 13 items.put("dog001",new Item("dog001","Dog","Chocolate labrador puppy",7999)); 14 items.put("sou001",new Item("sou001","Soup","Can of tasty tomato soup",199)); 15 items.put("cha001",new Item("cha001","Chair","Swivelling office chair", 4999)); 16 items.put("str001",new Item("str001","String","Metric tonne of bailing twine", 1999)); 17 items.put("qua001",new Item("qua001","Quark","Everyone's favorite sub-atomic particle", 49)); 18 } 19 20 public Collection<Item> getAllItems() { 21 return items.values(); 22 } 23 24 public boolean containsItem(String itemCode) { 25 return items.containsKey(itemCode); 26 } 27 28 public Item getItem(String itemCode) { 29 return items.get(itemCode); 30 } 31 32 }
3.Cart.java
1 package developerworks.ajax.store; 2 3 import java.math.BigDecimal; 4 import java.util.*; 5 6 /** 7 * A very simple shopping Cart 8 */ 9 public class Cart { 10 11 //HashMap<Item,Integer>中,Item用来表示购物车的哪种物品,Integer表示该物品的数量 12 private HashMap<Item,Integer> contents; 13 14 /** 15 * Creates a new Cart instance 16 */ 17 public Cart() { 18 contents = new HashMap<Item,Integer>(); 19 } 20 21 /** 22 * Adds a named item to the cart 23 * @param itemName The name of the item to add to the cart 24 */ 25 public void addItem(String itemCode) { 26 27 Catalog catalog = new Catalog(); 28 29 if (catalog.containsItem(itemCode)) { 30 Item item = catalog.getItem(itemCode); 31 32 int newQuantity = 1; 33 34 //查看要添加的item在现在的购物车中是否已经存在 35 if (contents.containsKey(item)) { 36 Integer currentQuantity = contents.get(item); 37 38 //若存在则数量加1就行 39 newQuantity += currentQuantity.intValue(); 40 } 41 //更新物品数量 42 contents.put(item, new Integer(newQuantity)); 43 } 44 } 45 46 /** 47 * Removes the named item from the cart 48 * @param itemName Name of item to remove 49 */ 50 public void removeItems(String itemCode) { 51 52 contents.remove(new Catalog().getItem(itemCode)); 53 } 54 55 /** 56 * @return XML representation of cart contents 57 */ 58 public String toXml() { 59 StringBuffer xml = new StringBuffer(); 60 xml.append("<?xml version=\"1.0\"?>\n"); 61 xml.append("<cart generated=\""+System.currentTimeMillis()+"\" total=\""+getCartTotal()+"\">\n"); 62 63 /*遍历购物车中的每种物品,取出各种物品的名称、数量,拼接xml 64 <item code="xx"> 65 <name>xx</name> 66 <quantity>xx</quantity> 67 </item> 68 */ 69 for (Iterator<Item> I = contents.keySet().iterator() ; I.hasNext() ; ) { 70 Item item = I.next(); 71 int itemQuantity = contents.get(item).intValue(); 72 73 xml.append("<item code=\""+item.getCode()+"\">\n"); 74 xml.append("<name>"); 75 xml.append(item.getName()); 76 xml.append("</name>\n"); 77 xml.append("<quantity>"); 78 xml.append(itemQuantity); 79 xml.append("</quantity>\n"); 80 xml.append("</item>\n"); 81 } 82 83 xml.append("</cart>\n"); 84 System.out.println(xml); 85 return xml.toString(); 86 } 87 88 //算总价 89 private String getCartTotal() { 90 int total = 0; 91 92 //取出购物车的每种物品 93 for (Iterator<Item> I = contents.keySet().iterator() ; I.hasNext() ; ) { 94 Item item = I.next(); 95 //取出购物车中每种物品的数量 96 int itemQuantity = contents.get(item).intValue(); 97 98 //每种物品的总价=单价*数量 99 total += (item.getPrice() * itemQuantity); 100 } 101 102 return "$"+new BigDecimal(total).movePointLeft(2); 103 } 104 }
4.CartServlet.java
1 package developerworks.ajax.servlet; 2 3 import developerworks.ajax.store.Cart; 4 import javax.servlet.http.*; 5 6 import java.util.Enumeration; 7 8 public class CartServlet extends HttpServlet { 9 10 /** 11 * Updates Cart, and outputs XML representation of contents 12 */ 13 public void doPost(HttpServletRequest req, HttpServletResponse res) throws java.io.IOException { 14 15 Enumeration headers = req.getHeaderNames(); 16 while (headers.hasMoreElements()) { 17 String header =(String) headers.nextElement(); 18 System.out.println(header+": "+req.getHeader(header)); 19 } 20 21 Cart cart = getCartFromSession(req); 22 23 //接收在req.send("action=add&item="+itemCode)指定的参数 24 String action = req.getParameter("action"); 25 String item = req.getParameter("item"); 26 27 if ((action != null)&&(item != null)) { 28 29 if ("add".equals(action)) { 30 cart.addItem(item); 31 32 } else if ("remove".equals(action)) { 33 cart.removeItems(item); 34 35 } 36 } 37 38 String cartXml = cart.toXml(); 39 res.setContentType("text/xml"); 40 //cartXml的值会赋给responseXML属性返回给request 41 res.getWriter().write(cartXml); 42 } 43 44 public void doGet(HttpServletRequest req, HttpServletResponse res) throws java.io.IOException { 45 // Bounce to post, for debugging use 46 // Hit this servlet directly from the browser to see XML 47 doPost(req,res); 48 } 49 50 private Cart getCartFromSession(HttpServletRequest req) { 51 52 //把购物车保存在session中 53 HttpSession session = req.getSession(true); 54 Cart cart = (Cart)session.getAttribute("cart"); 55 56 if (cart == null) { 57 cart = new Cart(); 58 session.setAttribute("cart", cart); 59 } 60 61 return cart; 62 } 63 }
5.cart.js
1 // Timestamp of cart that page was last updated with 2 var lastCartUpdate = 0; 3 4 /* 5 * Adds the specified item to the shopping cart, via Ajax call 6 * itemCode - product code of the item to add 7 */ 8 function addToCart(itemCode) { 9 10 var req = newXMLHttpRequest(); 11 12 /*XMLHttpRequest的 readyState属性是一个数值,它指出请求生命周期的状态。它从 0(代表“未初始化”)变化到 4(代表“完成”)。每次 readyState变化时,readystatechange事件就触发,由 onreadystatechange属性指定的事件处理函数就被调用。*/ 13 req.onreadystatechange = getReadyStateHandler(req, updateCart); 14 15 //在web.xml中有匹配了cart.do的servlet 16 req.open("POST", "cart.do", true); 17 18 /* 19 HTTP 请求分为三个部分:状态行、请求头、消息主体。类似于下面这样: 20 <method> <request-URL> <version> 21 <headers> 22 23 <entity-body> 24 25 application/x-www-form-urlencoded是最常见的 POST 提交数据的方式了。浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样(无关的请求头在本文中都省略掉了): 26 27 POST http://www.example.com HTTP/1.1 28 Content-Type: application/x-www-form-urlencoded;charset=utf-8 29 30 title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3 31 首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。例如 PHP 中,$_POST['title'] 可以获取到 title 的值,$_POST['sub'] 可以得到 sub 数组。 32 很多时候,我们用 Ajax 提交数据时,也是使用这种方式。例如 JQuery 和 QWrap 的 Ajax,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。 33 */ 34 req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 35 req.send("action=add&item="+itemCode); 36 } 37 38 /* 39 * 令一种产品的数量减1 40 */ 41 function removeToCart(itemCode) { 42 43 var req = newXMLHttpRequest(); 44 45 req.onreadystatechange = getReadyStateHandler(req, updateCart); 46 47 //在web.xml中有匹配了cart.do的servlet 48 req.open("POST", "cart.do", true); 49 50 req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 51 req.send("action=remove&item="+itemCode); 52 } 53 54 55 /* 56 * Update shopping-cart area of page to reflect contents of cart 57 * described in XML document. 58 */ 59 /*由于servlet调用res.getWriter().write(cartXml); 60 所以cartXml的值会赋给requestXML属性返回的给request,具体返回的xml格式如下: 61 <car generated="xxxxxx" total="$xxxx""> 62 <item code="xx"> 63 <name>xx</name> 64 <quantity>xx</quantity> 65 </item> 66 <item code="xx"> 67 <name>xx</name> 68 <quantity>xx</quantity> 69 </item> 70 </car> 71 */ 72 /*更新购物车*/ 73 function updateCart(cartXML) { 74 var cart = cartXML.getElementsByTagName("cart")[0]; 75 var generated = cart.getAttribute("generated"); 76 if (generated > lastCartUpdate) { 77 lastCartUpdate = generated; 78 var contents = document.getElementById("contents"); 79 //把次取出id为"contents"的UL时,都把它的html内容清空,否则旧内容与新内容会叠加 80 contents.innerHTML = ""; 81 82 var items = cart.getElementsByTagName("item"); 83 for (var I = 0 ; I < items.length ; I++) { 84 85 var item = items[I]; 86 87 //得到<name>xx</name>的值 88 var name = item.getElementsByTagName("name")[0].firstChild.nodeValue; 89 //得到<quantity>xx</quantity>的值 90 var quantity = item.getElementsByTagName("quantity")[0].firstChild.nodeValue; 91 92 var listItem = document.createElement("li"); 93 listItem.appendChild(document.createTextNode(name+" x "+quantity)); 94 contents.appendChild(listItem); 95 } 96 97 } 98 99 document.getElementById("total").innerHTML = cart.getAttribute("total"); 100 }
6.ajax1.js
1 /* 2 * Returns an new XMLHttpRequest object, or false if the browser 3 * doesn't support it 4 */ 5 function newXMLHttpRequest() { 6 7 var xmlreq = false; 8 9 // Create XMLHttpRequest object in non-Microsoft browsers 10 if (window.XMLHttpRequest) { 11 xmlreq = new XMLHttpRequest(); 12 13 } else if (window.ActiveXObject) { 14 15 try { 16 // Try to create XMLHttpRequest in later versions 17 // of Internet Explorer 18 19 xmlreq = new ActiveXObject("Msxml2.XMLHTTP"); 20 21 } catch (e1) { 22 23 // Failed to create required ActiveXObject 24 25 try { 26 // Try version supported by older versions 27 // of Internet Explorer 28 29 xmlreq = new ActiveXObject("Microsoft.XMLHTTP"); 30 31 } catch (e2) { 32 33 // Unable to create an XMLHttpRequest by any means 34 xmlreq = false; 35 } 36 } 37 } 38 39 return xmlreq; 40 } 41 42 /* 43 * Returns a function that waits for the specified XMLHttpRequest 44 * to complete, then passes it XML response to the given handler function. 45 * req - The XMLHttpRequest whose state is changing 46 * responseXmlHandler - Function to pass the XML response to 47 */ 48 49 /*getReadyStateHandler()像这样被调用:handlerFunction = getReadyStateHandler(req, updateCart)。在这个示例中,getReadyStateHandler()返回的函数将检查在 req变量中的 XMLHttpRequest是否已经完成,然后用响应的 XML 调用名为 updateCart的函数。*/ 50 function getReadyStateHandler(req, responseXmlHandler) { 51 52 // Return an anonymous function that listens to the XMLHttpRequest instance 53 return function () { 54 55 // If the request's status is "complete" 56 if (req.readyState == 4) { 57 58 // Check that we received a successful response from the server 59 if (req.status == 200) { 60 61 // Pass the XML payload of the response to the handler function. 62 responseXmlHandler(req.responseXML); 63 64 } else { 65 66 // An HTTP problem has occurred 67 alert("HTTP error "+req.status+": "+req.statusText); 68 } 69 } 70 } 71 }
7.index.jsp
1 <%@ page import="java.util.*" %> 2 <%@ page import="developerworks.ajax.store.*" %> 3 <?xml version="1.0" encoding="utf-8"?> 4 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 5 <html xmlns="http://www.w3.org/1999/xhtml"> 6 <head> 7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 8 <script type="text/javascript" language="javascript" src="ajax1.js"></script> 9 <script type="text/javascript" language="javascript" src="cart.js"></script> 10 </head> 11 <body> 12 <div style="float: left; width: 500px"> 13 <h2>Catalog</h2> 14 <table border="1"> 15 <thead><th>Name</th><th>Description</th><th>Price</th><th></th></thead> 16 <tbody> 17 <% 18 for (Iterator<Item> I = new Catalog().getAllItems().iterator() ; I.hasNext() ; ) { 19 Item item = I.next(); 20 %> 21 <tr><td><%= item.getName() %></td><td><%= item.getDescription() %></td><td><%= item.getFormattedPrice() %></td><td><button onclick="addToCart('<%= item.getCode() %>')">Add to Cart</button></td> 22 <td><button onclick="removeToCart('<%= item.getCode() %>')">Delete to Cart</button></td></tr> 23 <% } %> 24 </tbody> 25 </table> 26 <div style="position: absolute; top: 0px; right: 0px; width: 250px"> 27 <h2>Cart Contents</h2> 28 <ul id="contents"> 29 </ul> 30 Total cost: <span id="total">$0.00</span> 31 </div> 32 </body> 33 </html>
8.web.xml
1 <?xml version="1.0" encoding="ISO-8859-1"?> 2 <web-app 3 xmlns="http://java.sun.com/xml/ns/j2ee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" 6 version="2.4"> 7 8 <display-name>Ajax Shopping-Cart WebApp</display-name> 9 10 <servlet> 11 <servlet-name>Cart</servlet-name> 12 <servlet-class>developerworks.ajax.servlet.CartServlet</servlet-class> 13 <load-on-startup>1</load-on-startup> 14 </servlet> 15 16 <servlet-mapping> 17 <servlet-name>Cart</servlet-name> 18 <url-pattern>/cart.do</url-pattern> 19 </servlet-mapping> 20 </web-app>
三、运行结果
转自:http://www.ibm.com/developerworks/cn/java/j-ajax1/
You can do anything you set your mind to, man!