• 苍穹外卖day8(2)用户下单、微信支付



    前言

    用户下单
    因为订单信息中包含了其他业务中的数据,在逻辑处理中涉及了多个其他业务,比如要判断地址簿、购物车数据是否为空(查询地址簿和购物车)
    订单表字段多,在插入数据的时候,要确保每个字段都有值
    向订单表插入数据后,也得向订单明细表插入数据:具体来说,就是遍历购物车数据,把购物车中的商品详细信息(菜品、套餐、数量、价格…)赋给订单详情表
    完成下单后要清空购物车
    订单支付
    需要商家号,跳过支付,模拟实现订单支付功能


    一、用户下单

    1. 业务流程

    在这里插入图片描述

    2. 接口设计

    在这里插入图片描述

    3. 数据库设计

    在这里插入图片描述

    3.1 订单表orders

    在这里插入图片描述

    3.2 订单明细表 order_detail

    在这里插入图片描述

    4. 代码实现

    1、创建OrderController并提供用户下单方法

    @PostMapping("/submit")
    @ApiOperation("用户下单")
    public Result<OrderSubmitVO> submit(@RequestBody OrdersSubmitDTO ordersSubmitDTO){
        log.info("用户下单,参数为:{}",ordersSubmitDTO);
        OrderSubmitVO orderSubmitVO = orderService.submitOrder(ordersSubmitDTO);
        return Result.success(orderSubmitVO);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、在OrderService接口声明用户下单方法,OrderServiceImpl实现

    @Transactional
    public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
        //1. 处理各种业务异常
           //地址簿为空
        AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
        if(addressBook == null){
            throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        }
           //购物车数据为空
        ShoppingCart shoppingCart = new ShoppingCart();
        Long userId = BaseContext.getCurrentId();
        shoppingCart.setUserId(userId);
        List<ShoppingCart> shoppingCartList = shoppingCartMapper.list(shoppingCart);
        if(shoppingCartList == null || shoppingCartList.size()==0){
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }
        //2. 向订单表插入一条数据
        Orders orders = new Orders();
        BeanUtils.copyProperties(ordersSubmitDTO,orders);
        orders.setOrderTime(LocalDateTime.now());
        orders.setPayStatus(Orders.UN_PAID);
        orders.setStatus(Orders.PENDING_PAYMENT);
        orders.setNumber(String.valueOf(System.currentTimeMillis()));
        orders.setPhone(addressBook.getPhone());
        orders.setConsignee(addressBook.getConsignee()); //收货人
        orders.setUserId(userId);
        //orders.setAddress(addressBook.getDetail());
        orderMapper.insert(orders);
        List<OrderDetail> orderDetailList = new ArrayList<>();
        //3. 向订单明细表插入n条数据
        for(ShoppingCart cart:shoppingCartList){
            //订单明细
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(cart,orderDetail);
            //设置当前订单明细关联的订单id
            orderDetail.setOrderId(orders.getId());
            orderDetailList.add(orderDetail);
        }
        orderDetailMapper.insertBatch(orderDetailList);
        //4. 清空用户购物车数据
        shoppingCartMapper.deleteByUserId(userId);
        //5. 封装VO返回结果
        OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
                .id(orders.getId())
                .orderTime(orders.getOrderTime())
                .orderNumber(orders.getNumber())
                .orderAmount(orders.getAmount())
                .build();
        return orderSubmitVO;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    3、在OrderMapper接口定义insert方法,插入数据到订单表中,在OrderMapper.xml文件中编写sql语句

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into sky_take_out.orders
    	    (number, status, user_id, address_book_id, order_time, checkout_time,
    	    pay_method, pay_status, amount, remark, phone, address, user_name,
    	    consignee, cancel_reason, rejection_reason, cancel_time,estimated_delivery_time,
    	    delivery_status, delivery_time, pack_amount, tableware_number, tableware_status)
        VALUES
            (#{number}, #{status}, #{userId}, #{addressBookId}, #{orderTime}, #{checkoutTime},
             #{payMethod}, #{payStatus}, #{amount}, #{remark}, #{phone}, #{address}, #{userName},
             #{consignee}, #{cancelReason}, #{rejectionReason}, #{cancelTime}, #{estimatedDeliveryTime},
             #{deliveryStatus}, #{deliveryTime}, #{packAmount}, #{tablewareNumber}, #{tablewareStatus})
    insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4、在OrderDetailMapper接口定义insertBatch方法,批量插入订单明细数据,在OrderDetailMapper.xml文件中编写sql语句

    <insert id="insertBatch">
        insert into sky_take_out.order_detail(name, image, order_id, dish_id, setmeal_id, dish_flavor, amount)
        VALUES
        <foreach collection="orderDetailList" item="od" separator=",">
           (#{od.name}, #{od.image}, #{od.orderId}, #{od.dishId}, #{od.setmealId}, #{od.dishFlavor}, #{od.amount})
        foreach>
    insert>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    二、订单支付

    需要注册微信支付商户号获取微信支付平台证书、商户私钥文件
    (https://pay.weixin.qq.com/static/product/product_index.shtml)
    微信支付时序图
    在这里插入图片描述
    获取临时域名:支付成功后微信服务通过该域名回调我们的程序 (cplor)
    这部分因为没有商家号,所以选择跳过相关操作,模拟实现支付功能,实现代码如下:
    1、用户端(小程序):pay->index.json->支付详情(200多行)

    // 支付详情
       handleSave: function handleSave() {
         var _this = this;
         if (this.timeout) {
           (0, _api.cancelOrder)(this.orderId).then(function (res) {
           });
           uni.redirectTo({
             url: '/pages/details/index?orderId=' + this.orderId });
         } else {
           // 如果支付成功进入成功页
           clearTimeout(this.times);
           var params = {
             orderNumber: this.orderDataInfo.orderNumber,
             payMethod: this.activeRadio === 0 ? 1 : 2 };
           (0, _api.paymentOrder)(params).then(function (res) {
             if (res.code === 1) {
               wx.showModal({
                 title: '提示',
                 content: '支付成功',
                 success:function(){
                   uni.redirectTo({url: '/pages/success/index?orderId=' + _this.orderId });
                 }
               })
               console.log('支付成功!')
               
               //uni.redirectTo({url: '/pages/success/index?orderId=' + _this.orderId });
             } else {
               wx.showModal({
                 title: '提示',
                 content: res.msg
               })
             }
           });
         }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    2、管理端(idea)
    (1)在OderController中定义payment方法实现订单支付

     @PutMapping("/payment")
     @ApiOperation("订单支付")
     public Result<OrderPaymentVO> payment(@RequestBody OrdersPaymentDTO ordersPaymentDTO) throws Exception {
         log.info("订单支付:{}", ordersPaymentDTO);
         OrderPaymentVO orderPaymentVO = orderService.payment(ordersPaymentDTO);
         log.info("生成预支付交易单:{}", orderPaymentVO);
         //模拟交易成功,修改订单状态
         orderService.paySuccess(ordersPaymentDTO.getOrderNumber());
         return Result.success(orderPaymentVO);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    (2)在orderService定义相关方法,在orderServiceImpl中实现
    订单支付

    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
            // 当前登录用户id
            Long userId = BaseContext.getCurrentId();
            User user = userMapper.getById(userId);
            //生成空jsonObject
            JSONObject jsonObject = new JSONObject();
    
            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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    支付成功,修改订单状态

     public void paySuccess(String outTradeNo) {
            // 根据订单号查询订单
            Orders ordersDB = orderMapper.getByNumber(outTradeNo);
            // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
            Orders orders = Orders.builder()
                    .id(ordersDB.getId())
                    .status(Orders.TO_BE_CONFIRMED)
                    .payStatus(Orders.PAID)
                    .checkoutTime(LocalDateTime.now())
                    .build();
            orderMapper.update(orders);
            //通过websocket向客户端浏览器推送消息 type orderId content
            Map map = new HashMap();
            map.put("type",1);  //1表示来单提醒 2表示客户催单
            map.put("orderId",ordersDB.getId());
            map.put("content","订单号:"+outTradeNo);
            String json = JSON.toJSONString(map);
            webSocketServer.sendToAllClient(json);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

  • 相关阅读:
    C语言使用MinGW中的GCC生成平面(flat)二进制文件
    常用Python自动化测试框架有哪些?优缺点对比
    华为GAUSSDB集成
    UIStackView入门使用两个问题
    MyBatis-plus 分页功能实现
    开发工具篇第九讲:菜鸟入坑指南
    进阶C语言-指针的进阶(中)
    Find My手机保护壳|苹果Find My与手机保护壳结合,智能防丢,全球定位
    list解析<stl初级> (跑路人笔记)
    python04- for in 、while in、列表、交叉赋值、元组、字典、集合(set)、公共方法、列表推到式
  • 原文地址:https://blog.csdn.net/qq_51076441/article/details/138081959