苍穹外卖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);
    }

相关推荐
猴哥源码29 分钟前
基于Java+SpringBoot的健身房管理系统
java·spring boot
猴哥源码38 分钟前
基于Java+SpringBoot的三国之家网站
java·spring boot
Spirit_NKlaus1 小时前
解决HttpServletRequest无法获取@RequestBody修饰的参数
java·spring boot·spring
不死的精灵1 小时前
【Java21】在spring boot中使用ScopedValue
java·spring boot·后端
我是小bā吖3 小时前
阿里云服务网格ASM实践
网络·阿里云·云计算·服务发现
仰望星空@脚踏实地4 小时前
Spring Boot Web 服务单元测试设计指南
spring boot·后端·单元测试
一勺菠萝丶5 小时前
Spring Boot + MyBatis/MyBatis Plus:XML中循环处理List参数的终极指南
xml·spring boot·mybatis
保持学习ing5 小时前
苍穹外卖day3--公共字段填充+新增菜品
java·阿里云·实战·springboot·前后端·外卖项目·阿里云文件存储
RainbowSea7 小时前
问题:后端由于字符内容过长,前端展示精度丢失修复
java·spring boot·后端
风象南7 小时前
SpringBoot 控制器的动态注册与卸载
java·spring boot·后端