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

文章目录

  • 前言
  • 一、用户下单
    • [1. 业务流程](#1. 业务流程)
    • [2. 接口设计](#2. 接口设计)
    • [3. 数据库设计](#3. 数据库设计)
      • [3.1 订单表orders](#3.1 订单表orders)
      • [3.2 订单明细表 order_detail](#3.2 订单明细表 order_detail)
    • [4. 代码实现](#4. 代码实现)
  • 二、订单支付

前言

用户下单

因为订单信息中包含了其他业务中的数据,在逻辑处理中涉及了多个其他业务,比如要判断地址簿、购物车数据是否为空(查询地址簿和购物车)

订单表字段多,在插入数据的时候,要确保每个字段都有值

向订单表插入数据后,也得向订单明细表插入数据:具体来说,就是遍历购物车数据,把购物车中的商品详细信息(菜品、套餐、数量、价格...)赋给订单详情表

完成下单后要清空购物车
订单支付

需要商家号,跳过支付,模拟实现订单支付功能


一、用户下单

1. 业务流程

2. 接口设计

3. 数据库设计

3.1 订单表orders

3.2 订单明细表 order_detail

4. 代码实现

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

java 复制代码
@PostMapping("/submit")
@ApiOperation("用户下单")
public Result<OrderSubmitVO> submit(@RequestBody OrdersSubmitDTO ordersSubmitDTO){
    log.info("用户下单,参数为:{}",ordersSubmitDTO);
    OrderSubmitVO orderSubmitVO = orderService.submitOrder(ordersSubmitDTO);
    return Result.success(orderSubmitVO);
}

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

java 复制代码
@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;
}

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

xml 复制代码
<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>

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

xml 复制代码
<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>

二、订单支付

需要注册微信支付商户号获取微信支付平台证书、商户私钥文件

https://pay.weixin.qq.com/static/product/product_index.shtml)

微信支付时序图

获取临时域名:支付成功后微信服务通过该域名回调我们的程序 (cplor)

这部分因为没有商家号,所以选择跳过相关操作,模拟实现支付功能,实现代码如下:

1、用户端(小程序):pay->index.json->支付详情(200多行)

json 复制代码
// 支付详情
   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
           })
         }
       });
     }
 }

2、管理端(idea)

(1)在OderController中定义payment方法实现订单支付

java 复制代码
 @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);
 }

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

订单支付

java 复制代码
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;
    }

支付成功,修改订单状态

java 复制代码
 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);
    }

相关推荐
写了20年代码的老程序员14 小时前
写了 20 年 Java,我受够了 MyBatis 的 4 个瞬间
mybatis·orm
jameslogo14 小时前
如何用RocketMQTemplate发送事务消息
java·spring boot·rocketmq
漠效16 小时前
阿里云上的ICP备案和公安联网备案
阿里云·云计算
无关868816 小时前
Spring Boot 项目标准化部署打包实战
java·spring boot·后端
jay神16 小时前
基于微信小程序课外创新实践学分认定系统
java·spring boot·小程序·vue·毕业设计
阿丰资源16 小时前
基于Spring Boot的酒店客房管理系统
java·spring boot·后端
zzqssliu17 小时前
SpringBoot框架搭建跨境独立站|Taocarts代购系统订单模块深度开发
java·spring boot·后端
武子康17 小时前
Java-219 RocketMQ Spring Boot 集成指南:生产者与消费者实战
java·spring boot·分布式·kafka·消息队列·rocketmq·java-rocketmq
阿里云云原生18 小时前
阿里云的 Agent Infra 长什么样
阿里云·云计算·agent
想学习java初学者18 小时前
SpringBoot整合GS1编码解码
java·spring boot·后端