一、本節主要講了e3mall購物車的實現方法,我搭建的項目和系統購物車有一些區別,所以這裏須要說一下。系統搭建的項目在未登錄的狀況下也能夠經過cookie進行加入購物車,當用戶要下單的時候再進行攔截(配置攔截器),若用戶沒登錄。則跳轉登錄頁面,登錄完成後繼續剛纔的操做,同時把cookies中的商品加入到後臺redis緩存中(其中須要判斷redis中是否含有該商品,若含有,則增長數量),而後進行支付購買。若用戶已登錄,加入的購物車則直接保存到後臺redis緩存中。相似JD。
二、而我搭建的項目購物車是不存入cookies中的,在e3mall-cart這個項目中就配置了攔截器,若用戶未登錄則強制登錄,登錄後繼續以前的操做,保存的購物車商品數據都是存在redis緩存中的。所以我搭建的業務邏輯稍微簡單一點。
三、後面我把留下的做業也作了,就是在修改購物車中商品的數量的時候,該商品的小計不會跟隨數量的變化而變化這個BUG。html
用戶在購物車選購商品的時候,強制登錄。登陸後把購物車數據保存到服務端。須要永久保存,能夠保存到數據庫中。能夠把購物車數據保存到redis中。此處保存到redis中。
redis使用的數據類型(由於購物車的數據不須要使用TTL,所以建議使用hash)
a)使用hash數據類型
b)Hash的key應該是用戶id。Hash中的field是商品id,value能夠把商品信息轉換成json
添加購物車
直接把商品數據保存到redis中。
如何判斷是否登陸?
a)從cookie中取token
b)取不到未登陸
c)取到token,到redis中查詢token是否過時。
d)若是過時,未登陸狀態
e)沒過時登陸狀態。java
應該使用springmvc攔截器實現。
一、實現一個HandlerInterceptor接口。
二、在執行handler方法以前作業務處理
三、從cookie中取token。使用CookieUtils工具類實現。
四、沒有取到token,用戶未登陸。攔截,使用response.sendredirect()進行跳轉
五、取到token,調用sso系統的服務,根據token查詢用戶信息。
六、沒有返回用戶信息(null)。登陸已通過期,未登陸,攔截,使用response.sendredirect()進行跳轉
七、返回用戶信息。用戶是登陸狀態。能夠把用戶對象保存到request中,在Controller中能夠經過判斷request中是否包含用戶對象,肯定是否爲登陸狀態,放行。web
首先來配置一下登錄攔截器
Logininterceptor .javaredis
package cn.tsu.cart.e3mall.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.jboss.netty.util.internal.StringUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import cn.tsu.cart.e3mall.config.CartConfig; import cn.tsu.cart.e3mall.service.TokenService; import cn.tsu.e3mall.pojo.TbUser; import cn.tsu.e3mall.utils.CookieUtils; import cn.tsu.e3mall.utils.E3Result; import cn.tsu.sso.e3mall.service.UserService; /** * 判斷用戶是否登陸的攔截器 * @author xiaofeng * */ public class Logininterceptor implements HandlerInterceptor { @Autowired private TokenService tokenService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //獲取請求的連接 String url = request.getRequestURL().toString(); //若是連接中包含cart if (url.contains("cart")) { //從cookie中取token。使用CookieUtils工具類實現 String cookieValue = CookieUtils.getCookieValue(request, "USER_LOGIN_TOKEN"); //若是取到的數據不爲空 if (StringUtils.isNotBlank(cookieValue)) { //經過token獲取e3result對象 E3Result e3Result = tokenService.getToken(cookieValue); //若是對象的status是200的話,說明取到 if (e3Result.getStatus() == 200) { //轉爲tbuser對象 TbUser tbUser = (TbUser) e3Result.getData(); request.setAttribute("tbUser", tbUser); return true; } } } //不然則跳轉登錄頁面並把url也傳過去。 response.sendRedirect(CartConfig.LOGIN_HEAD+"/page/login?redirect="+url); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub } }
service層代碼:
CartServiceImpl.javaspring
package cn.tsu.cart.e3mall.service.impl; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import cn.tsu.cart.e3mall.service.CartService; import cn.tsu.e3mall.dao.TbItemMapper; import cn.tsu.e3mall.jedis.JedisClient; import cn.tsu.e3mall.pojo.TbItem; import cn.tsu.e3mall.utils.E3Result; import cn.tsu.e3mall.utils.JsonUtils; import cn.tsu.sso.e3mall.service.config.UserConfig; /** * 操做購物車 * @author xiaofeng * */ @Service public class CartServiceImpl implements CartService { @Autowired private JedisClient jedisClient; @Autowired private TbItemMapper itemMapper; // 添加購物車 @Override public E3Result addCart(Long userid, Long itemid, int num) { //查詢redis緩存中是否含有該field Boolean hexists = jedisClient.hexists(UserConfig.CART_REDIS_PRE+userid,itemid+""); //若是有 if (hexists) { //獲取該hash的field的值 String hget = jedisClient.hget(UserConfig.CART_REDIS_PRE+userid,itemid+""); //將string值轉化爲對象 TbItem tbItem = JsonUtils.jsonToPojo(hget, TbItem.class); //增長數量 tbItem.setNum(tbItem.getNum()+num); // String json = JsonUtils.objectToJson(tbItem); jedisClient.hset(UserConfig.CART_REDIS_PRE+userid, itemid+"", json); }else { TbItem tbItem = itemMapper.selectByPrimaryKey(itemid); tbItem.setNum(num); String images = tbItem.getImage(); if (StringUtils.isNotBlank(images)) { tbItem.setImage(images.split(",")[0]); } jedisClient.hset(UserConfig.CART_REDIS_PRE+userid, itemid+"", JsonUtils.objectToJson(tbItem)); } return E3Result.ok(); } //獲取購物車 @Override public List<TbItem> getCart(Long userid) { //經過hashkey獲取hash全部的值(不包含field) List<String> list = jedisClient.hvals(UserConfig.CART_REDIS_PRE+userid); List<TbItem> tbItems = new ArrayList<TbItem>(); //遍歷list,將list中的json數據轉爲tbItems對象 for (String string : list) { TbItem tbItem = JsonUtils.jsonToPojo(string, TbItem.class); tbItems.add(tbItem); } return tbItems; } // 更新購物車的num數量 @Override public E3Result updateCartNum(Long userid, Long itemid, int num) { //經過key獲取json String hget = jedisClient.hget(UserConfig.CART_REDIS_PRE+userid, itemid+""); //把json轉化爲tbitem對象 TbItem tbItem = JsonUtils.jsonToPojo(hget, TbItem.class); //把新的num設置到對象中 tbItem.setNum(num); jedisClient.hset(UserConfig.CART_REDIS_PRE+userid, itemid+"", JsonUtils.objectToJson(tbItem)); return E3Result.ok(); } // 根據itemid刪除購物車 @Override public E3Result deleteCartByItemId(Long userid, Long itemid) { //直接刪除hashkey的field jedisClient.hdel(UserConfig.CART_REDIS_PRE+userid, itemid+""); return E3Result.ok(); } }
controller層:
CartController .java數據庫
package cn.tsu.cart.e3mall.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.ResponseBody; import org.springframework.web.servlet.ModelAndView; import cn.tsu.cart.e3mall.service.CartService; import cn.tsu.e3mall.pojo.TbItem; import cn.tsu.e3mall.pojo.TbUser; import cn.tsu.e3mall.utils.E3Result; /** * 購物車處理 * @author xiaofeng * */ @Controller public class CartController { @Autowired private CartService cartService; //添加購物車 @RequestMapping("/cart/add/{productid}") //@PathVariable表示須要從url取值 public String AddCart(@PathVariable Long productid,Integer num, HttpServletRequest request,HttpServletResponse response) { //tbUser是loginInterceptor攔截器最後放行的時候set進去的 TbUser tbUser = (TbUser) request.getAttribute("tbUser"); //調用service方法進行添加購物車 if (tbUser !=null) { E3Result e3Result = cartService.addCart(tbUser.getId(), productid, num); } return "cartSuccess"; } //跳轉到購物車頁面 @RequestMapping("/cart/cart") public String ToCart(Model model,HttpServletRequest request) { TbUser user = (TbUser) request.getAttribute("tbUser"); List<TbItem> cartList = cartService.getCart(user.getId()); model.addAttribute("cartList", cartList); return "cart"; } //修改購物車中的商品數量 @RequestMapping("/cart/update/num/{itemid}/{num}") @ResponseBody public E3Result updateCartNum(@PathVariable Long itemid ,@PathVariable Integer num,HttpServletRequest request) { TbUser tbuser = (TbUser) request.getAttribute("tbUser"); E3Result e3Result = cartService.updateCartNum(tbuser.getId(), itemid, num); return e3Result; } //根據itemid刪除redis中的購物車商品 @RequestMapping("cart/delete/{itemid}") public String deleteCartByItemId(@PathVariable Long itemid,HttpServletRequest request) { TbUser tbUser = (TbUser) request.getAttribute("tbUser"); E3Result e3Result = cartService.deleteCartByItemId(tbUser.getId(), itemid); return "redirect:/cart/cart.html"; } }
用戶點擊-,和用戶直接修改數據相似。
cart.js文件apache
var CART = { itemNumChange : function(){ $(".increment").click(function(){//+ var _thisInput = $(this).siblings("input"); _thisInput.val(eval(_thisInput.val()) + 1); $.post("/cart/update/num/"+_thisInput.attr("itemId")+"/"+_thisInput.val() + ".action",function(data){ CART.refreshTotalPrice(); }); //從新計算小計 var htmlvale = $(_thisInput).parent().parent().siblings(".pSubtotal").find("span"); var value =(eval(_thisInput.attr("itemPrice")))*_thisInput.val(); htmlvale.html(new Number(value/100).toFixed(2)).priceFormat({ //價格格式化插件 prefix: '¥', thousandsSeparator: ',', centsLimit: 2 }); }); $(".decrement").click(function(){//- var _thisInput = $(this).siblings("input"); if(eval(_thisInput.val()) == 1){ return ; } _thisInput.val(eval(_thisInput.val()) - 1); $.post("/cart/update/num/"+_thisInput.attr("itemId")+"/"+_thisInput.val() + ".action",function(data){ CART.refreshTotalPrice(); }); //從新計算小計 var htmlvale = $(_thisInput).parent().parent().siblings(".pSubtotal").find("span"); var value =(eval(_thisInput.attr("itemPrice")))*_thisInput.val(); htmlvale.html(new Number(value/100).toFixed(2)).priceFormat({ //價格格式化插件 prefix: '¥', thousandsSeparator: ',', centsLimit: 2 }); }); $(".itemnum").change(function(){ var _thisInput = $(this); $.post("/cart/update/num/"+_thisInput.attr("itemId")+"/"+_thisInput.val() + ".action",function(data){ CART.refreshTotalPrice(); }); //從新計算小計 var htmlvale = $(_thisInput).parent().parent().siblings(".pSubtotal").find("span"); var value =(eval(_thisInput.attr("itemPrice")))*_thisInput.val(); htmlvale.html(new Number(value/100).toFixed(2)).priceFormat({ //價格格式化插件 prefix: '¥', thousandsSeparator: ',', centsLimit: 2 }); }); }, refreshTotalPrice : function(){ //從新計算總價 var total = 0; $(".itemnum").each(function(i,e){ var _this = $(e); total += (eval(_this.attr("itemPrice")) * 10000 * eval(_this.val())) / 10000; }); $("#allMoney2").html(new Number(total/100).toFixed(2)).priceFormat({ //價格格式化插件 prefix: '¥', thousandsSeparator: ',', centsLimit: 2 }); } }; $(function(){ CART.itemNumChange(); });