day10-功能实现09
家居网购项目实现09
以下皆为部分代码,详见 https://github.com/liyuelian/furniture_mall.git
21.功能20-修改购物车
21.1需求分析/图解

- 进入购物车页面,可以修改购买数量
- 更新该商品的金额
- 更新购物车商品数量和总金额
21.2思路分析

21.3代码实现
21.3.1entity层
Cart.java
增加方法updateCount()
/** * 根据家居id和count,修改指定cartItem的数量和总价 * * @param id 家居id * @param count 指定id的家居的数量 */ public void updateCount(int id, int count) { //获取指定的cartItem CartItem item = items.get(id); if (null != item) {//如果cartItem不为空 //更新数量 item.setCount(count); //某家居总价 = 单价 * 数量(为了安全使用get方法获取数量count) item.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getCount()))); } }
21.3.2web层
CartServlet.java
增加方法updateCount()
/** * 更新购物车的某个家居数量 * * @param req * @param resp * @throws ServletException * @throws IOException */ protected void updateCount(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int id = DataUtils.parseInt(req.getParameter("id"), 0); int count = DataUtils.parseInt(req.getParameter("count"), 1); //获取session中的购物车 Cart cart = (Cart) req.getSession().getAttribute("cart"); if (null != cart) { cart.updateCount(id, count); } //回到请求更新家居购物车的页面 resp.sendRedirect(req.getHeader("Referer")); }
21.3.3前端
cart.jsp
添加绑定事件,当点击修改对应的家居数量时,向服务器发送更新家居信息的请求
<script type="text/javascript"> $(function () { /*-------------------------- Cart Plus Minus Button ----------------------------*/ var CartPlusMinus = $(".cart-plus-minus"); CartPlusMinus.prepend('<div class="dec qtybutton">-</div>'); CartPlusMinus.append('<div class="inc qtybutton">+</div>'); $(".qtybutton").on("click", function () { var $button = $(this); var oldValue = $button.parent().find("input").val(); if ($button.text() === "+") { var newVal = parseFloat(oldValue) + 1; } else { // Don't allow decrementing below zero if (oldValue > 1) { var newVal = parseFloat(oldValue) - 1; } else { newVal = 1; } } $button.parent().find("input").val(newVal); var furnId = $button.parent().find("input").attr("furnId"); //发出修改购物车的请求 location.href = "cartServlet?action=updateCount&count=" + newVal + "&id=" + furnId; }); }) </script>
21.4完成测试

修改家居数量:

22.功能21-删除/清空购物车
22.1需求分析/图解

- 进入购物车,可以删除某商品
- 可以清空购物车
- 要求该出适当的确认信息
22.2思路分析
见21.2思路分析图
22.3代码实现
22.3.1entity层
Cart.java添加删除购物车家居项的方法delItem()
/** * 根据家居id删除对应的cartItem * * @param id 家居id */ public void delItem(int id) { items.remove(id); }
增加清空方法clear()
/** * 清空items */ public void clear() { items.clear(); }
22.3.2web层
CartServlet.java添加方法delItem()
/** * 根据id删除购物车的某个家居信息 * * @param req * @param resp * @throws ServletException * @throws IOException */ protected void delItem(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int id = DataUtils.parseInt(req.getParameter("id"), 0); //获取session中的购物车 Cart cart = (Cart) req.getSession().getAttribute("cart"); if (null != cart) { cart.delItem(id); } //回到请求删除家居项的购物车页面 resp.sendRedirect(req.getHeader("Referer")); }
增加clear()方法
/** * 清空购物车 * * @param req * @param resp * @throws ServletException * @throws IOException */ protected void clear(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取session的购物车 Cart cart = (Cart) req.getSession().getAttribute("cart"); if (null != cart) { cart.clear(); } //回到请求清空家居项的购物车页面 resp.sendRedirect(req.getHeader("Referer")); }
22.3.3前端
cart.jsp
//清空购物车绑定确认事件 $("a.clearCart").click(function () { return window.confirm("你确认要清空购物车吗?") }) //给删除购物车绑定事件 $("a.delItem").click(function () { //获取要删除的家居名 var furnName = $(this).parent().parent().find("td:eq(1)").text(); //使用确认弹窗 //点击确认,返回true,点击取消,返回false return window.confirm("你确认要删除" + furnName + "吗?") })


22.4完成测试
删除购物车项:


清空购物车:


23.功能22-生成订单
23.1需求分析/图解




- 进入购物车,点击购物车结账
- 生成订单和订单项
- 如果会员没有登录,则先进入登录页面,完成登录后再结账
23.2思路分析

23.3代码实现
23.3.1设计order和order_item表
创建订单表和订单项表
### -- 设计 订单表order -- 字段参考前端给的界面 -- mysql每个字段应尽量使用not null约束 -- 字段类型的设计应当和关联的表的字段保持一致 -- 外键是否要给? -- 因为外键对效率有影响,应当从程序的业务保证数据的一致性,而不是db层保证 CREATE TABLE `order`( `id` VARCHAR(64) PRIMARY KEY, #订单号,主键 `create_time` DATETIME NOT NULL, #订单生成时间 `price` DECIMAL(11,2) NOT NULL, #订单的总金额,类型应该和furn表的price类型对应 `status` TINYINT NOT NULL, #订单状态 0-未发货 1-已发货 2-已结账 `member_id` INT NOT NULL #从属的会员id -不需要外键约束 )CHARSET utf8 ENGINE INNODB; ### -- 设计 订单项表order_item CREATE TABLE `order_item`( `id` INT PRIMARY KEY AUTO_INCREMENT, #订单项id,自增长 `name` VARCHAR(64) NOT NULL, #家居名 `price` DECIMAL(11,2) NOT NULL, #家居单价 `count` INT NOT NULL, #某项的家居数量 `total_price` DECIMAL(11,2) NOT NULL, #订单项 的总价 `order_id` VARCHAR(64) NOT NULL #从属的订单号 )CHARSET utf8 ENGINE INNODB;
23.3.2entity层
Order.java
package com.li.furns.entity; import java.math.BigDecimal; import java.util.Date; /** * Order表示一个订单 * * @author 李 * @version 1.0 */ public class Order { //属性 private String id; private Date createTime; private BigDecimal price; private Integer status; private Integer memberId; public Order() { } public Order(String id, Date createTime, BigDecimal price, Integer status, Integer memberId) { this.id = id; this.createTime = createTime; this.price = price; this.status = status; this.memberId = memberId; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public Integer getMemberId() { return memberId; } public void setMemberId(Integer memberId) { this.memberId = memberId; } @Override public String toString() { return "Order{" + "id='" + id + '\'' + ", createTime=" + createTime + ", price=" + price + ", status=" + status + ", memberId=" + memberId + '}'; } }
OrderItem.java
package com.li.furns.entity; import java.math.BigDecimal; /** * @author 李 * @version 1.0 */ public class OrderItem { private Integer id; private String name; private BigDecimal price; private Integer count; private BigDecimal totalPrice; private String orderId; public OrderItem() { } public OrderItem(Integer id, String name, BigDecimal price, Integer count, BigDecimal totalPrice, String orderId) { this.id = id; this.name = name; this.price = price; this.count = count; this.totalPrice = totalPrice; this.orderId = orderId; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public Integer getCount() { return count; } public void setCount(Integer count) { this.count = count; } public BigDecimal getTotalPrice() { return totalPrice; } public void setTotalPrice(BigDecimal totalPrice) { this.totalPrice = totalPrice; } public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId; } @Override public String toString() { return "OrderItem{" + "id=" + id + ", name='" + name + '\'' + ", price=" + price + ", count=" + count + ", totalPrice=" + totalPrice + ", orderId='" + orderId + '\'' + '}'; } }
23.3.3dao层
OrderDAO接口
package com.li.furns.dao; import com.li.furns.entity.Order; /** * @author 李 * @version 1.0 */ public interface OrderDAO { /** * 将传入的order对象保存到数据表order表 * * @param order order对象 * @return 返回操作影响的行数 */ public int saveOrder(Order order); }
OrderDAOImpl实现类
package com.li.furns.dao.impl; import com.li.furns.dao.BasicDAO; import com.li.furns.dao.OrderDAO; import com.li.furns.entity.Order; /** * @author 李 * @version 1.0 */ public class OrderDAOImpl extends BasicDAO<Order> implements OrderDAO { @Override public int saveOrder(Order order) { String sql = "INSERT INTO `order`(`id`,`create_time`,`price`,`status`,`member_id`) " + "VALUES(?,?,?,?,?)"; return update(sql, order.getId(), order.getCreateTime(), order.getPrice(), order.getStatus(), order.getMemberId()); } }
test包-OrderDAOImplTest测试
package com.li.furns.test; import com.li.furns.dao.OrderDAO; import com.li.furns.dao.impl.OrderDAOImpl; import com.li.furns.entity.Order; import org.junit.jupiter.api.Test; import java.math.BigDecimal; import java.util.Date; /** * @author 李 * @version 1.0 */ public class OrderDAOImplTest { private OrderDAO orderDAO = new OrderDAOImpl(); @Test public void saveOrder() { Order order = new Order("sn000002", new Date(), new BigDecimal(300), 0, 1); System.out.println(orderDAO.saveOrder(order)); } }

OrderItemDAO接口
package com.li.furns.dao; import com.li.furns.entity.OrderItem; /** * OrderItemDAO表示一个订单项 * * @author 李 * @version 1.0 */ public interface OrderItemDAO { /** * 将传入的orderItem对象保存到order_item表中 * * @param orderItem * @return */ public int saveOrderItem(OrderItem orderItem); }
OrderItemDAOImpl
package com.li.furns.dao.impl; import com.li.furns.dao.BasicDAO; import com.li.furns.dao.OrderItemDAO; import com.li.furns.entity.OrderItem; /** * @author 李 * @version 1.0 */ public class OrderItemDAOImpl extends BasicDAO<OrderItem> implements OrderItemDAO { @Override public int saveOrderItem(OrderItem orderItem) { String sql = "INSERT INTO `order_item`(`id`,`name`,`price`,`count`,`total_price`,`order_id`) " + "VALUES(?,?,?,?,?,?);"; return update(sql, orderItem.getId(), orderItem.getName(), orderItem.getPrice(), orderItem.getCount(), orderItem.getTotalPrice(), orderItem.getOrderId()); } }
test包-OrderItemDAOImplTest
package com.li.furns.test; import com.li.furns.dao.OrderItemDAO; import com.li.furns.dao.impl.OrderItemDAOImpl; import com.li.furns.entity.OrderItem; import org.junit.jupiter.api.Test; import java.math.BigDecimal; /** * @author 李 * @version 1.0 */ public class OrderItemDAOImplTest { private OrderItemDAO orderItemDAO = new OrderItemDAOImpl(); @Test public void saveOrderItem() { OrderItem orderItem = new OrderItem(null, "北欧小沙发", new BigDecimal(200), 3, new BigDecimal(600), "sn000001"); System.out.println(orderItemDAO.saveOrderItem(orderItem)); } }

23.3.4service层
OrderService接口
package com.li.furns.service; import com.li.furns.entity.Cart; /** * @author 李 * @version 1.0 */ public interface OrderService { /** * 1.生成订单 * 2.订单是根据购物车来生成的,cart对象在session,通过web层,传入saveOrder * 3.订单和会员id关联 * * @param cart 购物车 * @param memberId 会员id * @return 返回生成的订单号 */ public String saveOrder(Cart cart, int memberId); }
OrderServiceImpl实现类
package com.li.furns.service.impl; import com.li.furns.dao.FurnDAO; import com.li.furns.dao.OrderDAO; import com.li.furns.dao.OrderItemDAO; import com.li.furns.dao.impl.FurnDAOImpl; import com.li.furns.dao.impl.OrderDAOImpl; import com.li.furns.dao.impl.OrderItemDAOImpl; import com.li.furns.entity.*; import com.li.furns.service.OrderService; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * @author 李 * @version 1.0 */ public class OrderServiceImpl implements OrderService { private OrderDAO orderDAO = new OrderDAOImpl(); private OrderItemDAO orderItemDAO = new OrderItemDAOImpl(); private FurnDAO furnDAO = new FurnDAOImpl(); @Override public String saveOrder(Cart cart, int memberId) { //这里的业务相对而言比较综合 //任务:将cart购物车的数据以order和orderItem的形式保存到数据库中 /** * 因为生成订单会操作多张表,设计到多表事务问题,使用ThreadLocal+MySQL事务机制+过滤器Filter * 因为事务处理考虑的点比较多,这里先不处理,后面专门处理 */ //1.构建一个对应的order对象 //先生成一个UUID,表示当前的订单号。要保证订单号是唯一的 String orderId = System.currentTimeMillis() + "" + memberId; Order order = new Order(orderId, new Date(), cart.getCartTotalPrice(), 0, memberId); //将order对象保存到数据库order表中 orderDAO.saveOrder(order); //2.通过cart对象,遍历出CartItem家居项,构建orderItem对象 HashMap<Integer, CartItem> items = cart.getItems(); //遍历hm /** * 遍历方法一:entrySet * 通过entrySet的方法遍历items,取出cartItem * for(Map.Entry<Integer, CartItem> entry : items.entrySet()) { * CartItem item = entry.getValue(); * ... * } */ //遍历方法二:keySet Set<Integer> keys = items.keySet(); for (Integer id : keys) { //获取家居项 CartItem item = items.get(id); //构建orderItem对象 OrderItem orderItem = new OrderItem(null, item.getName(), item.getPrice(), item.getCount(), item.getTotalPrice(), orderId); //将orderItem对象保存到数据库表order_item中 orderItemDAO.saveOrderItem(orderItem); //更新furn表的对应记录的sales销量,stock存量 //(1)获取到furn对象 Furn furn = furnDAO.queryFurnById(id); //(2)更新furn对象的sales销量,stock存量 furn.setSales(furn.getSales() + item.getCount()); furn.setStock(furn.getStock() - item.getCount()); //(3)更新到数据表中 furnDAO.updateFurn(furn); } //清空购物车 cart.clear(); //返回生成的订单号 return orderId; } }
test包-OrderServiceImplTest测试
package com.li.furns.test; import com.li.furns.entity.Cart; import com.li.furns.entity.CartItem; import com.li.furns.service.OrderService; import com.li.furns.service.impl.OrderServiceImpl; import org.junit.jupiter.api.Test; import java.math.BigDecimal; /** * @author 李 * @version 1.0 */ public class OrderServiceImplTest { private OrderService orderService = new OrderServiceImpl(); @Test public void saveOrder() { //构建cart对象 Cart cart = new Cart(); cart.addItem(new CartItem(1, "北欧风格小桌子", new BigDecimal(180), 10, new BigDecimal(1800))); cart.addItem(new CartItem(26, "简约风格小椅子", new BigDecimal(100), 5, new BigDecimal(500))); String orderId = orderService.saveOrder(cart, 2); System.out.println(orderId); } }

furn表对应的家居项:
-测试前

-测试后

order表:

order_item表:

23.3.5web层
配置OrderServlet
<servlet> <servlet-name>OrderServlet</servlet-name> <servlet-class>com.li.furns.web.OrderServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>OrderServlet</servlet-name> <url-pattern>/orderServlet</url-pattern> </servlet-mapping>
OrderServlet:
package com.li.furns.web; import com.li.furns.entity.Cart; import com.li.furns.entity.Member; import com.li.furns.service.OrderService; import com.li.furns.service.impl.OrderServiceImpl; import javax.servlet.*; import javax.servlet.http.*; import java.io.IOException; /** * @author 李 * @version 1.0 */ public class OrderServlet extends BasicServlet { private OrderService orderService = new OrderServiceImpl(); /** * 生成订单 * * @param req * @param resp * @throws ServletException * @throws IOException */ protected void saveOrder(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取购物车cart Cart cart = (Cart) req.getSession().getAttribute("cart"); if (null == cart || cart.isEmpty()) {//购物车不存在session或者购物车没有任何东西 // 转发到首页 req.getRequestDispatcher("/index.jsp").forward(req, resp); return;//结束业务 } //获取当前登录的memberId Member member = (Member) req.getSession().getAttribute("member"); if (null == member) {//如果没有登录 //转发到登录页面 req.getRequestDispatcher("/views/member/login.jsp").forward(req, resp); return;//结束业务 } //生成订单 String orderId = orderService.saveOrder(cart, member.getId()); req.getSession().setAttribute("orderId", orderId); //使用重定向到checkout.jsp页面 resp.sendRedirect(req.getContextPath() + "/views/order/checkout.jsp"); } }
修改前端接口:略
23.4完成测试
未登录状态下添加家居到购物车,点击生成账单,请求转发登录页面


点击登录后重新返回购物车页面,点击生成订单,生成订单成功

数据库插入成功
order表

order_item表

furn表

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!