尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

jpetstore-6购物车实现深扒:HttpSession与Cart域模型设计的完整教程

jpetstore-6购物车实现深扒:HttpSession与Cart域模型设计的完整教程 jpetstore-6购物车实现深扒HttpSession与Cart域模型设计的完整教程【免费下载链接】jpetstore-6A web application built on top of MyBatis 3, Spring 3 and Stripes项目地址: https://gitcode.com/gh_mirrors/jp/jpetstore-6jpetstore-6 是一个基于 MyBatis 3 与 Spring 3 构建的经典 Java Web 电商示例项目本文带你完整拆解它的购物车实现购物车数据如何通过HttpSession在浏览器访问间保持、Cart与CartItem这两个Cart 域模型是如何设计的、以及从加购到下单的完整数据流。读完你会发现一个看似简单的购物车背后藏着懒加载、双数据结构同步、BigDecimal 金额计算等一连串值得学习的工程细节 一、先看全貌购物车数据在系统里如何流转整个购物车功能横跨三层各自由独立文件承载层次职责核心文件Web 层接收请求、读写 Sessionsrc/main/java/org/mybatis/jpetstore/web/controllers/CartController.java域模型层内存中维护购物车数据结构src/main/java/org/mybatis/jpetstore/domain/Cart.java、src/main/java/org/mybatis/jpetstore/domain/CartItem.java视图层渲染购物车表格src/main/webapp/WEB-INF/jsp/cart/Cart.jsp数据流非常直观每次请求 → 从 HttpSession 取出 Cart 对象 → 修改 → 随 Session 保存 → 交给 JSP 渲染。购物车不经过数据库全部存在服务器内存里直到用户确认下单时才落库。二、Cart 域模型深扒一个购物车两套数据结构打开Cart.java最先映入眼帘的是两个成员变量这是整个设计最精妙的地方private final MapString, CartItem itemMap new ConcurrentHashMap(); private final ListCartItem itemList new ArrayList();为什么要一份数据存两份itemMapConcurrentHashMap以itemId为键实现 O(1) 的快速查找。加购前先查购物车里有没有这件商品、按 ID 改数量、删除商品全靠它。用并发容器也体现了对多线程 Web 环境的防御。itemListArrayList保持商品加入顺序专门用于页面展示和遍历计算。两套结构在每次写操作时严格同步例如addItem()的逻辑是若itemMap中没有该商品则新建CartItem并同时放入 map 和 list随后统一调用incrementQuantity()。removeItemById()同理两边一起移除。 这种双写模式是购物车这类既要快查、又要保序场景的常见技巧。再看CartItem.java它是购物车的一行记录只有 4 个字段item完整的商品对象来自domain/Item.java含价格、属性、所属产品quantity数量inStock加购时是否库存充足的快照标记total小计金额一个容易忽略的细节是calculateTotal()——每次setItem、setQuantity、incrementQuantity都会自动用BigDecimal重算total listPrice × quantity。金额计算全程使用BigDecimal而非double避免了浮点误差这是电商代码的基本功。购物车总价getSubTotal()则用 Stream 一行流式求和itemList.stream() .map(ci - ci.getItem().getListPrice().multiply(new BigDecimal(ci.getQuantity()))) .reduce(BigDecimal.ZERO, BigDecimal::add);另外Cart和CartItem都实现了Serializable并显式声明serialVersionUID——因为 Session 在某些服务器配置下会把内容序列化到磁盘或内存换页区不实现接口购物车就无法持久存活。三、HttpSession 中的购物车懒初始化模式CartController里有一段几乎可以照抄到任何 Java Web 项目的代码private Cart getCart(HttpSession session) { Cart cart (Cart) session.getAttribute(cart); if (cart null) { cart new Cart(); session.setAttribute(cart, cart); } return cart; }这就是懒初始化Lazy Initialization用户还没买任何东西时Session 里并不存在cart属性第一次调用任意购物车接口时才创建并挂到 Session 上。好处是零浪费每个访问者都只占一份内存。这里也暴露了 Session 方案的固有特性值得新手理解✅匿名可用未登录游客也能加购因为 Session 不依赖账户体系✅读写极快纯内存操作无需数据库往返⚠️单机限制多台服务器做集群时Session 不共享购物车会丢⚠️重启即失应用重启后内存中的购物车清空理解这些利弊你就知道为什么大型电商会改用 Redis 集中存储购物车而 jpetstore-6 作为示例项目选择 Session 是最务实的简化。四、四个购物车操作接口逐个拆解CartController以RequestMapping(/cart)注册共 4 个接口全部围绕上面的getCart(session)展开1. 加购GET /cart/addItem参数为workingItemId。先做空值校验再分两条路径商品已在车里cart.containsItemId()→ 直接incrementQuantityByItemId()新车里的商品 → 先经CatalogService.isItemInStock()查库确认库存再cart.addItem(item, isInStock)注意inStock是加购那一刻的快照之后库存卖光购物车里仍保留该商品并显示无货用户可以自行移除。2. 移除GET /cart/removeItem调用cart.removeItemById(itemId)若返回null说明车里根本没这件商品走错误页。3. 批量改数量POST /cart/update这是最接地气的一个接口配合Cart.jsp中的表格——每行的数量输入框name就是itemIdinput typetext size3 name${cartItem.item.itemId} value${cartItem.quantity} /服务端遍历购物车用request.getParameter(itemId)按商品 ID 取回新数量并setQuantityByItemId()数量小于 1 就顺手把该行删除。遇到非法数字输入则静默跳过保证一个坏行不影响其他行。4. 去结算GET /cart/checkout仅仅把购物车塞进 Model转发到cart/Checkout.jsp展示结算摘要真正的下单在下一节登场。五、从购物车到订单一次教科书级的模型转换购物车数据最终要在下单时物化成数据库记录这个转换发生在OrderController.java与domain/Order.java之间分三步第一步登录校验 生成订单草稿。GET /order/new要求accountBean已认证否则跳转登录页随后调用order.initOrder(account, cart)。第二步Cart → Order 字段搬运。Order.initOrder()完成三件事把账户里的收货/账单地址、姓名整块拷贝到订单totalPrice cart.getSubTotal()直接复用第二节的流式求和遍历cart.getAllCartItems()把每个CartItem转成LineItem行项目拷贝数量、商品 ID、单价并重算小计LineItemdomain/LineItem.java与CartItem结构高度相似——这正是购物车行与订单行同构的体现转换成本极低。第三步确认下单 清空购物车。POST /order/new携带confirmedtrue时调用OrderService.insertOrder()service/OrderService.java这是一个Transactional事务方法先用Sequence取订单号 → 逐行updateInventoryQuantity扣减库存 → 插入订单主表、状态表和全部行项目。任何一步失败整体回滚库存扣减与订单落库强一致。成功后执行关键一行session.setAttribute(cart, new Cart());用一个新的空 Cart 覆盖 Session 里的旧值——既避免残留旧引用又与懒初始化模式无缝衔接下一轮购物从零开始。六、单元测试与设计总结src/test/java/org/mybatis/jpetstore/domain/CartTest.java用 JUnit 5 把域模型测得很干净加购合并数量、库存标记、按 ID 删除含删除不存在的商品、连续增量、直接设量、空车与多商品的小计计算——基本覆盖了Cart的每个公开方法。建议新手在理解本文后运行一遍这些测试对照断言看输出是学习域模型最快的方式。最后提炼 4 条可直接复用的设计经验双数据结构Map 管快速查找、List 管有序展示写操作保持两边同步懒初始化 SessiongetAttribute为 null 才setAttribute按需创建金额必用 BigDecimal且小计在模型内自动重算防止视图层算错账事务边界放在订单服务购物车阶段不碰数据库下单瞬间才在Transactional里扣库存、写订单最后重置购物车——读放大到内存、写集中到事务。把这套模式吃透再去理解 Redis 购物车、分布式锁等进阶方案就有扎实的对照基础了 【免费下载链接】jpetstore-6A web application built on top of MyBatis 3, Spring 3 and Stripes项目地址: https://gitcode.com/gh_mirrors/jp/jpetstore-6创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表