一:🚀问题引入
1.1:🥃使用场景
实际场景中会遇到用户下单之后不想要了或者其他原因而申请取消订单,取消订单并不是单单更新商户后台数据库订单状态这么简单,还需要向微信支付后台申请关闭订单服务。有两种情况需要调用微信支付的关单接口,其一就是上面提到的用户主动取消订单,其二就是订单过期自动取消。
1.2:🥫接口说明
- 适用对象:商户端
- 请求URL:https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}/close
- 请求方式:POST
- 请求参数:String类型的直连商户号、String类型的商户订单号(长度为6-32)
1.3:🚨注意事项
关单没有时间限制,建议在订单生成后间隔几分钟(最短5分钟)再调用关单接口,避免出现订单状态同步不及时导致关单失败。
二:🚀处理流程
关闭订单的处理流程比较简单,没有什么逻辑判断,只需要单纯创建远程请求对象然后完成签名并执行请求即可,最后还需要更新订单状态。
三:🚀代码实现
3.1:controller层
/** * 用户取消订单 * @param order * @return */ @ApiOperation("取消订单") @PostMapping("/cancel") public R<String> cancelOrder(@RequestBody Orders order) throws Exception { log.info("取消订单"); wxPayService.cancelOrder(order); return R.success("取消订单成功"); }
3.2:service层
/** * 取消订单 * @param order */ @Override public void cancelOrder(Orders order) throws Exception { //调用微信支付的关单接口 this.closeOrder(order.getNumber()); //更新订单状态 Orders order_temp = ordersService.getById(order.getId()); ordersService.updateStatusByOrderNo(order_temp.getNumber(),"5"); } /** * 关单接口的调用 * @param orderNo */ @Override public void closeOrder(String orderNo) throws Exception { log.info("关单接口的调用,订单号 ===> {}", orderNo); //创建远程请求对象 String url = String.format(WxApiType.CLOSE_ORDER_BY_NO.getType(), orderNo); url = wxPayConfig.getDomain().concat(url); HttpPost httpPost = new HttpPost(url); httpPost.addHeader("Accept", "application/json"); httpPost.addHeader("Content-type","application/json; charset=utf-8"); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectMapper objectMapper = new ObjectMapper(); ObjectNode rootNode = objectMapper.createObjectNode(); rootNode.put("mchid",wxPayConfig.getMchId()); objectMapper.writeValue(bos, rootNode); httpPost.setEntity(new StringEntity(bos.toString(StandardCharsets.UTF_8), "UTF-8")); //完成签名并执行请求 try (CloseableHttpResponse response = wxPayClient.execute(httpPost)) { String jsonString = JSON.toJSONString(response); JSONObject body = JSON.parseObject(jsonString); JSONObject statusLine = body.getJSONObject("statusLine"); String code = statusLine.getString("statusCode"); log.info("关闭订单成功订单号:===>{}", code); } }
在微信支付开发者文档中介绍说关闭订单是没有返回参数的,但是我们可以在response中获取到返回的状态码以判断是否处理成功,执行断点调试可以发现返回状态码为204。
3.3:RabbitmqDelayConsumer
/** * 监听订单延迟队列 * @param orderNo * @throws Exception */ @RabbitListener(queues = {"plugin.delay.order.queue"}) public void orderDelayQueue(String orderNo, Message message, Channel channel) throws Exception { log.info("订单延迟队列开始消费..."); try { //处理订单 wxPayService.checkOrderStatus(orderNo); //告诉服务器收到这条消息 已经被我消费了 可以在队列删掉 这样以后就不会再发了 否则消息服务器以为这条消息没处理掉 后续还会在发 channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); log.info("消息接收成功"); } catch (Exception e) { e.printStackTrace(); //消息重新入队 channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,true); log.info("消息接收失败,重新入队"); } }
四:🚀友情链接
- 微信支付:开发者文档
- 微信支付API v3的Apache HttpClient扩展
- 项目源代码:这是一个链接