用户下单与微信支付
一.用户下单
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 {
// 当前登录用户id
Long userId = BaseContext.getCurrentId();
User user = userMapper.getById(userId);
//调用微信支付接口,生成预支付交易单
// JSONObject jsonObject = weChatPayUtil.pay(
// ordersPaymentDTO.getOrderNumber(), //商户订单号
// new BigDecimal(0.01), //支付金额,单位 元
// "苍穹外卖订单", //商品描述
// user.getOpenid() //微信用户的openid
// );
//生成空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;
}
交易成功调用方法;
/**
* 支付成功,修改订单状态
*
* @param outTradeNo
*/
public void paySuccess(String outTradeNo) {
// 当前登录用户id
Long 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 });