小白勇闯《苍穹外卖》Day8 导入地址簿功能代码代码已上传用户下单需求分析和设计流程接口设计数据库设计订单表和订单明细表的关系一对多代码开发DTOVO小程序提交下单 JSON → Controller 接收封装 OrdersSubmitDTO → 调用 service.submitOrder → service 校验地址、购物车组装 Orders 实体插入主表遍历购物车组装明细批量插入清空购物车组装 OrderSubmitVO 返回 → Controller 包装 Result 返回小程序。OrderController/** * 订单 */ RestController(userOrderController) RequestMapping(/user/order) Slf4j Api(tags C端-订单接口) public class OrderController { Autowired private OrderService orderService; /** * 用户下单 * * param ordersSubmitDTO * return */ PostMapping(/submit) ApiOperation(用户下单) public ResultOrderSubmitVO submit(RequestBody OrdersSubmitDTO ordersSubmitDTO) { log.info(用户下单{}, ordersSubmitDTO); OrderSubmitVO orderSubmitVO orderService.submitOrder(ordersSubmitDTO); return Result.success(orderSubmitVO); } }OrderServicepublic interface OrderService { /** * 用户下单 * param ordersSubmitDTO * return */ OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO); }OrderServiceImpl/** * 订单 */ Service //把当前实现类交给Spring容器管理Controller才能注入OrderService Slf4j //lombok生成log日志对象本方法没写log但是类上加了 public class OrderServiceImpl implements OrderService { //注入各个mapper操作不同数据表 Autowired private OrderMapper orderMapper; //操作订单主表 orders Autowired private OrderDetailMapper orderDetailMapper; //操作订单明细表 order_detail Autowired private ShoppingCartMapper shoppingCartMapper; //操作购物车表 shopping_cart Autowired private AddressBookMapper addressBookMapper; //操作地址簿表 addressBook /** * 用户下单 * * param ordersSubmitDTO controller传过来的【DTO入参】小程序提交下单的json数据 * return OrderSubmitVO 返回给controller最后给到小程序前端 */ Transactional //✅重点事务这一整个方法里面所有数据库操作要么全部成功要么全部失败回滚 public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) { // 第一步各种异常校验下单之前先判断条件是否合法 //根据地址id查询收货地址DTO里面传过来addressBookId用户选的收货地址id AddressBook addressBook addressBookMapper.getById(ordersSubmitDTO.getAddressBookId()); //地址查不到说明地址已经被删除不能下单抛自定义业务异常 if (addressBook null) { throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL); } //从ThreadLocal获取当前登录小程序用户的userIdBaseContext拦截器存进去的 Long userId BaseContext.getCurrentId(); //构建购物车查询条件对象 ShoppingCart shoppingCart new ShoppingCart(); shoppingCart.setUserId(userId); //查询该用户全部购物车商品 ListShoppingCart shoppingCartList shoppingCartMapper.list(shoppingCart); //如果购物车为空抛出异常不让下单 if (shoppingCartList null || shoppingCartList.size() 0) { throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL); } // 第二步组装订单主表实体 Orders实体类对应数据库orders表 Orders order new Orders(); //属性拷贝把DTO里面的字段复制到order实体。DTO来自前端但是缺少数据库需要的部分字段 BeanUtils.copyProperties(ordersSubmitDTO,order); //从查询出来的addressBook地址对象补全订单缺少的字段DTO不带这些信息 order.setPhone(addressBook.getPhone()); //收货人手机号 order.setAddress(addressBook.getDetail()); //收货详细地址你注释写老师少写这行不写数据库地址为空 order.setConsignee(addressBook.getConsignee()); //收货人姓名 order.setNumber(String.valueOf(System.currentTimeMillis()));//订单号用当前时间毫秒值充当唯一订单编号 order.setUserId(userId); //下单用户id order.setStatus(Orders.PENDING_PAYMENT); //订单状态待付款 order.setPayStatus(Orders.UN_PAID); //支付状态未支付 order.setOrderTime(LocalDateTime.now()); //下单时间取系统当前时间 //向订单主表插入一条记录插入之后order对象会回填数据库自增主键idorder.getId()才能拿到订单id orderMapper.insert(order); // 第三步组装订单明细一个订单对应多条明细购物车每一条就是一条订单明细 ListOrderDetail orderDetailList new ArrayList(); //遍历购物车全部商品 for (ShoppingCart cart : shoppingCartList) { OrderDetail orderDetail new OrderDetail(); BeanUtils.copyProperties(cart, orderDetail); //把购物车数据拷贝到订单明细实体 orderDetail.setOrderId(order.getId()); //⭐关键给每一条明细设置所属订单id就是上面刚插入的订单主键 orderDetailList.add(orderDetail); } //批量插入多条订单明细 orderDetailMapper.insertBatch(orderDetailList); // 第四步下单成功清空该用户的购物车 shoppingCartMapper.deleteByUserId(userId); // 第五步封装VO返回给上层ControllerVO是给前端展示用的 //builder构建者模式构建OrderSubmitVOVO不需要全部数据库字段只返回小程序需要的几个字段 OrderSubmitVO orderSubmitVO OrderSubmitVO.builder() .id(order.getId()) //订单id .orderNumber(order.getNumber()) //订单编号 .orderAmount(order.getAmount()) //订单总金额 .orderTime(order.getOrderTime()) //下单时间 .build(); return orderSubmitVO; } }OrderMapperMapper public interface OrderMapper { /** * 插入订单数据 * param order */ void insert(Orders order); }OrderMapper.xmlmapper namespacecom.sky.mapper.OrderMapper insert idinsert parameterTypeOrders useGeneratedKeystrue keyPropertyid insert into orders (number, status, user_id, address_book_id, order_time, checkout_time, pay_method, pay_status, amount, remark, phone, address, consignee, estimated_delivery_time, delivery_status, pack_amount, tableware_number, tableware_status) values (#{number}, #{status}, #{userId}, #{addressBookId}, #{orderTime}, #{checkoutTime}, #{payMethod}, #{payStatus}, #{amount}, #{remark}, #{phone}, #{address}, #{consignee}, #{estimatedDeliveryTime}, #{deliveryStatus}, #{packAmount}, #{tablewareNumber}, #{tablewareStatus}) /insert /mapperOrderDetailMapperMapper public interface OrderDetailMapper { /** * 批量插入订单明细数据 * param orderDetails */ void insertBatch(ListOrderDetail orderDetails); }OrderDetailMapper.xmlmapper namespacecom.sky.mapper.OrderDetailMapper insert idinsertBatch parameterTypelist insert into order_detail (name, order_id, dish_id, setmeal_id, dish_flavor, number, amount, image) values foreach collectionorderDetails itemod separator, (#{od.name},#{od.orderId},#{od.dishId},#{od.setmealId},#{od.dishFlavor}, #{od.number},#{od.amount},#{od.image}) /foreach /insert /mapper订单支付微信支付流程跳过微信支付这一步我是照着Purse Wind这个博主操作的微信开发者工具里面找到pages/pay/index.js找到这一段代码修改的跟我一样保存并且重新编译导入微信支付功能代码已上传修改OrderServiceImpl如下public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception { // // 当前登录用户id // Long userId BaseContext.getCurrentId(); // User user userMapper.getById(userId); // // //调用微信支付接口生成预支付交易单 // JSONObject jsonObject weChatPayUtil.pay( // ordersPaymentDTO.getOrderNumber(), //商户订单号 // new BigDecimal(0.01), //支付金额单位 元 // 苍穹外卖订单, //商品描述 // user.getOpenid() //微信用户的openid // ); // // if (jsonObject.getString(code) ! null jsonObject.getString(code).equals(ORDERPAID)) { // throw new OrderBusinessException(该订单已支付); // } // // OrderPaymentVO vo jsonObject.toJavaObject(OrderPaymentVO.class); // vo.setPackageStr(jsonObject.getString(package)); // // return vo; log.info(跳过微信支付支付成功); paySuccess(ordersPaymentDTO.getOrderNumber()); return new OrderPaymentVO(); }测试通过

相关新闻

最新新闻

IO多路转接

IO多路转接

IO多路转接( I/O 多路复用),就是:一个线程,同时监视多个文件描述符(socket、文件、管道),哪个 IO 就绪了就处理哪个。多路转接的思路:把 “监视多个 fd” 这件事交给内核。 用户进程告诉内核&am…

2026/8/18 13:07:59
智驾车载以太网(12)-autosar配置以太网实例

智驾车载以太网(12)-autosar配置以太网实例

文档摘要:本文主要介绍在autosar cp中完整配置一个以太网接口的步骤,通过配置实例把前面所讲解的内容串联起来。 需求:配置一个udp服务发送和接收udp报文,mac=02:00:00:00:00:01,ip=192.168.1.1,port=10240,vlan20,mcu芯片外接一个switch交换机。 EthTrcv配置 需求分…

2026/8/18 13:07:59
Python 异步高并发实战:构建农业农村部大宗农产品公开批发价格指数引擎

Python 异步高并发实战:构建农业农村部大宗农产品公开批发价格指数引擎

㊗️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~ ㊙️本期爬虫难度指数:⭐⭐⭐⭐⭐(专家级) 🉐福利: 一次订阅后,专栏内的所有文章可永久免费看,持续更新中,保底1000+(篇)硬核实战内容。 全文目录: 🌟…

2026/8/18 13:07:59
老游戏在新电脑上闪退黑屏?DDrawCompat兼容层实战指南

老游戏在新电脑上闪退黑屏?DDrawCompat兼容层实战指南

老游戏在新电脑上闪退黑屏?DDrawCompat兼容层实战指南 【免费下载链接】DDrawCompat DirectDraw and Direct3D 1-7 compatibility, performance and visual enhancements for Windows Vista, 7, 8, 10 and 11 项目地址: https://gitcode.com/gh_mirrors/dd/DDrawC…

2026/8/18 13:07:59
3步解锁加密音乐:Unlock Music免费解密工具完整指南

3步解锁加密音乐:Unlock Music免费解密工具完整指南

3步解锁加密音乐:Unlock Music免费解密工具完整指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址: https:/…

2026/8/18 13:07:59
GPT高效使用指南:从基础指令到项目实战的完整方法论

GPT高效使用指南:从基础指令到项目实战的完整方法论

1. 先搞清楚你要的“GPT教学”到底教什么 看到“简单的GPT教学”这个标题,很多人第一反应是“怎么注册账号”或者“怎么问问题”。但如果你已经能打开GPT的聊天窗口,那最需要的教学可能不是这些。真正让GPT从“玩具”变成“生产力工具”的,是…

2026/8/18 13:02:59