用户下单与微信支付
一.用户下单
1.1 订单表的设计
订单功能是一个核心的功能;
需要使用2张表:
1.订单表:记录一些订单信息,比如收货人,收获地址,支付金额,下单时间等;
2.订单详情表:记录订单上主要商品的信息,比如:套餐,菜品等;
设计订单表:
设计订单详情表:
由于一张订单上可能有多个商品(商品可以是菜品也可以是套餐);而每一个商品对应一个订单详情表,所以订单表与订单详情表是一对多的关系;
1.2 用户下单的DTO
用户下单时必然提交的数据是:
地址簿ID addressBookId,用于关联地址簿表获取地址信息;
总金额amount;
配送状态deliveryStatus;
预计送达时间estimatedDeliveryTime;
打包费packAmount;
备注remark;
餐具数量tablewareNumber;
餐具数量状态tablewareStatus;
1.3 用户下单之后返回的VO
订单ID
订单号;
订单金额;
下单时间;
1.4 用户下单处理流程
1.接收参数ordersSubmitDTO
2.处理可能出现的异常
3.向订单表插入一条数据
4.向订单明细表插入多条数据
5.用户下单成功之后,清空购物车
6.封装VO返回结果
//业务层核心代码
@Override
public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {//处理各种业务异常AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());//用户地址不能为空if (addressBook==null)throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);//用户购物车不能为空,查询当前用户的购物车数据;Long userId= BaseContext.getCurrentId();ShoppingCart shoppingCart=new ShoppingCart();shoppingCart.setUserId(userId);List<ShoppingCart> shoppingCartList = shoppingCartMapper.list(shoppingCart);if (shoppingCartList==null||shoppingCartList.size()==0)throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);//向订单表插入一条数据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);//在使用mapper操作数据库时,由于后边需要使用orderId,因此需要再orderMapper插入数据库时返回主键值;orderMapper.insert(orders);List<OrderDetail> orderDetails=new ArrayList<>();//向订单明细表插入多条数据for (ShoppingCart cart:shoppingCartList){OrderDetail orderDetail=new OrderDetail();BeanUtils.copyProperties(shoppingCart,orderDetail);orderDetail.setOrderId(orders.getId());orderDetails.add(orderDetail);}orderDetailMapper.insertBatch(orderDetails);//用户下单成功之后,清空购物车shoppingCartMapper.deleteByUserId(userId);//封装VO返回结果OrderSubmitVO orderSubmitVO=OrderSubmitVO.builder().id(orders.getId()).orderTime(orders.getOrderTime()).orderNumber(orders.getNumber()).orderAmount(orders.getAmount()).build();return orderSubmitVO;
}
二.微信支付
由于需要商户开通才能使用微信支付,因此个人项目可以模拟微信支付;
2.1导入微信支付相关代码
不用修改配置文件application.yml与application-dev.yml;
涉及微信支付工具类的代码已经给出:位于模块sky-common下的com.sky.utils的WeChatPayUtil下;
点击“去支付”之后,执行了submit提交订单相关操作之后,显示如下:
点击“确认支付”,发送请求,请求地址为/user/order/payment,调用payment接口,调用业务层接口,并返回OrderPaymentVO对象:
private String nonceStr; //随机字符串private String paySign; //签名private String timeStamp; //时间戳private String signType; //签名算法private String packageStr; //统一下单接口返回的 prepay_id 参数值
/*** 订单支付** @param ordersPaymentDTO* @return*/@PutMapping("/payment")@ApiOperation("订单支付")public Result<OrderPaymentVO> payment(@RequestBody OrdersPaymentDTO ordersPaymentDTO) throws Exception {log.info("订单支付:{}", ordersPaymentDTO);OrderPaymentVO orderPaymentVO = orderService.payment(ordersPaymentDTO);//模拟交易成功orderService.paySuccess(ordersPaymentDTO.getOrderNumber());return Result.success(orderPaymentVO);}
修改业务层的payment方法中的部分代码:
正常获取当前登陆用户id,但是这里不调用微信支付的接口,而是直接生成一个空的jsonObject对象;在进行相应的赋值之后,获得的OrderPaymentVO对象仍然为空;
此时,模拟交易成功,直接调用业务层的交易成功的方法,并将“交易成功”的订单号传入;
而交易成功的业务层方法会直接修改订单的状态;
/*** 订单支付** @param ordersPaymentDTO* @return*/public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {// 当前登录用户idLong userId = BaseContext.getCurrentId();User user = userMapper.getById(userId);//调用微信支付接口,生成预支付交易单
// JSONObject jsonObject = weChatPayUtil.pay(
// ordersPaymentDTO.getOrderNumber(), //商户订单号
// new BigDecimal(0.01), //支付金额,单位 元
// "苍穹外卖订单", //商品描述
// user.getOpenid() //微信用户的openid
// );//生成空jsonObjectJSONObject 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;}
交易成功调用方法;
/*** 支付成功,修改订单状态** @param outTradeNo*/public void paySuccess(String outTradeNo) {// 当前登录用户idLong userId = BaseContext.getCurrentId();// 根据订单号查询当前用户的订单Orders ordersDB = orderMapper.getByNumberAndUserId(outTradeNo, userId);// 根据订单id更新订单的状态、支付方式、支付状态、结账时间Orders orders = Orders.builder().id(ordersDB.getId()).status(Orders.TO_BE_CONFIRMED).payStatus(Orders.PAID).checkoutTime(LocalDateTime.now()).build();orderMapper.update(orders);}
提示支付成功
另外,前端代码也需要略作修改:
直接打开pay目录下的index.js,ctrf+f查找handleSave
将支付成功下边调用wx.requestPayment({})方法直接注释掉即可,
// wx.requestPayment({// nonceStr: res.data.nonceStr,// package: res.data.packageStr,// paySign: res.data.paySign,// timeStamp: res.data.timeStamp,// signType: res.data.signType,// success: function (res) {// 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 });