功能分析:
1、在用户不登陆的情况下也可以使用购物车,那么就需要把购物车信息放入cookie中。
2、可以把商品信息,存放到pojo中,然后序列化成json存入cookie中。
3、取商品信息可以从cookie中把json数据取出来,然后转换成java对象即可。
4、此功能只需要操作cookie不需要数据库的支持,所以只需要在taotao-portal中实现即可。
5、购物车分有四种动作
a) 添加商品
b) 修改商品数量
c) 删除购物车中的商品
d) 展示购物车商品列表
service层代码:
package com.taotao.portal.service.impl; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.taotao.common.pojo.TaotaoResult; import com.taotao.common.utils.CookieUtils; import com.taotao.common.utils.HttpClientUtil; import com.taotao.common.utils.JsonUtils; import com.taotao.pojo.TbItem; import com.taotao.portal.pojo.CartItem; import com.taotao.portal.service.CartService; /** * 购物车service * @author Administrator */ @Service public class CartServiceImpl implements CartService { //rest服务基础url @Value("${REST_BASE_URL}") private String REST_BASE_URL; //获取商品信息的url @Value("${ITEM_INFO_URL}") private String ITEM_INFO_URL; /** * 添加购物车商品 * 1、接收controller传递过来的商品id,根据商品id查询商品信息。 2、从cookie中取出购物车信息,转换成商品pojo列表。 3、把商品信息添加到商品列表中。 参数: 1、商品id 2、Request 3、response 返回值: TaoTaoResult 同时此方法还可以作为 点击购物车商品的“+”、“-”号时增加或减少商品数量 的方法, 点 加号时,传参数 num = 1 点 减号时,传参数 num = -1 */ @Override public TaotaoResult addCartItem(long itemId, int num, HttpServletRequest request,HttpServletResponse response) { //当前id对应的购物车商品 CartItem cartItem = null; //从cookie中获取购物车列表 ListcartList = getCartItemList(request); //先判断原购物车列表中是否有当前商品 for (CartItem item : cartList) { //如果存在 if (item.getId()==itemId) { //增加商品数量 item.setNum(item.getNum()+num); cartItem = item; break; } } //如果原来没有此商品,则新建 if (cartItem==null) { cartItem = new CartItem(); //调用rest服务获取商品信息 String doGetResult = HttpClientUtil.doGet(REST_BASE_URL+ITEM_INFO_URL+itemId); TaotaoResult taoTaoResult = TaotaoResult.formatToPojo(doGetResult, TbItem.class); if (taoTaoResult.getStatus()==200) { //封装成购物车商品对象 TbItem item = (TbItem) taoTaoResult.getData(); cartItem.setId(itemId); cartItem.setImage(item.getImage()==null?"":item.getImage().split(",")[0]); cartItem.setPrice(item.getPrice()); cartItem.setTitle(item.getTitle()); cartItem.setSellPoint(item.getSellPoint()); cartItem.setNum(num); //将商品加入到购物车列表中 cartList.add(cartItem); } } //将购物车列表写回cookie String listJson = JsonUtils.objectToJson(cartList); //最后一个参数 true,对数据进行编码,这样在 cookie中就看不到中文原始数据了 CookieUtils.setCookie(request, response, "TT_CART", listJson,true); return TaotaoResult.ok(); } /** * 从cookie中取商品列表 * @param request * @return */ private List getCartItemList(HttpServletRequest request) { //从cookie中取商品列表 String cartJson = CookieUtils.getCookieValue(request, "TT_CART",true); if (cartJson==null) { return new ArrayList (); } //把json转换为商品列表 try { List list = JsonUtils.jsonToList(cartJson, CartItem.class); return list; } catch (Exception e) { e.printStackTrace(); } return new ArrayList (); } /** * 获取 购物车商品列表供前台展示 */ @Override public List getCartItemList(HttpServletRequest request, HttpServletResponse response) { List result = getCartItemList(request); return result; } /** * 直接输入数量,更新购物车中商品的数量(在购物车列表展示页面中使用) */ @Override public TaotaoResult updateCartItmeNum(long itemId, int num, HttpServletRequest request, HttpServletResponse response){ //当前id对应的购物车商品 CartItem cartItem = null; //从cookie中获取购物车列表 List cartList = getCartItemList(request); //先判断原购物车列表中是否有当前商品 for (CartItem item : cartList) { //如果存在 if (item.getId()==itemId) { //修改商品数量 item.setNum(num); cartItem = item; break; } } //将购物车列表写回cookie String listJson = JsonUtils.objectToJson(cartList); //最后一个参数 true,对数据进行编码,这样在 cookie中就看不到中文原始数据了 CookieUtils.setCookie(request, response, "TT_CART", listJson,true); return TaotaoResult.ok(); } /** * 删除购物车中商品 * @param itemId * @param request * @param response * @return */ @Override public TaotaoResult delCartItem(long itemId, HttpServletRequest request, HttpServletResponse response){ //当前id对应的购物车商品 CartItem cartItem = null; //从cookie中获取购物车列表 List cartList = getCartItemList(request); Iterator iterator = cartList.iterator(); //遍历 while (iterator.hasNext()) { CartItem item = iterator.next(); //找到对应的商品 if (item.getId()==itemId) { //执行删除动作 iterator.remove(); break; } } //将购物车列表写回cookie String listJson = JsonUtils.objectToJson(cartList); //最后一个参数 true,对数据进行编码,这样在 cookie中就看不到中文原始数据了 CookieUtils.setCookie(request, response, "TT_CART", listJson,true); return TaotaoResult.ok(); } }
Controller 层代码:
package com.taotao.portal.controller; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import com.taotao.portal.pojo.CartItem; import com.taotao.portal.service.CartService; /** * 购物车的Controller * @author Administrator */ @Controller @RequestMapping("/cart") public class CartController { @Autowired private CartService cartService; /** * 添加商品到购物车 * @param itemId * @param num * @param request * @param response * @return * * 同时此方法还可以作为 点击购物车商品的“+”、“-”号时增加或减少商品数量 的方法, 点 加号时,传参数 num = 1 点 减号时,传参数 num = -1 */ @RequestMapping("/add/{itemId}") public String addCartItem(@PathVariable Long itemId, @RequestParam(defaultValue="1")Integer num, HttpServletRequest request,HttpServletResponse response) { cartService.addCartItem(itemId, num, request, response); // return "cartSuccess"; //这样会打开新的页面,所以不用 //为了 避免每次添加完商品都打开新的页面,所以这里这样重定向 return "redirect:/cart/success.html"; // return "forward:/cart/success.html"; //这种写法也可以(请求转发) } //接收重定向的请求返回jsp页面 @RequestMapping("/success") public String showSuccess(){ return "cartSuccess"; } /** * 查询购物车中的商品列表返回前台展示 * @param request * @param response * @param model * @return */ @RequestMapping("/cart") public String showCart(HttpServletRequest request,HttpServletResponse response,Model model){ ListcartItemList = cartService.getCartItemList(request, response); model.addAttribute("cartList", cartItemList); return "cart"; } /** * 手动填写直接修改商品数量 * @param itemId * @param num * @param request * @param response * @return */ @RequestMapping("/update/{itemId}") public String updateCartItemNum(@PathVariable Long itemId, @RequestParam(defaultValue="0")Integer num, HttpServletRequest request,HttpServletResponse response) { cartService.updateCartItmeNum(itemId, num, request, response); return "redirect:/cart/cart.html"; } /** * 删除购物车中的指定商品 * @param itemId * @param request * @param response * @return */ @RequestMapping("/delete/{itemId}") public String delCartItem(@PathVariable Long itemId, HttpServletRequest request,HttpServletResponse response){ cartService.delCartItem(itemId, request, response); return "redirect:/cart/cart.html"; } }
添加完购物车后的成功跳转页:
cartSuccess.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page trimDirectiveWhitespaces="true" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>${item.title } - 淘淘title> <script>var jdpts = new Object(); jdpts._st = new Date().getTime();script> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link rel="stylesheet" type="text/css" href="/css/taotao.css" media="all" /> <link rel="stylesheet" type="text/css" href="/css/pshow.css" media="all" /> <script type="text/javascript"> window.pageConfig = { compatible: true, product: { skuid: 1221882, name: '\u957f\u8679\uff08\u0043\u0048\u0041\u004e\u0047\u0048\u004f\u004e\u0047\uff09\u004c\u0045\u0044\u0034\u0032\u0035\u0033\u0038\u0045\u0053\u0020\u0034\u0032\u82f1\u5bf8\u0020\u7a84\u8fb9\u84dd\u5149\u004c\u0045\u0044\u6db2\u6676\u7535\u89c6\uff08\u9ed1\u8272\uff09', skuidkey:'E804B1D153D29E36088A33A134D85EEA', href: 'http://item.jd.com/1221882.html', src: 'jfs/t304/157/750353441/93159/e4ee9876/54227256N20d4f5ec.jpg', cat: [737,794,798], brand: 20710, nBrand: 20710, tips: false, type: 1, venderId:0, shopId:'0', TJ:'0', specialAttrs:["HYKHSP-0","isHaveYB","isSelfService-0","isWeChatStock-0","isCanUseJQ","isOverseaPurchase-0","YuShou","is7ToReturn-1","isCanVAT"], videoPath:'', HM:'0' } }; script> head> <body version="140120"> <script type="text/javascript">try{(function(flag){ if(!flag){return;} if(window.location.hash == '#m'){var exp = new Date();exp.setTime(exp.getTime() + 30 * 24 * 60 * 60 * 1000);document.cookie = "pcm=1;expires=" + exp.toGMTString() + ";path=/;domain=jd.com";return;}else{var cook=document.cookie.match(new RegExp("(^| )pcm=([^;]*)(;|$)"));var flag=false;if(cook&&cook.length>2&&unescape(cook[2])=="1"){flag=true;}} var userAgent = navigator.userAgent; if(userAgent){ userAgent = userAgent.toUpperCase();if(userAgent.indexOf("PAD")>-1){return;} var mobilePhoneList = ["IOS","IPHONE","ANDROID","WINDOWS PHONE"];for(var i=0,len=mobilePhoneList.length;i<len;i++){ if(userAgent.indexOf(mobilePhoneList[i])>-1){var url="http://m.jd.com/product/"+pageConfig.product.skuid+".html";if(flag){pageConfig.product.showtouchurl=true;}else{window.location.href = url;}break;}}}})((function(){var json={"6881":3,"1195":3,"10011":3,"6980":3,"12360":3};if(json[pageConfig.product.cat[0]+""]==1||json[pageConfig.product.cat[1]+""]==2||json[pageConfig.product.cat[2]+""]==3){return false;}else{return true;}})());}catch(e){}script> <jsp:include page="commons/header.jsp" /> 商品已经成功加入购物车 <a href ="/cart/cart.html">去购物车结算a> <jsp:include page="commons/footer.jsp" /> body> html>
购物车列表页的jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page trimDirectiveWhitespaces="true" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta name="format-detection" content="telephone=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="format-detection" content="telephone=no"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="/css/base.css"> <link href="/css/purchase.2012.css?v=201410141639" rel="stylesheet" type="text/css"> <title>我的购物车 - 淘淘商城title> <script> var pageConfig = {}; script> <body> <jsp:include page="commons/shortcut.jsp" /> <div class="w w1 header clearfix"> <div id="logo"><a href="/"><img clstag="clickcart|keycount|xincart|logo" src="/images/taotao-logo.gif" title="返回淘淘商城首页" alt="返回淘淘商城首页">a>div> <div class="language"><a href="javascript:void(0);" onclick="toEnCart()">a>div> <div class="progress clearfix"> <ul class="progress-1"> <li class="step-1"><b>b>1.我的购物车li> <li class="step-2"><b>b>2.填写核对订单信息li> <li class="step-3">3.成功提交订单li> ul> div> div> <div class="w cart"> <div class="cart-hd group"> <h2>我的购物车h2> div> <div id="show"> <div class="cart-frame"> <div class="tl">div> <div class="tr">div> div> <div class="cart-inner"> <div class="cart-thead clearfix"> <div class="column t-checkbox form"><input data-cart="toggle-cb" name="toggle-checkboxes" id="toggle-checkboxes_up" type="checkbox" checked="" value=""><label for="toggle-checkboxes_up">全选label>div> <div class="column t-goods">商品div> <div class="column t-price">淘淘价div> <div class="column t-promotion">优惠div> <div class="column t-inventory">库存div> <div class="column t-quantity">数量div> <div class="column t-action">操作div> div> <div id="product-list" class="cart-tbody"> <c:set var="totalPrice" value="0">c:set> <c:forEach items="${cartList}" var="cart"> <c:set var="totalPrice" value="${ totalPrice + (cart.price * cart.num)}"/> <div id="product_11345721" data-bind="rowid:1" class="item item_selected "> <div class="item_form clearfix"> <div class="cell p-checkbox"><input data-bind="cbid:1" class="checkbox" type="checkbox" name="checkItem" checked="" value="11345721-1">div> <div class="cell p-goods"> <div class="p-img"> <a href="/item/${cart.id }.html" target="_blank"> <img clstag="clickcart|keycount|xincart|p-imglistcart" src="${cart.image}" alt="${cart.title}" width="52" height="52"> a> div> <div class="p-name"> <a href="/item/${cart.id }.html" clstag="clickcart|keycount|xincart|productnamelink" target="_blank">${cart.title}a> <span class="promise411 promise411_11345721" id="promise411_11345721">span> div> div> <div class="cell p-price"><span class="price">¥<fmt:formatNumber groupingUsed="false" value="${cart.price / 100}" maxFractionDigits="2" minFractionDigits="2"/> span>div> <div class="cell p-promotion"> div> <div class="cell p-inventory stock-11345721">有货div> <div class="cell p-quantity" for-stock="for-stock-11345721"> <div class="quantity-form" data-bind=""> <a href="javascript:void(0);" class="decrement" clstag="clickcart|keycount|xincart|diminish1" id="decrement">-a> <input type="text" class="quantity-text" itemPrice="${cart.price}" itemId="${cart.id}" value="${cart.num }" id="changeQuantity-11345721-1-1-0"> <a href="javascript:void(0);" class="increment" clstag="clickcart|keycount|xincart|add1" id="increment">+a> div> div> <div class="cell p-remove"><a id="remove-11345721-1" data-more="removed-87.20-1" clstag="clickcart|keycount|xincart|btndel318558" class="cart-remove" href="/cart/delete/${cart.id}.html">删除a> div> div> div> c:forEach> div> <div class="cart-toolbar clearfix"> <div class="total fr"> <p><span class="totalSkuPrice">¥<fmt:formatNumber value="${totalPrice / 100}" maxFractionDigits="2" minFractionDigits="2" groupingUsed="true"/>span>总计:p> <p><span id="totalRePrice">- ¥0.00span>优惠:p> div> <div class="amout fr"><span id="selectedCount">1span> 件商品div> div> <div class="ui-ceilinglamp-1" style="width: 988px; height: 49px;"><div class="cart-dibu ui-ceilinglamp-current" style="width: 988px; height: 49px;"> <div class="control fdibu fdibucurrent"> <span class="column t-checkbox form"> <input data-cart="toggle-cb" name="toggle-checkboxes" id="toggle-checkboxes_down" type="checkbox" checked="" value="" class="jdcheckbox"> <label for="toggle-checkboxes_down"> 全选 label> span> <span class="delete"> <b> b> <a href="javascript:void(0);" clstag="clickcart|keycount|xincart|clearcartlink" id="remove-batch"> 删除选中的商品 a> span> <span class="shopping"> <b> b> <a href="/" target="_blank" clstag="clickcart|keycount|xincart|coudanlink" id="continue">继续购物a> span> div> <div class="cart-total-2014"> <div class="cart-button"> <span class="check-comm-btns" id="checkout-jd"> <a class="checkout" href="/order/order-cart.html" clstag="clickcart|keycount|xincart|gotoOrderInfo" id="toSettlement">去结算<b>b>a> span> <span class="combine-btns" style="display:none"> <span class="fore1" style="display: none;"> <a href="" class="combine-btn">不支持合并付款a> span> <span class="fore2 hide" style="display: inline;"> <a href="javascript:goToOverseaOrder();" class="checkout-jdInt">去淘淘国际结算<b>b>a> <a href="javascript:goToOrder();" class="checkout-jd">去淘淘结算<b>b>a> span> span> div> <div class="total fr"> 总计(不含运费): <span class="totalSkuPrice">¥<fmt:formatNumber value="${totalPrice / 100}" maxFractionDigits="2" minFractionDigits="2" groupingUsed="true"/>span> div> div> div>div> div> div> div> <script type="text/javascript" src="/js/base-v1.js">script> <jsp:include page="commons/footer.jsp" /> <script type="text/javascript" src="/js/cart.js">script> <script type="text/javascript" src="/js/jquery.price_format.2.0.min.js">script> html>
购物车列表页面引用的 js:
var TTCart = { load : function(){ // 加载购物车数据 }, itemNumChange : function(){ $(".increment").click(function(){//+ var _thisInput = $(this).siblings("input"); _thisInput.val(eval(_thisInput.val()) + 1); $.post("/cart/add/"+_thisInput.attr("itemId")+".html?num=1",function(data){ TTCart.refreshTotalPrice(); }); }); $(".decrement").click(function(){//- var _thisInput = $(this).siblings("input"); if(eval(_thisInput.val()) == 1){ return ; } _thisInput.val(eval(_thisInput.val()) - 1); $.post("/cart/add/"+_thisInput.attr("itemId")+".html?num=-1",function(data){ TTCart.refreshTotalPrice(); }); }); $(".quantity-form .quantity-text").rnumber(1);//限制只能输入数字 $(".quantity-form .quantity-text").change(function(){ var _thisInput = $(this); $.post("/cart/update/"+_thisInput.attr("itemId")+".html?num="+_thisInput.val(),function(data){ TTCart.refreshTotalPrice(); }); }); }, refreshTotalPrice : function(){ //重新计算总价 var total = 0; $(".quantity-form .quantity-text").each(function(i,e){ var _this = $(e); total += (eval(_this.attr("itemPrice")) * 10000 * eval(_this.val())) / 10000; }); $(".totalSkuPrice").html(new Number(total/100).toFixed(2)).priceFormat({ //价格格式化插件 prefix: '¥', thousandsSeparator: ',', centsLimit: 2 }); } }; $(function(){ TTCart.load(); TTCart.itemNumChange(); });
上面代码没有解决的问题: