✅P241_商城业务-购物车-添加购物车

gong_yz大约 3 分钟谷粒商城

添加购物车

SkuInfoVo

cfmall-cart/src/main/java/com/gyz/cfmall/vo/SkuInfoVo.java

package com.gyz.cfmall.vo;

import lombok.Data;

import java.math.BigDecimal;

@Data
public class SkuInfoVo {

    private Long skuId;
    /**
     * spuId
     */
    private Long spuId;
    /**
     * sku名称
     */
    private String skuName;
    /**
     * sku介绍描述
     */
    private String skuDesc;
    /**
     * 所属分类id
     */
    private Long catalogId;
    /**
     * 品牌id
     */
    private Long brandId;
    /**
     * 默认图片
     */
    private String skuDefaultImg;
    /**
     * 标题
     */
    private String skuTitle;
    /**
     * 副标题
     */
    private String skuSubtitle;
    /**
     * 价格
     */
    private BigDecimal price;
    /**
     * 销量
     */
    private Long saleCount;

}

Controller

添加商品到购物车的请求方法

com.gyz.cfmall.controller.CartController#addCartItem

    @GetMapping("/addCartItem")
    public String addCartItem(@RequestParam("skuId") Long skuId,
                              @RequestParam("num") Integer num,
                              Model model){
        CartItemVo cartItemVo = cartService.addCartItem(skuId, num);
	    model.addAttribute("cartItem", cartItemVo);
        return "success";
    }

Service业务实现

cfmall-cart/src/main/java/com/gyz/cfmall/service/impl/CartServiceImpl.java

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private ThreadPoolExecutor executor;
    @Resource
    private ProductFeignService productFeignService;

    private final String CART_PREFIX = "cfmall:cart:";

	@Override
    public CartItemVo addCartItem(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        CartItemVo cartItemVo = new CartItemVo();

        CompletableFuture<Void> getSkuInfoFuture = CompletableFuture.runAsync(() -> {
            //1、远程查询当前要添加商品的信息
            R productSkuInfo = productFeignService.skuInfo(skuId);
            SkuInfoVo skuInfo = productSkuInfo.getData("skuInfo", new TypeReference<SkuInfoVo>() {
            });
            //数据赋值操作
            cartItemVo.setSkuId(skuInfo.getSkuId());
            cartItemVo.setTitle(skuInfo.getSkuTitle());
            cartItemVo.setImage(skuInfo.getSkuDefaultImg());
            cartItemVo.setPrice(skuInfo.getPrice());
            cartItemVo.setCount(num);
        }, executor);

        CompletableFuture<Void> getSkuSaleAttrFuture = CompletableFuture.runAsync(() -> {
            //2、获取销售属性
            List<String> skuSaleAttrValues = productFeignService.getSkuSaleAttrValues(skuId);
            cartItemVo.setSkuAttrValues(skuSaleAttrValues);
        }, executor);

        CompletableFuture.allOf(getSkuInfoFuture, getSkuSaleAttrFuture).get();

        BoundHashOperations<String, Object, Object> cartOpts = getCartOpts();
        String carItemInfo = JSON.toJSONString(cartItemVo);
        cartOpts.put(skuId.toString(), carItemInfo);
        return cartItemVo;
    }
}

Feign

cfmall-cart/src/main/java/com/gyz/cfmall/feign/ProductFeignService.java

    /**
     * 根据skuId查询查询销售属性,pms_sku_sale_attr_value表中的信息.
     *
     * @param skuId
     * @return
     */
    @GetMapping(value = "/product/skusaleattrvalue/stringList/{skuId}")
    List<String> getSkuSaleAttrValues(@PathVariable("skuId") Long skuId);

cfmall-product/src/main/java/com/gyz/cfmall/product/controller/SkuSaleAttrValueController.java

    @GetMapping(value = "/stringList/{skuId}")
    public List<String> getSkuSaleAttrValues(@PathVariable("skuId") Long skuId) {
        List<String> stringList = skuSaleAttrValueService.getSkuSaleAttrValuesAsStringList(skuId);
        return stringList;
    }

cfmall-product/src/main/java/com/gyz/cfmall/product/service/impl/SkuSaleAttrValueServiceImpl.java

    @Override
    public List<String> getSkuSaleAttrValuesAsStringList(Long skuId) {
        SkuSaleAttrValueDao baseMapper = this.baseMapper;
        List<String> stringList = baseMapper.getSkuSaleAttrValuesAsStringList(skuId);

        return stringList;
    }

cfmall-product/src/main/resources/mapper/product/SkuSaleAttrValueDao.xml

<select id="getSkuSaleAttrValuesAsStringList" resultType="java.lang.String">
    SELECT CONCAT(attr_name, ":", attr_value)
    FROM pms_sku_sale_attr_value
    WHERE sku_id = #{skuId}
</select>

异步编排

配置线程池

cfmall-cart/src/main/java/com/gyz/cfmall/config/ThreadPoolConfigProperties.java

package com.gyz.cfmall.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@ConfigurationProperties(prefix = "cfmall.thread")
@Data
@Component
public class ThreadPoolConfigProperties {
    /**
     * 核心线程数
     */
    private Integer corePoolSize;
    /**
     * 最大线程数
     */
    private Integer maxPoolSize;
    /**
     * 线程最大空闲时间
     */
    private Integer keepAliveTime;
}

cfmall-cart/src/main/java/com/gyz/cfmall/config/MyThreadPoolConfig.java

package com.gyz.cfmall.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Configuration
public class MyThreadPoolConfig {

    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties properties) {
        return new ThreadPoolExecutor(
                properties.getCorePoolSize(),
                properties.getMaxPoolSize(),
                properties.getKeepAliveTime(),
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }
}

application.properties

#配置线程池
cfmall.thread.corePoolSize=20
cfmall.thread.maxPoolSize=200
cfmall.thread.keepAliveTime=10

前端页面调整

商品详情界面

加入购物车为绑定单击事件,url改为**#**避免跳转并且设置id为超链接自定义属性,用于存储skuId

cfmall-product/src/main/resources/templates/item.html

<div class="box-btns-two">
    <a href="#" id="addToCart" th:attr="skuId=${item.skuInfo.skuId}">
        加入购物车
    </a> 
</div>

为文本框设置id:numInput

cfmall-product/src/main/resources/templates/item.html

<div class="box-btns clear">
    <div class="box-btns-one">
        <input type="text" name="" id="numInput" value="1"/>
        <div class="box-btns-one1">
            <div>
                <button id="jia">
                    +
                </button>
            </div>
	//代码省略...

编写单击事件

  • $(this):指当前实例;
  • return false : 禁止默认行为

cfmall-product/src/main/resources/templates/item.html

$("#addToCart").click(function () {
    var num = $("#numInput").val();
    var skuId = $(this).attr("skuId");
    location.href = "http://cart.cfmall.com/addCartItem?skuId=" + skuId + "&num=" + num;
    return false;
});

用户登录判断

cfmall-product/src/main/resources/templates/item.html

成功添加购物车页面

cfmall-cart/src/main/resources/templates/success.html

默认图片的显示

<div class="p-img">
    <a href="/static/cart/javascript:;" target="_blank"><img
            style="height: 60px;width:60px;" th:src="${cartItem.image}"></a>
</div>

商品详情页跳转以及标题显示

cfmall-cart/src/main/resources/templates/success.html

商品数量显示

cfmall-cart/src/main/resources/templates/success.html