Cookie及Redis在商城購物車系統(tǒng)中的使用

關(guān)于商城中購物車功能候学,天貓是必須登錄才能將商品加入到購物車歧寺,京東則可以在不登錄狀態(tài)下也可以加入購物車,這里就模仿京東購物車功能揣云。
購物車工程搭建:
e3-cart(pom)
|–e3-cart-interface(jar)
|-e3-cart-service(war)
e3-cart-web(war)
參照”redis實(shí)現(xiàn)單點(diǎn)登錄系統(tǒng)”搭建

需求:
商品詳情頁面如下:


image.png

選擇好商品捕儒,確定數(shù)量后,點(diǎn)擊“加入購物車”按鈕邓夕,發(fā)送請求刘莹。
請求地址:8090/cart/add/{itemId}.html,參數(shù):商品id跟商品數(shù)量
返回邏輯視圖:”cartSuccess”;

一、未登錄狀態(tài)下購物車功能實(shí)現(xiàn)

1焚刚、未登錄狀態(tài)下添加商品到購物車
在不登陸的情況下也可以添加購物車点弯。把購物車信息寫入cookie。
優(yōu)點(diǎn):
1矿咕、不占用服務(wù)端存儲空間
2抢肛、用戶體驗(yàn)好。
3碳柱、代碼實(shí)現(xiàn)簡單捡絮。
缺點(diǎn):
1、cookie中保存的容量有限莲镣。最大4k
2福稳、把購物車信息保存在cookie中,更換設(shè)備購物車信息不能同步瑞侮。

分析:頁面?zhèn)鱽淼氖巧唐穒d跟商品數(shù)量

(1) 從cookie中獲取商品列表信息(單獨(dú)提出來寫成個(gè)通用的方法)
(2) 遍歷購物車列表的圆,判斷需要添加的商品在購物車列表是否存在
(3) 商品存在的話,那么取出該商品原來的數(shù)量+添加的數(shù)量作為該商品現(xiàn)在的數(shù)量
(4) 如果商品不存在区岗,那么調(diào)用服務(wù)略板,根據(jù)傳來的商品id查詢商品數(shù)量,設(shè)置商品的數(shù)量為頁面?zhèn)鱽淼臄?shù)量慈缔,取商品的第一張圖片(購物車列表只展示一張圖片)叮称。
(5) 把修改后的購物車列表重新存入到cookie中
(6) 返回邏輯視圖”cartSuccess”

實(shí)現(xiàn):

在表現(xiàn)層工程e3-cart-web中引用商品服務(wù)工程提供的服務(wù)

<!-- 加載配置文件 -->
    <context:property-placeholder location="classpath:conf/resource.properties" />

    <context:component-scan base-package="cn.e3mall.cart.controller" />
    <mvc:annotation-driven />
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <!-- 引用dubbo服務(wù) -->
    <dubbo:application name="e3-cart-web"/>
    <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/>    
    <dubbo:reference interface="cn.e3mall.service.ItemService" id="itemService" />

ItemService提供了根據(jù)id獲取商品信息的方法:getItemById(Long itemId)

@Controller
public class CartController {

    @Autowired
    private ItemService itemService;

    @Value("${COOKIE_MAX_TIME}")
    private Integer COOKIE_MAX_TIME;

    /*
     * 1.未登錄狀態(tài)下添加購物車商品
     */
    @RequestMapping("/cart/add/{itemId}")
    public String addCartNum(@PathVariable Long itemId, Integer num,
                HttpServletRequest request,HttpServletResponse response){
        //獲取購物車列表
        List<TbItem> cartList = getCartListFromCookie(request);
        //判斷購物車中是否有該商品
        boolean flag = false;
        for (TbItem tbItem : cartList) {
        if(tbItem.getId()==itemId.longValue()){
                flag = true;
                //存在該商品,數(shù)量相加
                tbItem.setNum(tbItem.getNum()+num);
                //跳出循環(huán)
                break;
            }
        }
        if(!flag){
            //沒有的話,調(diào)用服務(wù)查詢該商品
            TbItem tbItem = itemService.getItemById(itemId);
            //設(shè)置數(shù)量
            tbItem.setNum(num);
            //取一張圖片
            String image = tbItem.getImage();
            if(StringUtils.isNotBlank(image)){
                tbItem.setImage(image.split(",")[0]);
            }
            //商品添加到購物車列表
            cartList.add(tbItem);
        }
        //購物車信息寫入cookie
        CookieUtils.setCookie(request, response, "cart1", 
                JsonUtils.objectToJson(cartList), COOKIE_MAX_TIME, true);
        //返回邏輯視圖
        return "cartSuccess";
    }
    /*
     *從cookie中獲取購物車列表
     */
    public List<TbItem> getCartListFromCookie(HttpServletRequest request){
        String string = CookieUtils.getCookieValue(request, "cart1", true);
        //判斷是否為空
        if(StringUtils.isBlank(string)){
            //空的話也不能返回null
            return new ArrayList<>();
        }
        //轉(zhuǎn)為商品列表
        List<TbItem> list = JsonUtils.jsonToList(string, TbItem.class);
        return list;
    }

}

其中商品實(shí)體類TbItem里面的屬性image存放的是多張照片。
COOKIE_MAX_TIME便是cookie中cart1最大存在時(shí)間瓤檐,true表示采用utf-8編碼
測試:


image.png

其實(shí)并不能看出來效果赂韵。展示購物車列表功能實(shí)現(xiàn)后就能看到了。

2挠蛉、展示購物車列表

單擊“去購物車結(jié)算按鈕”向服務(wù)端發(fā)送請求祭示,服務(wù)端應(yīng)該返回邏輯視圖”cart”
請求地址:8090/cart/cart.html
返回邏輯視圖:”cart”也就是購物車列表頁面

實(shí)現(xiàn):同樣是在CartController中添加

/*
     * 2.未登錄狀態(tài)下展示商品列表 
     */
    @RequestMapping("/cart/cart")
    public String showCartList(HttpServletRequest request){
        //獲取購物車列表
        List<TbItem> cartList = getCartListFromCookie(request);
        //綁定參數(shù)
        request.setAttribute("cartList", cartList);
        //返回邏輯視圖
        return "cart";
    }

注:cartList是根據(jù)cart.jsp的需要綁定的。該頁面拿到cartList后會進(jìn)行遍歷谴古,取各個(gè)商品的信息质涛。
測試:


image.png

3、為登錄狀態(tài)下購物車列表頁面修改商品數(shù)量

購物車列表頁面單擊”+”,”-”會向服務(wù)端發(fā)送ajax請求掰担。
頁面需要根據(jù)調(diào)整的數(shù)量重新顯示商品總計(jì)(已經(jīng)實(shí)現(xiàn)了也就是輸入框的值*價(jià)格)和小計(jì)(用js汇陆,待實(shí)現(xiàn))
服務(wù)端要求修改cookie中對應(yīng)商品的數(shù)量。
請求地址:/cart/update/num/{itemId}/{num}
參數(shù):商品id带饱,商品數(shù)量
返回結(jié)果:E3Result

/*
     * 未登錄狀態(tài)下更新商品數(shù)量
     */
    @RequestMapping("/cart/update/num/{itemId}/{num}")
    @ResponseBody
    public E3Result updateCartNum(@PathVariable Long itemId,@PathVariable Integer num, 
            HttpServletRequest request,HttpServletResponse response){
        //獲取購物車列表
        List<TbItem> cartList = getCartListFromCookie(request);
        //取所選擇的需要更新的商品
        for (TbItem tbItem : cartList) {
            if(tbItem.getId()==itemId.longValue()){
                //更新商品數(shù)量
                tbItem.setNum(num);
                //跳出循環(huán)
                break;
            }
        }
        //購物車信息寫入cookie
        CookieUtils.setCookie(request, response, "cart1", 
                JsonUtils.objectToJson(cartList), COOKIE_MAX_TIME, true);
        return E3Result.ok();
    }

測試:


image.png

注:商品總金額的js沒有去寫所以還是只顯示單價(jià)毡代。
E3Result為自定義響應(yīng)結(jié)構(gòu)

public class E3Result implements Serializable{
    // 定義jackson對象
    private static final ObjectMapper MAPPER = new ObjectMapper();
    // 響應(yīng)業(yè)務(wù)狀態(tài)
    private Integer status;
    // 響應(yīng)消息
    private String msg;
    // 響應(yīng)中的數(shù)據(jù)
    private Object data;
    public static E3Result build(Integer status, String msg, Object data) {
        return new E3Result(status, msg, data);
    }
    public static E3Result ok(Object data) {
        return new E3Result(data);
    }
    public static E3Result ok() {
        return new E3Result(null);
    }
    public E3Result() {
    }
    public static E3Result build(Integer status, String msg) {
        return new E3Result(status, msg, null);
    }
    public E3Result(Integer status, String msg, Object data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }
    public E3Result(Object data) {
        this.status = 200;
        this.msg = "OK";
        this.data = data;
    }
    get、set方法
   }

4勺疼、未登錄狀態(tài)下刪除購物車商品

請求地址:/cart/delete/{itemId}
請求參數(shù):商品id
響應(yīng):重定向到購物車列表教寂。

實(shí)現(xiàn):
(1)從cookie中獲取購物車列表
(2)遍歷,查找到要?jiǎng)h除的商品
(3)將該商品從購物車列表移除
(4)更新后的購物車列表重新寫入cookie
(5)重定向到購物車列表頁面

/*
     * 未登錄狀態(tài)下刪除購物車商品
     */
    @RequestMapping("/cart/delete/{itemId}")

    public String deleteCartById(@PathVariable Long itemId,
            HttpServletRequest request,HttpServletResponse response){
        //獲取商品列表
        List<TbItem> cartList = getCartListFromCookie(request);
        //遍歷商品列表执庐,找到該商品
        for (TbItem tbItem : cartList) {
            if(tbItem.getId() == itemId.longValue()){
                //刪除該商品
                cartList.remove(tbItem);
                break;
            }
        }
        //購物車信息寫入cookie
        CookieUtils.setCookie(request, response, "cart1", 
                JsonUtils.objectToJson(cartList), COOKIE_MAX_TIME, true);
        //重定向到列表頁面
        return "redirect:/cart/cart.html";
    }

測試:
上面的圖酪耕,點(diǎn)擊刪除后


image.png

二、登錄狀態(tài)下購物車功能的實(shí)現(xiàn)

功能分析:
1轨淌、購物車數(shù)據(jù)保存的位置:
未登錄狀態(tài)下因妇,把購物車數(shù)據(jù)保存到cookie中。
登錄狀態(tài)下猿诸,需要把購物車數(shù)據(jù)保存到服務(wù)端。需要永久保存狡忙,可以保存到數(shù)據(jù)庫中梳虽。可以把購物車數(shù)據(jù)保存到redis中灾茁。
2窜觉、redis使用的數(shù)據(jù)類型
a) 使用hash數(shù)據(jù)類型
b) Hash的key應(yīng)該是用戶id。Hash中的field是商品id北专,value可以是把商品信息轉(zhuǎn)換成json
3禀挫、添加購物車
登錄狀態(tài)下直接把商品數(shù)據(jù)保存到redis中。
未登錄狀態(tài)保存到cookie中拓颓。
4语婴、如何判斷是否登錄?
a) 從cookie中取token
b) 取不到未登錄
c) 取到token,到redis中查詢token是否過期砰左。
d) 如果過期匿醒,未登錄狀態(tài)
e) 沒過期登錄狀態(tài)。

1缠导、登錄攔截器

幾乎在購物車所有功能執(zhí)行 都要判斷用戶是否登錄廉羔。利用aop思想,應(yīng)該編寫個(gè)攔截器僻造,來判斷用戶是否登錄憋他。登錄的話用戶信息需要存在request域中
(1) 從cookie中取token
(2) 判斷token是否存在
(3) 不存在,說明用于未登錄髓削,放行
(4) 如果token存在竹挡,調(diào)用服務(wù),根據(jù)token從redis中取用戶信息
(5) 取不到用戶信息蔬螟,說明已經(jīng)過期此迅,放行
(6) 取到了用戶信息,說明用戶已經(jīng)登錄旧巾,用戶信息存到request中
(7) 放行
實(shí)現(xiàn):
首先需要在購物車系統(tǒng)表現(xiàn)層工程中(e3-cart-web)調(diào)用單點(diǎn)登錄系統(tǒng)(sso)的服務(wù)耸序,以及攔截器的配置。

<!-- 加載配置文件 -->
    <context:property-placeholder location="classpath:conf/resource.properties" />

    <context:component-scan base-package="cn.e3mall.cart.controller" />
    <mvc:annotation-driven />
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <!-- 攔截器配置 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="cn.e3mall.cart.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    <!-- 引用dubbo服務(wù) -->
    <dubbo:application name="e3-cart-web"/>
    <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/>    
    <dubbo:reference interface="cn.e3mall.service.ItemService" id="itemService" />
    <dubbo:reference interface="cn.e3mall.sso.service.TokenService" id="tokenService" />
/*
 * 用戶登錄處理
 */
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenService tokenService;

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //前處理,執(zhí)行handler之前執(zhí)行此方法
        //返回true:放行  false:攔截
        //1.從cookie中取token
        String token = CookieUtils.getCookieValue(request, "token");
        //2.如果沒有token鲁猩,未登錄狀態(tài)
        if(StringUtils.isBlank(token)){
            return true;
        }
        //3.如果取到token,需要調(diào)用sso系統(tǒng)的服務(wù)坎怪,根據(jù)token取用戶信息
        E3Result e3Result = tokenService.getUserByToken(token);
        if (e3Result.getStatus()!=200){
            //4.沒有取到用戶信息,登錄已經(jīng)過期,直接放行
            return true;
        }
        //5.取到用戶信息廓握。登錄狀態(tài)搅窿。
        TbUser user = (TbUser) e3Result.getData();
        //6.把用戶信息放到request中,只需要在controller中判斷request中是否包含user信息。
        request.setAttribute("user", user);
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        //handler執(zhí)行之后隙券,返回modelAndView之前
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        //完成處理男应,返回modelAndView之后(已經(jīng)響應(yīng)了)
        //可以再次處理異常
    }   
}

攔截器寫完之后,對于購物車功能只需要在表現(xiàn)層判斷用戶是否登錄娱仔,從而進(jìn)行不同的處理沐飘。

2、登錄狀態(tài)下牲迫,商品添加功能實(shí)現(xiàn)

(1)耐朴、服務(wù)層e3-cart-service中:
服務(wù)層用到了redis,所以需要將redis和spring整合盹憎。

<!-- 連接redis單機(jī)版 -->
    <bean id="jedisClientPool" class="cn.e3mall.common.jedis.JedisClientPool">
        <property name="jedisPool" ref="jedisPool"></property>
    </bean>
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
    <!-- 一定要用name筛峭,構(gòu)造方法太多用index容易錯(cuò) -->
        <constructor-arg name="host" value="192.168.25.128"/>
        <constructor-arg name="port" value="6379"/>
    </bean>

JedisClient只是自己對jedis操作redis的api的封裝。服務(wù)層當(dāng)然還得添加其他配置陪每,如組件掃描影晓,引入數(shù)據(jù)源镰吵,事務(wù)。

/*
 * 購物車處理服務(wù)
 */
@Service
public class CartServiceImpl implements CartService{

    @Autowired
    private JedisClient jedisClient;

    @Value("${REDIS_CART_PRE}")//屬性配置文件中俯艰,值為cart1
    private String REDIS_CART_PRE;

    @Autowired
    private TbItemMapper itemMapper;
    public E3Result addCart(Long userId, Long itemId, int num) {
        //向redis中添加購物車
        //數(shù)據(jù)類型是hash  key:用戶id   field:商品id  value:商品信息
        //判斷商品是否存在
        Boolean hexists = jedisClient.hexists(REDIS_CART_PRE+":"+userId, itemId+"");
        if(hexists){
            //如果存在,數(shù)量相加
            String json = jedisClient.hget(REDIS_CART_PRE+":"+userId, itemId+"");
            //把json轉(zhuǎn)換成TbItem
            TbItem tbItem = JsonUtils.jsonToPojo(json, TbItem.class);
            tbItem.setNum(tbItem.getNum()+num);
            //寫回redis
            jedisClient.hset(REDIS_CART_PRE+":"+userId, itemId+"",JsonUtils.objectToJson(tbItem));
            return E3Result.ok();
        }
        //如果不存在,根據(jù)商品id取商品信息,服務(wù)層盡量別相互調(diào)用
        TbItem item = itemMapper.selectByPrimaryKey(itemId);
        //設(shè)置購物車數(shù)量
        item.setNum(num);
        //取一張圖片
        String image = item.getImage();
        if(StringUtils.isNotBlank(image)){
            item.setImage(image.split(",")[0]);
        }
        //添加到購物車列表
        jedisClient.hset(REDIS_CART_PRE+":"+userId, itemId+"",JsonUtils.objectToJson(item));
        //返回成功
        return E3Result.ok();
    }
}

發(fā)布服務(wù):

<context:component-scan base-package="cn.e3mall.cart.service"/>

    <!-- 使用dubbo發(fā)布服務(wù) -->
    <!-- 提供方應(yīng)用信息捡遍,用于計(jì)算依賴關(guān)系 -->
    <dubbo:application name="e3-cart" />
    <dubbo:registry protocol="zookeeper"
        address="192.168.25.128:2181" />
    <!-- 用dubbo協(xié)議在20880端口暴露服務(wù) -->
    <dubbo:protocol name="dubbo" port="20884" /><!-- 一個(gè)服務(wù)對應(yīng)一個(gè)端口 -->
    <!-- 聲明需要暴露的服務(wù)接口 -->
    <dubbo:service interface="cn.e3mall.cart.service.CartService" ref="cartServiceImpl" timeout="600000"/>

(2)、表現(xiàn)層工程e3-cart-web中
調(diào)用e3-car-service剛發(fā)布的服務(wù)

<!-- 引用dubbo服務(wù) -->
    <dubbo:application name="e3-cart-web"/>
    <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/>    
    <dubbo:reference interface="cn.e3mall.service.ItemService" id="itemService" />
    <dubbo:reference interface="cn.e3mall.sso.service.TokenService" id="tokenService" />
    <dubbo:reference interface="cn.e3mall.cart.service.CartService" id="cartService" />

只需要再原來的添加商品功能中做判斷處理

@RequestMapping("/cart/add/{itemId}")
    public String addCart(@PathVariable Long itemId, @RequestParam(defaultValue="1") Integer num,
            HttpServletRequest request, HttpServletResponse response){
        //判斷用戶是否為登錄狀態(tài)
        TbUser user = (TbUser) request.getAttribute("user");
        if(user != null){
            //保存到服務(wù)端
            cartService.addCart(user.getId(), itemId, num);
            //返回邏輯視圖
            return "cartSuccess";
        }
        //如果是登錄狀態(tài),把購物車寫入redis
        //如果未登錄使用cookie
        ...未登錄狀態(tài)下代碼
    }

測試:
Tidy用戶登錄竹握,買了一個(gè)thinkpad電腦画株,單擊加入購物車


image.png

查看redis,商品信息已經(jīng)添加


image.png

2啦辐、登錄狀態(tài)下谓传,商品列表展示

分析:
(1)從cookie中取購物車列表
(2)判斷用戶是否登錄
(3)用戶已經(jīng)登錄的話,則調(diào)用服務(wù)層芹关,合并cookie中的列表和redis中的列表续挟。存入到redis中。
(4)同時(shí)刪除cookie中的購物車列表
(5)根據(jù)用戶id侥衬,調(diào)用服務(wù)查詢r(jià)edis中所有的商品诗祸,返回購物車列表。
(6)未登錄狀態(tài)還是跟前面一樣
(7)將列表綁定到參數(shù)轴总,返回購物車列表頁面直颅。
在服務(wù)層e3-cart-service中

/*
     * 合并購物車
     */
    public E3Result mergeCart(Long userId, List<TbItem> itemList) {
        //遍歷商品列表 
        //把列表添加到購物車
        //判斷購物車中是否有此商品
        //如果有,數(shù)量相加
        //如果沒有添加新的商品
        for (TbItem tbItem : itemList) {
            //等同于上面的添加商品到redis中
            addCart(userId, tbItem.getId(), tbItem.getNum());
        }
        return E3Result.ok();
    }
    /*
     * 取購物車列表
     */
    public List<TbItem> getCartList(long userId) {
        //根據(jù)用戶id查詢購物車列表
        List<String> jsonList = jedisClient.hvals(REDIS_CART_PRE+":"+userId);
        List<TbItem> itemList = new ArrayList<>();
        for (String string : jsonList) {
            //創(chuàng)建一個(gè)TbItem
            TbItem item = JsonUtils.jsonToPojo(string, TbItem.class);
            //添加到列表
            itemList.add(item);
        }
        return itemList;
    }

表現(xiàn)層工程 e3-cart-web中

/*
     * 展示購物車列表
     */
    @RequestMapping("/cart/cart")
    public String showCartList(HttpServletRequest request,HttpServletResponse response){
        //從cookie中取購物車列表
        List<TbItem> list = getCartListFromCookie(request);

        //判斷用戶是否為登錄狀態(tài)
        TbUser user = (TbUser) request.getAttribute("user");
        //如果是登錄狀態(tài)
        if(user!=null){
            //從cookie中取購物車列表
            //如果不為空怀樟,把cookie中的購物車商品和服務(wù)端的購物車商品合并功偿。
            cartService.mergeCart(user.getId(), list);
            //把cookie中的購物車刪除
            CookieUtils.deleteCookie(request, response, "cart");
            //從服務(wù)端取購物車列表
            list = cartService.getCartList(user.getId());

        }

        //未登錄狀態(tài) 
        //把列表傳遞給頁面
        request.setAttribute("cartList", list);
        //返回邏輯視圖
        return "cart";
    }

測試:
先不登錄狀態(tài)下添加商品都購物車,再登錄添加商品到購物車往堡。


image.png

再登錄tidy賬號(之前買了個(gè)電腦放入到了購物車)


image.png

發(fā)現(xiàn)已經(jīng)合并成功了械荷,再看cookie中
image.png

發(fā)現(xiàn)購物車已經(jīng)為空了。

也可以看下redis中虑灰,商品合并了


image.png

3吨瞎、登錄狀態(tài)下修改購物車商品數(shù)量

分析
單擊”+”,”-”修改商品的數(shù)量的時(shí)候,要求redis中該商品的數(shù)量發(fā)生改變
(1) 根據(jù)用戶id,商品id從redis中取出對應(yīng)的商品
(2) 設(shè)置商品的數(shù)量
(3) 該商品更新到redis中
(4) 返回E3Result
實(shí)現(xiàn):
服務(wù)層e3-cart-service中

/*
     * 登錄狀態(tài)下更新購物車數(shù)量
     */
    public E3Result updateCartNum(Long userId, Long itemId, int num) {
        //從redis中取商品信息
        String json = jedisClient.hget(REDIS_CART_PRE+":"+userId, itemId+"");
        //更新商品數(shù)量
        TbItem tbItem = JsonUtils.jsonToPojo(json, TbItem.class);
        tbItem.setNum(num);
        //寫入redis
        jedisClient.hset(REDIS_CART_PRE+":"+userId, itemId+"",JsonUtils.objectToJson(tbItem));
        return E3Result.ok();
    }

表現(xiàn)層工程e3-cart-web中

/*
     * 更新購物車商品數(shù)量
     */
    @RequestMapping("/cart/update/num/{itemId}/{num}")
    @ResponseBody
    public E3Result updateCartNum(@PathVariable Long itemId, @PathVariable Integer num,
                HttpServletRequest request, HttpServletResponse response){
        //判斷用戶是否為登錄狀態(tài)
        TbUser user = (TbUser) request.getAttribute("user");
        if (user != null){
            cartService.updateCartNum(user.getId(), itemId, num);
            return E3Result.ok();
        }

        //從cookie中取購物車列表
        List<TbItem> cartList = getCartListFromCookie(request);
        //遍歷商品列表找到對應(yīng)的商品
        for (TbItem tbItem : cartList) {
            //包裝類型直接==比的是內(nèi)存地址
            if(tbItem.getId() == itemId.longValue()){
                //跟新數(shù)量
                tbItem.setNum(num);
                break;
            }
        }
        //把購物車列表寫回cookie
        CookieUtils.setCookie(request, response, "cart", 
                JsonUtils.objectToJson(cartList), COOKIE_CART_EXPIRE, true);
        //返回成功
        return E3Result.ok();
    }

5穆咐、登錄狀態(tài)下关拒,刪除購物車商品

分析
單擊刪除的時(shí)候,刪除redis中該商品庸娱。重定向到列表頁面
(1) 直接用jedisClient的del的方法根據(jù)用戶id跟商品id 商品
(2) 返回成功

服務(wù)層e3-cart-service中

/*
     * 登錄狀態(tài)下刪除
     */
    public E3Result deleteCartItem(long userId, long itemId) {
        //刪除購物車商品
        jedisClient.hdel(REDIS_CART_PRE+":"+userId, itemId+"");
        return E3Result.ok();
    }

表現(xiàn)層工程e3-cart-web中
在原先的刪除方法中添加即可

/*
     * 從購物車刪除商品
     */
    @RequestMapping("/cart/delete/{itemId}")
    public String deleteCartItem(@PathVariable Long itemId,HttpServletRequest request,
            HttpServletResponse response){
        //判斷用戶是否為登錄狀態(tài)
        TbUser user = (TbUser) request.getAttribute("user");
        if (user != null){
            cartService.deleteCartItem(user.getId(), itemId);
            return "redirect:/cart/cart.html";
        }
        未登錄狀態(tài)下刪除購物車
        ...
    }

修改刪除測試:
初始情況


image.png

image.png

現(xiàn)在:刪除手機(jī),筆記本的數(shù)量改為2谐算,操作后頁面跟redis中如下


image.png

image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末熟尉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子洲脂,更是在濱河造成了極大的恐慌斤儿,老刑警劉巖剧包,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異往果,居然都是意外死亡疆液,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進(jìn)店門陕贮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堕油,“玉大人,你說我怎么就攤上這事肮之〉羧保” “怎么了?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵戈擒,是天一觀的道長眶明。 經(jīng)常有香客問我,道長筐高,這世上最難降的妖魔是什么搜囱? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮柑土,結(jié)果婚禮上蜀肘,老公的妹妹穿的比我還像新娘。我一直安慰自己冰单,他們只是感情好幌缝,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著诫欠,像睡著了一般涵卵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荒叼,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天轿偎,我揣著相機(jī)與錄音,去河邊找鬼被廓。 笑死坏晦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嫁乘。 我是一名探鬼主播昆婿,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蜓斧!你這毒婦竟也來了仓蛆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挎春,失蹤者是張志新(化名)和其女友劉穎看疙,沒想到半個(gè)月后豆拨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡能庆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年施禾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搁胆。...
    茶點(diǎn)故事閱讀 40,438評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡弥搞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出丰涉,到底是詐尸還是另有隱情拓巧,我是刑警寧澤,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布一死,位于F島的核電站肛度,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏投慈。R本人自食惡果不足惜承耿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伪煤。 院中可真熱鬧加袋,春花似錦、人聲如沸抱既。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽防泵。三九已至蚀之,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捷泞,已是汗流浹背足删。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锁右,地道東北人失受。 一個(gè)月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像咏瑟,于是被迫代替她去往敵國和親拂到。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內(nèi)容