尚品汇-添加购物车实现(三十六)

目录:

(1)购物车业务简介

(2)购物车模块搭建

(3)搭建service-cart服务

(4)功能—添加入购物车

(5)添加购物车功能开发

(1)购物车业务简介

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

  功能要求:

  1. 利用缓存提高性能。
  2. 未登录状态也可以存入购物车,一旦用户登录要进行合并操作。

流程分析:

(2)购物车模块搭建

购物车添加展示流程:

(3)搭建service-cart服务

修改配置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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>com.atguigu.gmall</groupId>
      <artifactId>service</artifactId>
      <version>1.0</version>
   </parent>

   <version>1.0</version>
   <artifactId>service-cart</artifactId>
   <packaging>jar</packaging>
   <name>service-cart</name>
   <description>service-cart</description>

<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>

 添加配置文件bootstrap.properties

spring.application.name=service-cart
spring.profiles.active=dev
spring.cloud.nacos.discovery.server-addr=192.168.200.129:8848
spring.cloud.nacos.config.server-addr=192.168.200.129: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

启动类

package com.atguigu.gmall.cart;

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

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan(basePackages = "com.atguigu.gmall")
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.atguigu.gmall")
public class ServiceCartApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceCartApplication.class,args);
    }
}

(4)功能—添加入购物车

功能解析:

  1. 商品详情页添加购物车
  2. 添加购物车,用户可以不需要登录,如果用户没有登录,则生成临时用户id,购物车商品与临时用户id关联,当用户登录后,将临时用户id的购物车商品与登录用户id的商品合并
  3. 商品详情添加购物车时,先判断用户是否登录,如果没登录,再判断是否存在临时用户,如果cookie中也没有临时用户,则生成临时用户

商品详情页

商品详情添加购物车页面方法(/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

}

服务网关处理

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

网关中获取临时用户id

在server-gateway 项目中添加

/**
 * 获取当前用户临时用户id
 * @param request
 * @return
 */
private String getUserTempId(ServerHttpRequest request) {
    String userTempId = "";
    List<String> tokenList = request.getHeaders().get("userTempId");
    if(null  != tokenList) {
        userTempId = tokenList.get(0);
    } else {
        MultiValueMap<String, HttpCookie> cookieMultiValueMap =  request.getCookies();
        HttpCookie cookie = cookieMultiValueMap.getFirst("userTempId");
        if(cookie != null){
            userTempId = URLDecoder.decode(cookie.getValue());
        }
    }
    return userTempId;
}

设置网关请求头

String userTempId = this.getUserTempId(request);

if(!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)) {
    if(!StringUtils.isEmpty(userId)) {
        //存储到request作用域
        request.mutate().header("userId", userId).build();
    }
    if(!StringUtils.isEmpty(userTempId)) {
        //存储到request作用域
        request.mutate().header("userTempId", userTempId).build();
    }
    //将现在的request 变成 exchange对象
    return chain.filter(exchange.mutate().request(request).build());
}

这里的代码可以获取临时用户id 

(5)添加购物车功能开发

 

创建实体

@Data
@ApiModel(description = "购物车")
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;

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

    @ApiModelProperty(value = "图片文件")
    private String imgUrl;

    @ApiModelProperty(value = "sku名称 (冗余)")
    private String skuName;

    @ApiModelProperty(value = "isChecked")
    private Integer isChecked = 1;

    //实时价格 skuInfo.price
    BigDecimal skuPrice;

}

创建添加购物车接口

package com.atguigu.gmall.cart.service;

public interface CartService {
    // 添加购物车 用户Id,商品Id,商品数量。
    void addToCart(Long skuId, String userId, Integer skuNum);
}

定义业务需要使用的常量,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 = 30000;

添加购物车实现类 

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
public void addToCart(Long skuId, String userId, Integer skuNum) {
    //  获取缓存key
    String cartKey = getCartKey(userId);

    BoundHashOperations<String, String, CartInfo> boundHashOps = this.redisTemplate.boundHashOps(cartKey);
    CartInfo cartInfo = null;
    //包含的话更新数量
    if(boundHashOp
s.hasKey(skuId.toString())) {
        cartInfo = boundHashOps.get(skuId.toString());
        cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
        cartInfo.setIsChecked(1);
        cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
        cartInfo.setUpdateTime(new Date());
    } else {
        //购物车不存在数据,存入新的数据

        cartInfo = new CartInfo();
        //  给cartInfo 赋值! 远程请求sku详情数据
        SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);

        //  给表的字段赋值!
        cartInfo.setUserId(userId);
        cartInfo.setSkuId(skuId);
        cartInfo.setCartPrice(skuInfo.getPrice());
        cartInfo.setSkuNum(skuNum);
        cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
        cartInfo.setSkuName(skuInfo.getSkuName());
        cartInfo.setCreateTime(new Date());
        cartInfo.setUpdateTime(new Date());
        //实时价格
        cartInfo.setSkuPrice(skuInfo.getPrice());
    }

    //存储
    boundHashOps.put(skuId.toString(), cartInfo);
    
}




// 获取购物车的key
private String getCartKey(String userId) {
        //定义key user:userId:cart
        return RedisConst.USER_KEY_PREFIX + userId +       RedisConst.USER_CART_KEY_SUFFIX;
    }



}

添加购物车控制器

package com.atguigu.gmall.cart.controller;

@RestController
@RequestMapping("api/cart")
public class CartApiController {

    @Autowired
    private CartService cartService;

    /**
     * 添加购物车
     * @param skuId
     * @param skuNum
     * @param request
     * @return
     */
    @RequestMapping("addToCart/{skuId}/{skuNum}")
    public Result addToCart(@PathVariable("skuId") Long skuId,
                            @PathVariable("skuNum") Integer skuNum,
                            HttpServletRequest request) {
        // 如何获取userId
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)) {
            // 获取临时用户Id
            userId = AuthContextHolder.getUserTempId(request);
        }
        cartService.addToCart(skuId, userId, skuNum);
        return Result.ok();
    }
}

未登录添加购物车:Redis存的key中的用户id是临时id

登录后key中用户id存的是登录的用户的id

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵俺第一专栏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值