购物车
一.配置购物车环境
1.点击 我的购物车
从商品的首页index.html,跳转到购物车的页面cartList.html
<img src="/static/index/img/img_15.png"/>
<span><a href="http://cart.gulimall.com/cart.html">我的购物车</a></span>
2.点击 加入购物车
从商品需求页面item.html,到购物车添加成功页面success.html
<a href="http://cart.gulimall.com/addCart">加入购物车</a>
3.点击 去购物车结算
从购物车添加成功页面success.html,到购物车列表cartList.html,即我的购物车
<a class="btn-addtocart" href="http://cart.gulimall.com/cart.html"id="GotoShoppingCart"><b></b>去购物车结算</a>
4.点击 查看商品详情
从购物车添加成功页面success.html,到商品详情页面item.html
<a class="btn-tobback" href="http://item.gulimall.com/11.html">查看商品详情</a>
5.点击 去结算
从购物车到结算界面
二. 业务操作
1.添加购物车
使用的技术,feign远程,线程池及异步编排CompletableFuture,redis。
逻辑:点击商品后,获取商品skuId,数量。根据skuId、数量获取商品信息
使用异步编排实现使用同一线程
1).controller
CartItem cartItem = cartService.addCart(skuId, num);
2).CartServiceImpl分3步(a、b、c)
a.远程查询当前要添加的商品信息。product
//1.远程查询当前要添加的商品信息。product的SkuInfo
R r = productFeignService.info(skuId);
SkuInfoVo data = r.getData("skuInfo", new TypeReference<SkuInfoVo>() {
});
b.商品信息添加到购物车
cartItem.setSkuId(skuId);
cartItem.setCheck(true);
cartItem.setImage(data.getSkuDefaultImg());
cartItem.setTitle(data.getSkuTitle());
cartItem.setPrice(data.getPrice());
cartItem.setCount(num);
c.远程查询属组合信息,product
//3.远程查询属组合信息.product的SkuSaleAttrValue
List<String> values = productFeignService.getSkuSaleAttrValues(skuId);
cartItem.setSkuAttr(values);
d.使用异步编排CompletableFuture,使得2个远程任务使用一个线程
e.所有任务完成,数据才放入redis
CompletableFuture.allOf(futureSkuInfo,futureSkuSaleAttrValues).get();
String s = JSON.toJSONString(cartItem);
cartOps.put(skuId.toString(),s);
f.获取操作的购物车(抽取的方法)
//获取 操作的购物车。
private BoundHashOperations<String, Object, Object> getCartOps() {
UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
String cartKey="";
if (userInfoTo.getUserId()!=null){
//登录成功。登录后,用户id不为空
cartKey= CartConstant.CART_PREFIX+userInfoTo.getUserId();
System.out.println("用户登录后的购物车key: "+cartKey);
}else {
//登录失败
cartKey=CartConstant.CART_PREFIX+userInfoTo.getUserKey();
System.out.println("用户未登录后的临时用户key: "+cartKey);
}
//因为数据是hash
BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
return operations;
}
g.组合为最终的CartServiceImpl的添加购物车的方法
//添加购物车
@Override
public CartItem addCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
BoundHashOperations<String, Object, Object> cartOps = getCartOps();
CartItem cartItem = new CartItem();
//异步编排,作用:多个任务使用同一线程
CompletableFuture<Void> futureSkuInfo = CompletableFuture.runAsync(() -> {
//1.远程查询当前要添加的商品信息。product的SkuInfo
R r = productFeignService.info(skuId);
SkuInfoVo data = r.getData("skuInfo", new TypeReference<SkuInfoVo>() {
});
//2.商品信息添加到购物车
cartItem.setSkuId(skuId);
cartItem.setCheck(true);
cartItem.setImage(data.getSkuDefaultImg());
cartItem.setTitle(data.getSkuTitle());
cartItem.setPrice(data.getPrice());
cartItem.setCount(num);
}, executor);
CompletableFuture<Void> futureSkuSaleAttrValues = CompletableFuture.runAsync(() -> {
//3.远程查询属组合信息.product的SkuSaleAttrValue
List<String> values = productFeignService.getSkuSaleAttrValues(skuId);
cartItem.setSkuAttr(values);
}, executor);
CompletableFuture.allOf(futureSkuInfo,futureSkuSaleAttrValues).get();
String s = JSON.toJSONString(cartItem);
cartOps.put(skuId.toString(),s);
return cartItem;
}
3). 上面2)的结果
在未登录,登录下,分表添加商品到购物车,会在redis存不同的数据。
4).添加购物车细节
添加购物车分两种情况
@Override
public CartItem addCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
BoundHashOperations<String, Object, Object> cartOps = getCartOps();
第1种购物车有此商品
//如果购物车有此商品,修改数量即可。没有就添加新商品
String res = (String) cartOps.get(skuId.toString());
if (