一、购物车需求分析:
1.1 购物车存储数据结构如下:
购物车实现的核心思想:
根据京东购物车的改版,我们也做成了要求登录版的购物车,即所有购物商品的用户必须登录。这使用的是cas单点登录。
1.2 数据模型Cart声明如下:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Cart implements Serializable {
private String sellerId; //商家id
private String sellerName; //商家名称
private List<OrderItemEntity> orderItemList; //订单项列表
}
二、新建模块
zyg-cart-interface / zyg-cart-service / zyg-cart-web
说明: 1、在zyg-cart-service中引入redis的依赖就可以,其它与普通服务一样。 2、在zyg-cart-web中引入cas与security的依赖,可以参考zyg-user-web模块,将相关的单点登录的登录引入。
三、添加购物车功能的实现
3.1 在zyg-cart-service模块中定义添加到购物车的方法:
/**
* ------------------------------
* 功能:
* 作者:WF
* 微信:hbxfwf13590332912
* 创建时间:2021/8/13-14:47
* ------------------------------
*/
@Service
public class CartServiceImpl implements CartService {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private ItemDao itemDao;
/**
* 功能: 添加商品到购物车
* 参数:
* 返回值: java.util.List<com.zelin.entity.group.Cart>
* 时间: 2021/8/13 14:47
*/
@Override
public List<Cart> addCart(String name, Long itemId, int num) {
//第一步:得到购物车列表
//1.1 根据skuid得到sku商品对象
ItemEntity itemEntity = itemDao.selectById(itemId);
//1.2 得到商家id
String sellerId = itemEntity.getSellerId();
//1.3 从redis中读取购物车列表(字符串形式)
String cartListString = redisTemplate.opsForValue().get(name);
//1.4 将购物车列表转换为List<Cart>这种数据
List<Cart> cartList = null;
if(StringUtils.isBlank(cartListString)) {
cartListString = "[]";
}
cartList = JSON.parseArray(cartListString, Cart.class);
//第二步:根据itemId查询在某个购物车中是否存在此商品,有就返回此购物车
//2.1 遍历购物车列表,根据sellerId查找购物车
Cart cart = findCartBySellerId(cartList,sellerId);
//2.2 如要没有购物车,就构造一个,有就修改购物车中的购物项集合
if(cart == null){ //如果没有就创建
cart = createCart(itemEntity,num);
//放到购物车集合列表中
cartList.add(cart);
}else{ //如果有就修改此购物车
//2.3 判断在此购物车的购物项集合中是否有此itemId对应的购物项
OrderItemEntity orderItem = findOrderItemByItemId(cart,itemId);
//2.4 如果有此购物项,就修改它的数量及金额
if(orderItem != null){
orderItem.setNum(orderItem.getNum() + num); //修改数量
orderItem.setTotalFee(new BigDecimal(orderItem.getNum() * orderItem.getPrice().doubleValue())); //修改小计
}else{ //2.5 没有此商品就创建此商品并放到购物车的购物项集合中
//2.5.1 构造item对象
OrderItemEntity item = createOrderItem(itemEntity, num);
//2.5.2 将此item放到购物车的购物项集合中
cart.getOrderItemList().add(item);
}
//其它一些兼容性处理
//① 如果购物车中没有购物项,要从购物车列表中移除此购物项
if(cart.getOrderItemList().size() == 0){
cartList.remove(cart);
}
//② 如果某个购物车的购物项的数量为0,要从购物车的购物项中移除此购物项
if(orderItem != null && orderItem.getNum() == 0){
cart.getOrderItemList().remove(orderItem);
}
}
//将购物车列表放到redis中
redisTemplate.opsForValue().set(name,JSON.toJSONString(cartList),10, TimeUnit.DAYS);
return cartList;
}
/**
* 功能: 在购物车的购物项列表中查询是否指定itemid对应的购物项
* 参数:
* 返回值: com.zelin.entity.OrderItemEntity
* 时间: 2021/8/13 15:16
*/
private OrderItemEntity findOrderItemByItemId(Cart cart, Long itemId) {
for (OrderItemEntity itemEntity : cart.getOrderItemList()) {
if (itemEntity.getItemId().longValue() == itemId.longValue()) {
return itemEntity;
}
}
return null;
}
/**
* 功能: 创建一个新的购物车
* 参数:
* 返回值: com.zelin.entity.group.Cart
* 时间: 2021/8/13 15:04
*/
private Cart createCart(ItemEntity itemEntity, int num) {
//1. 创建购物车对象
Cart cart = new Cart();
cart.setSellerId(itemEntity.getSellerId());
cart.setSellerName(itemEntity.getSeller());
List<OrderItemEntity> orderItemList = new ArrayList<>();
OrderItemEntity item = createOrderItem(itemEntity, num);
//3. 将item放到orderItemList中
orderItemList.add(item);
//2. 将orderItemList设置到购物车的购物项集合
cart.setOrderItemList(orderItemList);
//3. 返回
return cart;
}
/**
* 功能: 创建订单项方法
* 参数:
* 返回值: void
* 时间: 2021/8/13 15:11
*/
private OrderItemEntity createOrderItem(ItemEntity itemEntity, int num) {
//1. 定义OrderItemEntity对象
OrderItemEntity item = new OrderItemEntity();
item.setGoodsId(itemEntity.getGoodsId());
item.setItemId(itemEntity.getId());
item.setNum(num);
item.setPrice(itemEntity.getPrice());
item.setTitle(itemEntity.getTitle());
item.setPicPath(itemEntity.getImage());
item.setTotalFee(item.getPrice().multiply(new BigDecimal(num))); //小计
//2. 返回
return item;
}
/**
* 功能: 从购物车列表中根据商家id查询出购物车对象
* 参数:
* 返回值: com.zelin.entity.group.Cart
* 时间: 2021/8/13 15:02
*/
private Cart findCartBySellerId( List<Cart> cartList ,String sellerId) {
for (Cart cart : cartList) {
if (cart.getSellerId().equals(sellerId)) {
return cart;
}
}
return null;
}
}
3.2 在控制器cartController中定添加到购物车方法
@Controller
@RequestMapping("cart")
public class CartController {
@Reference(timeout = 5000)
public CartService cartService;
//1. 添加商品到购物车中
@RequestMapping("/addCart")
public String addCart(Long itemId, int num, Model model){
//1.0 得到登录名
String name = SecurityContextHolder.getContext().getAuthentication().getName();
System.out.println("name = " + name);
//1.1 将指定的sku商品添加到购物车列表中
List<Cart> cartList = cartService.addCart(name,itemId,num);
System.out.println("cartList = " + cartList);
//1.2 将购物车集合放到model中,送到模板中显示
model.addAttribute("cartList",cartList);
//1.3 返回页面
return "cart";
}
}
四、展示购物车:
4.1 前端计算购物车的总数量与总金额
<script th:inline="javascript">
$(function() {
//1. 得到购物车数据
let cartList = [[${cartList}]];
//2. 遍历购物车集合计算总金额及总数量
let totalNum = 0; //商品总数量
let totalMoney = 0; //商品总金额
cartList.forEach(cart=>{
let items = cart.orderItemList;
items.forEach(item=>{
totalNum += item.num;
totalMoney += item.totalFee;
})
})
//3. 为控件赋值
$("#goodsNum").html(totalNum)
$("#goodsPrice").html("¥" + totalMoney);
})
</script>
4.2 前端展示数据
<div class="toolbar">
<div class="chosed">已选择<span id="goodsNum">xxx</span>件商品</div>
<div class="sumprice">
<span><em>总价(不含运费) :</em><i class="summoney" id="goodsPrice">¥16283.00</i></span>
<span><em>已节省:</em><i>-¥20.00</i></span>
</div>
<div class="sumbtn">
<a class="sum-btn" href="/static/cart/getOrderInfo.html" target="_blank">结算</a>
</div>
</div>