1. 購物車的實現
1.1. 功能分析
1、購物車是一個獨立的表現層工程。
2、添加購物車不要求登錄。可以指定購買商品的數量。
3、展示購物車列表頁面
4、修改購物車商品數量
5、刪除購物車商品
模塊劃分結構
1.1. 添加購物車
1.1.1. 功能分析
在不登陸的情況下也可以添加購物車。把購物車信息寫入cookie。
優點:
1、不佔用服務端存儲空間
2、用戶體驗好。
3、代碼實現簡單。
缺點:
1、cookie中保存的容量有限。最大4k
2、把購物車信息保存在cookie中,更換設備購物車信息不能同步。
請求的url:/cart/add/{itemId}
參數:
1)商品id: Long itemId
2)商品數量: int num
業務邏輯:
1、從cookie中查詢商品列表。
2、判斷商品在商品列表中是否存在。
3、如果存在,商品數量相加。
4、不存在,根據商品id查詢商品信息。
5、把商品添加到購車列表。
6、把購車商品列表寫入cookie。
返回值:邏輯視圖
Controller
/** * 購物車Controller * @Auther: jun * @Date: 2018/5/31 0031 19:44 * @Description: */ @Controller public class CartController { @Autowired private ItemService itemService; @Autowired private CartService cartService; @Value("${COOKIE_CART_EXIPERE}") private Integer COOKIE_CART_EXIPERE; /** *添加購物車商品 * @auther: jun * @date: 2018/5/31 0031 22:16 * @param itemId,num,request,response * @return: java.lang.String * @Description: */ @RequestMapping("/cart/add/{itemId}") public String addCart(@PathVariable Long itemId, @RequestParam(defaultValue = "1") Integer num, HttpServletRequest request, HttpServletResponse response){ //判斷用戶是否登錄 //從request中獲取到用戶信息 TbUser user = (TbUser) request.getAttribute("user"); //判斷是否有值有就是登陸狀態把購物車寫入redis中 if (user !=null){ //保存到服務端(redis) cartService.addCart(user.getId(),itemId,num); //返回邏輯視圖 return "cartSuccess"; } //從cookie中獲取到購物車列表 List<TbItem> cartList = getCartListFromCookie(request); //用於判斷購物車中是否有添加的商品信息 boolean flag=false; //遍歷購物車商品列表 for (TbItem item:cartList) { //判斷添加的商品是否在購物冊列表中使用商品id判斷 if (itemId.equals(item.getId())){ //如果在flag爲true flag=true; //並且購物車中商品數量加上添加商品的的數量 item.setNum(item.getNum()+num); //跳出循環 break; } } //如果不存在 if(!flag){ //根據商品id查詢得到一個TbItem對象 TbItem item = itemService.getItemById(itemId); //設置商品數量 item.setNum(num); //取一張圖片 String image = item.getImage(); if (StringUtils.isNoneBlank(image)){ //設置第一張圖片 item.setImage(image.split(",")[0]); } //添加商品到購物車商品列表中 cartList.add(item); } //寫入cookie中需要數據需要轉換成json數據還有過期時間1個小時,還要編碼實現 CookieUtils.setCookie(request,response,"cart",JsonUtils.objectToJson(cartList),COOKIE_CART_EXIPERE,true); //返回邏輯視圖頁面 return "cartSuccess"; }
/** *從cookie中取購物車列表的處理 * @auther: jun * @date: 2018/5/31 0031 19:47 * @param request * @return: java.util.List<com.e3mall.pojo.TbItem> * @Description: */ private List<TbItem> getCartListFromCookie(HttpServletRequest request){ //從cookie中取出數據時需要轉碼 String json = CookieUtils.getCookieValue(request, "cart", true); //判斷json是否爲空 if (StringUtils.isBlank(json)){ //避免空值 return new ArrayList<>(); } //返回List的商品列表 return JsonUtils.jsonToList(json,TbItem.class); }
Service層
配置文件resource.properties
/** * 購物車Service * @Auther: jun * @Date: 2018/6/1 0001 15:23 * @Description: */ @Service public class CartServiceImpl implements CartService { @Autowired private JedisClient jedisClient; @Autowired private TbItemMapper itemMapper; @Value("${REDIS_CART_PRE}") private String REDIS_CART_PRE; @Override public E3Result addCart(Long userId, Long itemId,Integer num) { //向redis中添加購物車 //數據類型:hash類型 key:用戶id filed:商品id value :商品信息 //判斷商品是否存在 Boolean hexists = jedisClient.hexists(REDIS_CART_PRE + ":" + userId, itemId.toString()); if (hexists){ //存在獲取到redis中的存在的商品值 String json = jedisClient.hget(REDIS_CART_PRE + ":" + userId, itemId.toString()); //把json轉換成pojo對象 TbItem item = JsonUtils.jsonToPojo(json, TbItem.class); //數量相加 item.setNum(item.getNum()+num); //重新寫入redis中 jedisClient.hset(REDIS_CART_PRE + ":" + userId,itemId.toString(),JsonUtils.objectToJson(item)); //退出返回結果 return E3Result.ok(); } //不存在就是要查詢數據庫並且存入redis中 //根據商品id查詢商品信息 TbItem item = itemMapper.selectByPrimaryKey(itemId); //設置數量 item.setNum(num); //取一張圖片存入item中 String image = item.getImage(); if (StringUtils.isNoneBlank(image)){ item.setImage(image.split(",")[0]); } jedisClient.hset(REDIS_CART_PRE + ":" + userId,itemId.toString(),JsonUtils.objectToJson(item)); return E3Result.ok(); }
applicationContent-service.xml發佈服務
<!-- 使用dubbo發佈服務 --> <!-- 提供方應用信息,用於計算依賴關係 --> <dubbo:application name="e3-sso" /> <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181" /> <!-- 用dubbo協議在20880端口暴露服務 --> <dubbo:protocol name="dubbo" port="20884" /> <!-- 聲明需要暴露的服務接口 --> <!--購物車服務--> <dubbo:service interface="com.e3mall.cart.service.CartService" ref="cartServiceImpl" timeout="600000"/>
springmvc.xml 調用服務
<!-- 引用dubbo服務 --> <dubbo:application name="e3-cart-web"/> <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/> <!--商品服務--> <dubbo:reference interface="com.e3mall.service.ItemService" id="itemService" /> <!--sso服務--> <dubbo:reference interface="com.e3mall.sso.service.TokenService" id="tokenService" /> <dobbo:reference interface="com.e3mall.cart.service.CartService" id="cartService"/>
配置用戶攔截器判斷用戶是登錄和未登錄狀態
/** * 用戶登錄攔截器實現 * * @Auther: jun * @Date: 2018/6/1 0001 14:38 * @Description: */ public class LoginInterceptor implements HandlerInterceptor { @Autowired private TokenService tokenService; @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception { //前處理,執行handler之前執行此方法 // 返回true 放行 false 攔截 //1.從cookie中取出token String token = CookieUtils.getCookieValue(httpServletRequest, "token"); //2.如果沒有token,未登錄狀態,直接放行 if (StringUtils.isBlank(token)){ //放行 return true; } //3.取到token,炫耀調用sso系統的服務,根據token去用戶信息 E3Result result = tokenService.getUserByToker(token); //4.沒有取到用戶信息,登錄過期,直接放行 //判斷狀態爲200 登錄成功 if (result.getStatus()!=200){ return true; } //在token中取用戶信息 //5.取到用戶信息,登錄狀態 TbUser user = (TbUser) result.getData(); //6.把用戶信息放到request中,只需要在Controller中判斷request中是否包含user信息 httpServletRequest.setAttribute("user",user); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, ModelAndView modelAndView) throws Exception { //handler執行之後,返回ModelAndView之前 } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception e) throws Exception { //完成處理之後,返回ModelAndView之後 //可以在此處理異常 }
在springmvc.xml攔截器配置
<mvc:interceptors> <mvc:interceptor> <!--攔截所有的url--> <mvc:mapping path="/**"/> <!--配置攔截器的實現類--> <bean class="com.e3mall.cart.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors>
1.1. 展示購物車商品列表
請求的url:/cart/cart
參數:無
返回值:邏輯視圖
業務邏輯:
需要考慮登錄用戶redis中的購物車數據和cookie中的數據和並
沒有登錄就展示cookie中的數據
1、從cookie中取商品列表。
2、把商品列表傳遞給頁面。
引用服務/** *購物車展示 * @auther: jun * @date: 2018/5/31 0031 20:38 * @param request * @return: java.lang.String * @Description: */ @RequestMapping("/cart/cart") public String showCartList(HttpServletRequest request,HttpServletResponse response){ //從cookie中取購物車列表 List<TbItem> cartList = getCartListFromCookie(request); //判斷用戶是否爲登錄狀態 TbUser user = (TbUser) request.getAttribute("user"); //如果是登錄狀態 if (user!=null){ //如果不爲空,把cookie購物車和redis中的購物車商品信息合併 cartService.mergeCart(cartList, user.getId()); //把cookie中的購物車商品刪除 CookieUtils.deleteCookie(request,response,"cart"); //從redis取購物車列表信息 cartList = cartService.getCartList(user.getId()); } //未登錄狀態 // List<TbItem> cartList = cartList; //把列表轉遞給頁面 request.setAttribute("cartList",cartList); //返回邏輯視圖 return "cart"; }
Service
合併數據的實現方法
@Override public E3Result mergeCart(List<TbItem> itemList, Long userId) { //遍歷商品列表 //把商品列表添加到購物車中 //判斷購物車中是否有該商品 //如果有就商品數量相加 //沒有就添加新的商品信息 for (TbItem item : itemList) { //調用添加購物車方法實現 addCart(userId,item.getId(),item.getNum()); } //返回成功 return E3Result.ok(); }
展示購物車數據
@Override public List<TbItem> getCartList(Long userId) { //根據用戶id查詢購物車商品列表(redis 中的鍵找值) List<String> jsonList = jedisClient.hvals(REDIS_CART_PRE + ":" + userId); //創建一個商品列表信息 List<TbItem> itemList=new ArrayList<>(); for (String string : jsonList) { //獲取到json中一個數據並轉換數據類型成pojo對象 TbItem item = JsonUtils.jsonToPojo(string, TbItem.class); //添加到列表 itemList.add(item); } //返回列表 return itemList; }
發佈服務
1.1. 修改購物車商品數量
1.1.1. 功能分析
1、在頁面中可以修改商品數量
2、重新計算小計和總計。
3、修改需要寫入cookie。
4、每次修改都需要向服務端發送一個ajax請求,在服務端修改cookie中的商品數量。
請求的url:/cart/update/num/{itemId}/{num}
參數:long itemId、int num
業務邏輯:
1、接收兩個參數
2、從cookie中取商品列表
3、遍歷商品列表找到對應商品
4、更新商品數量
5、把商品列表寫入cookie。
6、響應e3Result。Json數據。
返回值:
e3Result。Json數據
Controller
引用服務
/** *修改商品數據功能 * @auther: jun * @date: 2018/5/31 0031 22:16 * @param itemId,num,request,response * @return: com.e3mall.common.utils.E3Result * @Description: */ @RequestMapping("/cart/update/num/{itemId}/{num}") @ResponseBody public E3Result updateCartNum(@PathVariable Long itemId,@PathVariable Integer num, HttpServletRequest request,HttpServletResponse response){ //獲取登錄信息 TbUser user = (TbUser) request.getAttribute("user"); //判斷登錄狀態 if (user!=null){ //調用服務更新 cartService.updateCartNum(user.getId(), itemId, num); return E3Result.ok(); } //從cookie中獲取到商品列表 List<TbItem> cartList= getCartListFromCookie(request); //遍歷列表 for (TbItem item:cartList){ //根據id修改商品列表中的數量信息 if (itemId==item.getId().longValue()){ item.setNum(num); } //退出 break; } //把購物車寫回cookie CookieUtils.setCookie(request,response,"cart",JsonUtils.objectToJson(cartList),COOKIE_CART_EXIPERE,true); //返回結果 return E3Result.ok(); }
Service
@Override public E3Result updateCartNum(Long userId, Long itemId, Integer num) { //獲取到購物車中商品信息 String json = jedisClient.hget(REDIS_CART_PRE + ":" + userId, itemId.toString()); //轉換json成pojo對象 TbItem item = JsonUtils.jsonToPojo(json, TbItem.class); //寫入數量 item.setNum(num); //回寫到redis中 jedisClient.hset(REDIS_CART_PRE + ":" + userId,itemId.toString(),JsonUtils.objectToJson(item)); //返回結果 return E3Result.ok(); }
發佈服務
2、重新計算小計和總計。jsp頁面修改
1.修改cart.jsp
cart.js
加減方法中添加的
CART.refreshTotal(_thisInput.val(),_thisInput.attr("itemId"));
1.1. 刪除購物車商品
1.1.1. 功能分析
請求的url:/cart/delete/{itemId}
參數:商品id
返回值:展示購物車列表頁面。Url需要做redirect跳轉。
業務邏輯:
1、從url中取商品id
2、從cookie中取購物車商品列表
3、遍歷列表找到對應的商品
4、刪除商品。
5、把商品列表寫入cookie。
6、返回邏輯視圖:在邏輯視圖中做redirect跳轉。
Controller
引用服務
/** *刪除購物車商品 * @auther: jun * @date: 2018/6/1 0001 17:18 * @param itemId,request,response * @return: java.lang.String * @Description: */ @RequestMapping("/cart/delete/{itemId}") public String deleteCartItem(@PathVariable Long itemId, HttpServletRequest request,HttpServletResponse response){ //獲取登錄信息 TbUser user = (TbUser) request.getAttribute("user"); //判斷登錄狀態 if (user!=null){ //調用服務更新 cartService.deleteCartItem(user.getId(), itemId); //返回邏輯視圖 return "redirect:/cart/cart.html"; } //從cookie中獲取商品列表 List<TbItem> cartList = getCartListFromCookie(request); //遍歷列表 for (TbItem item:cartList){ //根據id刪除指定商品列表中的數據 if (itemId==item.getId().longValue()){ //移除cookie中的商品信息 cartList.remove(item); } //退出 break; }Service
@Override public E3Result deleteCartItem(Long userId, Long itemId) { //刪除指定id的商品 jedisClient.hdel(REDIS_CART_PRE + ":" + userId,itemId.toString()); //返回結果 return E3Result.ok(); }
發佈服務
清空購物車
需要修改一下jsp並且還要寫一段js代碼
Controller代碼
/** *清空購物車 * @auther: jun * @date: 2018/6/4 0004 13:10 * @param request * @param response * @return: java.lang.String * @Description: */ @RequestMapping("/cart/clearCart") public String clearCart(HttpServletRequest request, HttpServletResponse response) throws IOException { //獲取用戶信息 TbUser user = (TbUser) request.getAttribute ("user"); //是否登錄狀態 if (user != null) { //調用服務清除購物車合併後的數據 cartService.clearCartItem (user.getId ()); return "redirect:/cart/cart.html"; } //cookie清除 CookieUtils.deleteCookie (request, response, "cart"); return "redirect:/cart/cart.html"; }
調用服務
@Override public E3Result clearCartItem(Long userId) { //刪除購物車信息 jedisClient.del (REDIS_CART_PRE+":"+userId); return E3Result.ok (); }
發佈服務
刪除選中的商品的功能實現
jsp修改頁面value
js代碼段
Controller
這裏我們考慮了登錄和未登錄狀態問題所以我們操作了cookie數據和redis中的數據
/** * 批量刪除購物車中的商品 * * @param ids * @param request * @param response * @auther: jun * @date: 2018/6/4 0004 10:48 * @return: com.e3mall.common.utils.E3Result * @Description: */ @RequestMapping(value = "/cart/cartDelMore") @ResponseBody public E3Result cartDelMore(String[] ids, HttpServletRequest request, HttpServletResponse response) { //判斷是否是登錄狀態 TbUser user = (TbUser) request.getAttribute ("user"); if (user != null) { //調用服務執行批量刪除商品 cartService.cartDelMore (user.getId (), ids); } //未登錄狀態 //從cookie中獲取商品列表 List<TbItem> cartList = getCartListFromCookie (request); //遍歷參數數組 for (String id : ids) { //遍歷商品列表 for (TbItem item : cartList) { //判斷 if (Long.parseLong (id) ==item.getId ().longValue () ) { //移除 cartList.remove (item); //退出當前商品列表集合 break; } } } //重新寫入列表到cookie CookieUtils.setCookie (request, response, "cart", JsonUtils.objectToJson (cartList), COOKIE_CART_EXIPERE, true); return E3Result.ok (); }
Service
@Override public E3Result cartDelMore(Long userId, String[] ids) { for (String itemId:ids){ //刪除指定id的商品 jedisClient.hdel(REDIS_CART_PRE + ":" + userId,itemId); } return E3Result.ok (); }
1.1. 小結
使用cookie實現購物車:
優點:
1、實現簡單
2、不需要佔用服務端存儲空間。
缺點:
1、存儲容量有限
2、更換設備購車信息不能同步。
實現購車商品數據同步:
1、要求用戶登錄。
2、把購物車商品列表保存到數據庫中。推薦使用redis。
3、Key:用戶id,value:購車商品列表。推薦使用hash,hash的field:商品id,value:商品信息。
4、在用戶未登錄情況下寫cookie。當用戶登錄後,訪問購物車列表時,
a) 把cookie中的數據同步到redis。
b) 把cookie中的數據刪除
c) 展示購物車列表時以redis爲準。
d) 如果redis中有數據cookie中也有數據,需要做數據合併。相同商品數量相加,不同商品添加一個新商品。
如果用戶登錄狀態,展示購物車列表以redis爲準。如果未登錄,以cookie爲準。