第11章-购物车.md 26 KB

第11章-购物车

学习目标:

  • 能够说出购物车业务需求
  • 搭建购物车模块
  • 完成新增购物车功能
  • 完成购物车合并功能
  • 完成购物车商品选中删除购物车功能

1、购物车业务简介

img

购物车模块要能过存储顾客所选的的商品,记录下所选商品,还要能随时更新,当用户决定购买时,用户可以选择决定购买的商品进入结算页面。

功能要求:

1) 利用缓存提高性能。

2) 未登录状态也可以存入购物车,一旦用户登录要进行合并操作。

2、购物车模块搭建

购物车添加展示流程:

img

2.1 搭建service-cart服务

选中gmall-service父工程,创建子模块:service-cart 。搭建方式如service-item

2.2 配置pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>gmall-service</artifactId>
        <groupId>com.atguigu.gmall</groupId>
        <version>1.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-cart</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.atguigu.gmall</groupId>
            <artifactId>service-product-client</artifactId>
            <version>1.0</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>service-cart</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2.3 启动类

package com.atguigu.gmall;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class CartApp {
    public static void main(String[] args) {
        SpringApplication.run(CartApp.class, args);
    }
}

2.3 添加配置文件

在resources目录下创建:bootstrap.properties

spring.application.name=service-cart
spring.profiles.active=dev
spring.cloud.nacos.discovery.server-addr=192.168.200.128:8848
spring.cloud.nacos.config.server-addr=192.168.200.128:8848
spring.cloud.nacos.config.prefix=${spring.application.name}
spring.cloud.nacos.config.file-extension=yaml
spring.cloud.nacos.config.shared-configs[0].data-id=common.yaml

3、功能—添加入购物车

3.1 功能解析:

1、 商品详情页添加购物车

2、 添加购物车,用户可以不需要登录,如果用户没有登录,则生成临时用户id,购物车商品与临时用户id关联,当用户登录后,将临时用户id的购物车商品与登录用户id的商品合并

3、 商品详情添加购物车时,先判断用户是否登录,如果没登录,再判断是否存在临时用户,如果cookie中也没有临时用户,则生成临时用户

3.2 处理临时用户

3.2.1 商品详情页

商品详情添加购物车页面方法(/item/index.html):

addToCart() {
    // 判断是否登录和是否存在临时用户,如果都没有,添加临时用户
    if(!auth.isTokenExist() && !auth.isUserTempIdExist()) {
        auth.setUserTempId()
    }
    window.location.href = 'http://cart.gmall.com/addCart.html?skuId=' + this.skuId + '&skuNum=' + this.skuNum
}

3.2.2 服务网关处理

思路:既然userId是从服务网关统一传递过来的,那么临时用户id我们也可以从网关传递过来,改造网关

网关中获取临时用户id

gmall-gateway 项目中过滤器AuthGlobalFilter添加

/**
 * 尝试获取临时用户ID
 *
 * @param request
 * @return
 */
private String getUserTempId(ServerHttpRequest request) {
    String userTempId = "";

    //1.尝试从cookie中获取
    List<HttpCookie> cookieList = request.getCookies().get("userTempId");
    if (!CollectionUtils.isEmpty(cookieList)) {
        userTempId = cookieList.get(0).getValue();
        return userTempId;
    }

    //2.尝试从请求头中获取
    userTempId = request.getHeaders().getFirst("userTempId");
    if(StringUtils.isNotBlank(userTempId)){
        return userTempId;
    }
    return userTempId;
}

将userTempId 添加header请求头

 //5.将获取到用户ID设置到请求头中,将用户ID传输到目标微服务
if (StringUtils.isNotBlank(userId)) {
    request.mutate().header("userId", userId);
}
//将获取到临时用户ID设置到请求头
String userTempId = getUserTempId(request);
if (StringUtils.isNotBlank(userTempId)) {
    request.mutate().header("userTempId", userTempId);
}

AuthContextHolder类添加公共方法

package com.atguigu.gmall.common.util;


import javax.servlet.http.HttpServletRequest;


 /**
 * @author: atguigu
 * @create: 2023-01-11 10:31
 */
public class AuthContextHolder {


    /**
     * 从请求对象中获取用户ID
     *
     * @return
     */
    public static String getUserId(HttpServletRequest request) {
        String userId = request.getHeader("userId");
        return org.apache.commons.lang.StringUtils.isNotBlank(userId) ? userId : "";
    }


    /**
     * 从请求对象中获取临时用户ID
     *
     * @return
     */
    public static String getUserTempId(HttpServletRequest request) {
        String userTempId = request.getHeader("userTempId");
        return org.apache.commons.lang.StringUtils.isNotBlank(userTempId) ? userTempId : "";
    }
}

3.3 功能开发:

YAPI接口地址:http://192.168.200.128:3000/project/11/interface/api/683

3.3.1 创建实体

package com.atguigu.gmall.model.cart;

import com.atguigu.gmall.model.activity.CouponInfo;
import com.atguigu.gmall.model.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;

@Data
@ApiModel(description = "购物车")
//@TableName("cart_info")
public class CartInfo extends BaseEntity {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "用户id")
    private String userId;

    @ApiModelProperty(value = "skuid")
    private Long skuId;

    @ApiModelProperty(value = "放入购物车时价格")
    private BigDecimal cartPrice;  // 1999

    @ApiModelProperty(value = "数量")
    private Integer skuNum;

    @ApiModelProperty(value = "图片文件")
    private String imgUrl;
    //  根据skuId ---> skuInfo 找名称, 减少关联查询,提供检索效率.
    @ApiModelProperty(value = "sku名称 (冗余)")
    private String skuName;

    //  选择状态 默认 1 = 选中  0 = 未选中
    @ApiModelProperty(value = "isChecked")
    private Integer isChecked = 1;

    // 实时价格 skuInfo.price
    BigDecimal skuPrice;  // 元旦 1888 | 提示 比加入时,降价了,还是涨价了

    //  优惠券信息列表
    @ApiModelProperty(value = "购物项对应的优惠券信息")
    @TableField(exist = false)
    private List<CouponInfo> couponInfoList;

}

3.3.2 添加购物车控制器

YAPI接口文档:http://192.168.200.128:3000/project/11/interface/api/683

package com.atguigu.gmall.controller;

import com.atguigu.gmall.service.CartService;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.util.AuthContextHolder;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * @author: atguigu
 * @create: 2023-01-11 10:46
 */
@RestController
@RequestMapping("/api/cart")
public class CarApiController {


    @Autowired
    private CartService cartService;


    /**
     * 用户将商品加入到购物车
     *
     * @param skuId  商品SKUID
     * @param skuNum 商品加购的数量
     * @return
     */
    @GetMapping("/addToCart/{skuId}/{skuNum}")
    public Result addToCart(HttpServletRequest request, @PathVariable("skuId") Long skuId, @PathVariable("skuNum") Integer skuNum) {
        //声明用户ID遍历:可能是登录用户ID也可能是临时用户ID
        String userId = "";
        userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isBlank(userId)) {
            userId = AuthContextHolder.getUserTempId(request);
        }
        cartService.addToCart(userId, skuId, skuNum);
        return Result.ok();
    }
}

3.3.3 业务接口

package com.atguigu.gmall.service;

public interface CartService {
    /**
     * 用户将商品加入到购物车
     *
     * @param userId 用户ID
     * @param skuId 商品SKUID
     * @param skuNum 商品加购的数量
     * @return
     */
    void addToCart(String userId, Long skuId, Integer skuNum);
}

3.3.4 业务实现类

定义业务需要使用的常量,RedisConst类

public static final String USER_KEY_PREFIX = "user:";
public static final String USER_CART_KEY_SUFFIX = ":cart";
public static final long USER_CART_EXPIRE = 60 * 60 * 24 * 30;
package com.atguigu.gmall.service.impl;

import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.service.CartService;
import com.atguigu.gmall.cart.model.CartInfo;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.atguigu.gmall.product.model.SkuInfo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author: atguigu
 * @create: 2023-01-11 10:47
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

 /**
 * 用户将商品加入到购物车-存储到Redis
 *
 * @param userId
 * @param skuId  商品SKUID
 * @param skuNum 商品加购的数量
 * @return
 */
@Override
public void addToCart(String userId, Long skuId, Integer skuNum) {
    //1.构建购物车结构 redisKey 包含登录用户ID或者临时用户ID
    //1.1 登录用户ID作为 形式:user:1:cart
    String redisKey = getCartKey(userId);
    //1.2 创建hash操作对象 - 决定操作数据都是传入用户购物车数据
    //BoundHashOperations<redisKey类型,hashKey类型,hashValue类型>
    BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(redisKey);

    //2.参数中skuID作为hashKey 标识商品  注意:hashKey类型必须是字符串
    String hashKey = skuId.toString();

    //3.构建hashVal 将商品信息+数量
    //3.1 远程调用商品微服务获取商品信息
    SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
    if (skuInfo != null) {
        CartInfo cartInfo = null;
        if (hashOps.hasKey(skuId.toString())) {
            cartInfo = hashOps.get(skuId.toString());
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
        } else {
            //3.2 封装商品购物车对象
            cartInfo = new CartInfo();
            cartInfo.setSkuId(skuId);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setIsChecked(1);
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());
            cartInfo.setUserId(userId);
            cartInfo.setCartPrice(productFeignClient.getSkuPrice(skuId));
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
        }
        //3.3 将数据存入Redis
        //redisTemplate.opsForHash().put(redisKey, hashKey, cartInfo);
        hashOps.put(hashKey, cartInfo);
    }
}


    /**
     * 获取用户对应hash操作的Key
     *
     * @param userId 用户ID
     * @return
     */
    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }
}

4、功能—展示购物车列表

YAPI接口地址:http://192.168.200.128:3000/project/11/interface/api/675

4.1 功能解析

4.2 控制器:CartApiController

/**
 * 查询用户购物车列表
 * 版本1:分别查询未登录购物车列表,以及登录的购物车列表
 * 版本2:将两个购物车中商品合并
 * @param request
 * @return
 */
@GetMapping("/cartList")
public Result<List<CartInfo>> cartList(HttpServletRequest request){
    //获取登录用户ID
    String userId = AuthContextHolder.getUserId(request);
    //获取临时用户ID
    String userTempId = AuthContextHolder.getUserTempId(request);
    List<CartInfo> cartInfoList = cartService.cartList(userId, userTempId);
    return Result.ok(cartInfoList);
}

4.3 购物车列表接口:CartService

/**
 * 查询用户购物车列表
 * 版本1:分别查询未登录购物车列表,以及登录的购物车列表
 * 版本2:将两个购物车中商品合并
 * @return
 */
List<CartInfo> cartList(String userId, String userTempId);

4.4 实现类:CartServiceImpl

/**
 * 查询用户购物车列表
 * 版本1:分别查询未登录购物车列表,以及登录的购物车列表
 * 版本2:将两个购物车中商品合并
 *
 * @return
 */
@Override
public List<CartInfo> cartList(String userId, String userTempId) {
    //1.查询未登录购物车列表
    List<CartInfo> cartInfoList = null;
    //1.1 判断临时用户有值情况下 redis中获取购物车列表
    if (StringUtils.isNotBlank(userTempId)) {
        //1.2 构建redisKey 创建hash操作对象
        String noLogCartKey = getCartKey(userTempId);
        BoundHashOperations<String, String, CartInfo> noLoginHashOps = redisTemplate.boundHashOps(noLogCartKey);
        cartInfoList = noLoginHashOps.values();
    }

    //3.已登录的购物车列表
    //3.1 判断用户有值情况下 redis中获取购物车列表
    if (StringUtils.isNotBlank(userId)) {
        //3.2 构建redisKey 创建hash操作对象
        String loginCartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> loginHashOps = redisTemplate.boundHashOps(loginCartKey);
        cartInfoList = loginHashOps.values();
    }

    //4.对购物车商品数据进行排序
    cartInfoList.sort((o1, o2) -> {
        return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
    });
    return cartInfoList;
}

5、功能--合并购物车

功能分析:

  1. 当用户登录以后,先判断未登录的时候,用户是否购买了商品。

    • 如果用户购买了商品,则找到对应的商品Id,对数量进行合并

    • 没有找到的商品,则直接添加到数据

  2. 合并完成之后,删除未登录数据。

5.1 更改实现类:CartServiceImpl

/**
 * 查询用户购物车列表
 * 版本2:将两个购物车中商品合并
 * 未登录(没有加购商品,加购商品) 登录(没有加购商品,加购商品)
 * 情况一:(临时用户)用户未登录:加入商品到购物车  用户没登录 返回临时用户加购商品列表
 * 情况二:(临时用户)用户未登录:加入商品到购物车-->用户登录  需要进行合并,删除未登录购物车列表
 *
 * @return
 */
@Override
public List<CartInfo> cartList(String userId, String userTempId) {
    //1.(临时用户)用户未登录:加入商品到购物车  用户没登录 返回临时用户加购商品列表
    List<CartInfo> noLoginCartList = null;
    if (StringUtils.isNotBlank(userTempId)) {
        //1.1 构建未登录用户redisKey
        String noLoginCartKey = getCartKey(userTempId);

        //1.2 获取未登录购物车列表
        BoundHashOperations<String, String, CartInfo> noLoginHashOps = redisTemplate.boundHashOps(noLoginCartKey);
        noLoginCartList = noLoginHashOps.values();
    }
    if (StringUtils.isBlank(userId)) {
        noLoginCartList.sort((o1, o2) -> {
            return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
        });
        return noLoginCartList;
    }

    //2.如果未登录购物车列表中有数据,则需要跟已登录购物车列表进行合并--说明登录了
    //2.1 构建已登录购物车KEY
    String loginCartKey = getCartKey(userId);
    //2.2 构建已登录购物车hash操作对象
    BoundHashOperations<String, String, CartInfo> loginHashOps = redisTemplate.boundHashOps(loginCartKey);

    if (!CollectionUtils.isEmpty(noLoginCartList)) {
        for (CartInfo cartInfo : noLoginCartList) {
            //2.3 判断如果登录购物车中包含商品SKUID 则累加数量  反之则新增
            if (loginHashOps.hasKey(cartInfo.getSkuId().toString())) {
                CartInfo loginCartInfo = loginHashOps.get(cartInfo.getSkuId().toString());
                //将离线购物车商品数量跟在线购物车商品数量累加
                loginCartInfo.setSkuNum(loginCartInfo.getSkuNum() + cartInfo.getSkuNum());
                //更新登录购物车数据
                loginHashOps.put(cartInfo.getSkuId().toString(), loginCartInfo);
            } else {
                //2.4 如果未登录购物车中商品在已登录购物车中不存在新增
                cartInfo.setUserId(userId);
                cartInfo.setUpdateTime(new Date());
                loginHashOps.put(cartInfo.getSkuId().toString(), cartInfo);
            }
        }

        //3. 删除未登录购物车数据
        String noLoginCartKey = getCartKey(userTempId);
        redisTemplate.delete(noLoginCartKey);
    }

    //4.再次查询登录后用户购物车列表
    List<CartInfo> allCartInfoList = loginHashOps.values();
    //4.对购物车商品数据进行排序
    allCartInfoList.sort((o1, o2) -> {
        return DateUtil.truncatedCompareTo(o2.getUpdateTime(), o1.getUpdateTime(), Calendar.SECOND);
    });
    return allCartInfoList;
}

6、选中状态的变更

用户每次勾选购物车的多选框,都要把当前状态保存起来。由于可能会涉及更频繁的操作,所以这个勾选状态不必存储到数据库中。保留在缓存状态即可。

YAPI接口地址:http://192.168.200.128:3000/project/11/interface/api/667

6.1 编写控制器

CartApiController

//  选中状态
@GetMapping("checkCart/{skuId}/{isChecked}")
public Result checkCart(@PathVariable Long skuId,
                        @PathVariable Integer isChecked,
                        HttpServletRequest request){

    String userId = AuthContextHolder.getUserId(request);
    //  判断
    if (StringUtils.isEmpty(userId)){
        userId = AuthContextHolder.getUserTempId(request);
    }
    //  调用服务层方法
    cartService.checkCart(userId,isChecked,skuId);
    return Result.ok();
}

6.2 编写业务接口与实现

业务接口CartService

/**
 * 更新选中状态
 *
 * @param userId
 * @param isChecked
 * @param skuId
 */
void checkCart(String userId, Integer isChecked, Long skuId);

业务实现类CartServiceImpl

/**
 * 变更购物车商品选中状态
 *
 * @param skuId     商品SKUID
 * @param isChecked 状态
 * @return
 */
@Override
public void checkCart(String userId, Long skuId, Integer isChecked) {
    //获取用户购物车Key
    String cartKey = getCartKey(userId);
    //获取hash操作对象
    BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
    if (hashOps.hasKey(skuId.toString())) {
        //获取商品信息
        CartInfo cartInfo = hashOps.get(skuId.toString());
        //修改状态
        cartInfo.setIsChecked(isChecked);
        //更新购物车商品
        hashOps.put(skuId.toString(), cartInfo);
    }
}

7、删除购物车

YAPI接口地址:http://192.168.200.128:3000/project/11/interface/api/659

7.1 编写控制器

/**
 * 删除
 *
 * @param skuId
 * @param request
 * @return
 */
@DeleteMapping("deleteCart/{skuId}")
public Result deleteCart(@PathVariable("skuId") Long skuId,
                         HttpServletRequest request) {
    // 如何获取userId
    String userId = AuthContextHolder.getUserId(request);
    if (StringUtils.isEmpty(userId)) {
        // 获取临时用户Id
        userId = AuthContextHolder.getUserTempId(request);
    }
    cartService.deleteCart(skuId, userId);
    return Result.ok();
}

7.1 封装业务接口与实现

业务接口CartService

/**
 * 删除购物车商品
 * @param skuId
 * @param userId
 */
void deleteCart(Long skuId, String userId);

业务实现类:CartServiceImpl

/**
 * 删除购物车商品
 * @param userId
 * @param skuId
 */
@Override
public void deleteCart(String userId, Long skuId) {
    //获取用户购物车Key
    String cartKey = getCartKey(userId);
    //获取hash操作对象
    BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
    //删除购物车商品
    hashOps.delete(skuId.toString());
}

8、前端实现

8.1 在web-all添加前端实现

8.1.1 网关动态路由

在Nacos配置列表找找到server-gateway-dev.yaml进行修改:配置购物车域名以及购物车服务的动态路由

- id: web-cart
  uri: lb://web-all
  predicates:
  - Host=cart.gmall.com
- id: service-cart
  uri: lb://service-cart
  predicates:
  - Path=/*/cart/**

8.1.3 购物车Feign接口

  1. service-client模块下创建购物车feign模块:service-cart-client

image-20221207190600598

  1. 在:service-cart-client创建获取购物车Feign远程调用API接口CartFeignClient

    package com.atguigu.gmall.cart.client;
       
    import com.atguigu.gmall.cart.client.impl.CartDegradeFeignClient;
    import com.atguigu.gmall.cart.model.CartInfo;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
       
    import java.util.List;
       
    /**
    * author:atguigu
    * 描述:
    **/
    @FeignClient(value = "service-cart",fallback = CartDegradeFeignClient.class)
    public interface CartFeignClient {
       //  根据用户Id 获取到选中购物车列表。
       @GetMapping("api/cart/getCartCheckedList/{userId}")
       List<CartInfo> getCartCheckedList(@PathVariable String userId);
    }
       
    
  2. 服务降级类

    package com.atguigu.gmall.cart.client.impl;
       
    import com.atguigu.gmall.cart.client.CartFeignClient;
    import com.atguigu.gmall.cart.model.CartInfo;
    import org.springframework.stereotype.Component;
       
    import java.util.List;
       
    /**
    * author:atguigu
    * date:2022/11/23 9:35
    * 描述:
    **/
    @Component
    public class CartDegradeFeignClient implements CartFeignClient {
       @Override
       public List<CartInfo> getCartCheckedList(String userId) {
           return null;
       }
    }
    

8.1.2 controller实现

  1. web-all模块pom.xml中导入依赖

    <dependency>
       <groupId>com.atguigu.gmall</groupId>
       <artifactId>service-cart-client</artifactId>
       <version>1.0</version>
    </dependency>
    
  2. 新增CartController

    package com.atguigu.gmall.all.controller;
       
    import com.atguigu.gmall.cart.client.CartFeignClient;
    import com.atguigu.gmall.product.model.SkuInfo;
    import com.atguigu.gmall.product.client.ProductFeignClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
       
    import javax.servlet.http.HttpServletRequest;
       
    /**
    * <p>
    * 购物车页面
    * </p>
    *
    */
    @Controller
    public class CartController {
       
       @Autowired
       private CartFeignClient cartFeignClient;
       
       @Autowired
       private ProductFeignClient productFeignClient;
       
       /**
        * 查看购物车
        * @return
        */
       @RequestMapping("cart.html")
       public String index(){
           return "cart/index";
       }
       
       /**
        * 添加购物车
        * @param skuId
        * @param skuNum
        * @param request
        * @return
        */
       @RequestMapping("addCart.html")
       public String addCart(@RequestParam(name = "skuId") Long skuId,
                             @RequestParam(name = "skuNum") Integer skuNum,
                             HttpServletRequest request){
           SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
           request.setAttribute("skuInfo",skuInfo);
           request.setAttribute("skuNum",skuNum);
           return "cart/addCart";
       }
    }