赞
踩
最近第一次接触到微信支付,踩了很多坑,赶紧写下来,全是心酸和眼泪。话不多说。开始展示。
项目中使用的接入方式是JSAPI(参考 产品中心 - 微信支付商户平台),当然也可以使用其他接入方式,根据需求来。
微信支付提供了两种对接方式(SDK,工具 | 微信支付商户平台文档中心)。一种是SDK,一种是Client,我个人偏向于SDK,因为它更简单,基本都封装好了。
项目中我们选择的非官方SDK binarywang,没什么别的原因,主要是更方便。
官网:Binary Wang;
GitHub:GitHub - binarywang/weixin-java-pay-demo: 基于Spring Boot 和 WxJava 实现的微信支付Java后端Demo
接入前需要创建账号等步骤,可以参考官方文档:JSAPI支付-接入前准备 | 微信支付商户平台文档中心x
- <dependency>
- <groupId>com.github.binarywang</groupId>
- <artifactId>weixin-java-mp</artifactId>
- </dependency>
- <dependency>
- <groupId>com.github.binarywang</groupId>
- <artifactId>weixin-java-pay</artifactId>
- </dependency>
因为支付会有回调和退款等操作,本地接口不能被访问。建议使用内网穿透工具进行测试(Sunny-Ngrok内网转发内网穿透 - 国内内网映射服务器)
wechat-pay: #商户id mchId: 111111 #公众号appid appid: wxce9662d47d419qwvw #APIv3密钥 apiV3key: oLV98ZUF1Kdsfwefgwq7nCazqpew #商户证书序列号 serialNo: 234235r598C803FersvdvB380A4F9CA77C8538AE7F #商户私钥 privateKeyPath: E:/Project/devOps/key/apiclient_key.pem privateCertPath: E:/Project/devOps/key/apiclient_cert.pem #接收结果通知地址 notifyUrl: http://howfhu.frfe.idcwfwgye.com/notify/pay/wx #退款通知地址 refundNotifyUrl: http://hu.free.idefengye.com/notify/refund/wx
订单表
退款表 支付单表
订单与支付单和退款单关系为一对多 不同用户扫码会产生多个支付记录,同样退款有多个退款记录。业务代码需要做支付幂等,同一笔不允许重复支付,重复支付需要调用退款接口。
- @Api(tags = "订单管理")
- @RestController
- public class OrderController {
- @Autowired
- private OrderService orderService;
-
- @Operation(summary = "提交订单")
- @PostMapping("/order/create")
- public BizResult<String> createOrder(@Valid @RequestBody OrderCreateReq req) {
- String orderNO = orderService.createOrder(req);
- return BizResult.create(orderNO);
- }
-
- @Operation(summary = "订单详情")
- @GetMapping("/order/detail")
- public BizResult<OrderRsp> orderDetail(@RequestParam String orderNo) {
- OrderRsp orderRsp = orderService.orderDetail(orderNo);
- return BizResult.create(orderRsp);
- }
-
- @Operation(summary = "轮询订单")
- @GetMapping("/order/polling")
- public BizResult<Boolean> pollingOrder(@RequestParam String orderNo) {
- Boolean result = orderService.pollingOrder(orderNo);
- return BizResult.create(result);
- }
-
- @Operation(summary = "订单列表")
- @PostMapping("/order/list")
- public BizResult<PageData<OrderListRsp>> queryOrderList(@RequestBody OrderListReq req) {
- req.check();
- PageData<OrderListRsp> pageData = orderService.queryOrderList(req);
- return BizResult.create(pageData);
- }
-
- }

- @Slf4j
- @Service
- public class OrderService {
-
-
- /**
- * 创建订单
- */
- @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
- public String createOrder(OrderCreateReq req)
-
- //判断用户是否短时间多次提交
- // 加锁 RLock rLock
-
- try {
- //查询商品是否存在 不存在处理异常
- OrderDO orderDO = OrderConverter.init(req, traceCodeGoodsDO, merchantDO, orderTypeEnum);
- orderMapper.insert(orderDO);
- return orderDO.getOrderNo();
- } finally {
- if (rLock.isHeldByCurrentThread()) {
- rLock.unlock();
- }
- }
- }
-
-
- /**
- * 查询订单详情
- */
- public OrderRsp orderDetail(String orderNo) {
- if (StringUtils.isBlank(orderNo)) {
- throw BizException.create(BaseErrorCodeEnum.PARAMS_ERROR, "订单号不存在");
- }
- //查询订单
- OrderDO orderDO = orderMapper.findByOrderNo(orderNo);
- if (Objects.isNull(orderDO)) {
- throw BizException.create(BizErrorCodeEnum.ORDER_NOT_EXITS);
- }
- return OrderConverter.toOrderRsp(orderDO);
- }
-
-
- /**
- * 订单轮询 前端轮询这个接口 判断当前订单状态 进行响应状态修改
- */
- @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
- public Boolean pollingOrder(String orderNo) {
- if (StringUtils.isBlank(orderNo)) {
- throw BizException.create(BaseErrorCodeEnum.PARAMS_ERROR, "订单号不存在");
- }
- OrderDO orderDO = orderMapper.findByOrderNo(orderNo);
- if (Objects.isNull(orderDO)) {
- throw BizException.create(BizErrorCodeEnum.ORDER_NOT_EXITS);
- }
- //状态支付中 将状态改为未支付
- if (Objects.equals(orderDO.getStatus(), OrderStatusEnum.PAYING.getCode())) {
- orderMapper.updateStatus(orderNo, OrderStatusEnum.UNPAID.getCode(), orderDO.getStatus());
- return false;
- }
- //未支付
- if (Objects.equals(orderDO.getStatus(), OrderStatusEnum.UNPAID.getCode())) {
- return false;
- }
- String payNo = orderDO.getPayNo();
- if (StringUtils.isBlank(payNo)) {
- return false;
- }
- //查询支付单是否存在
- PaymentDO paymentDO = paymentMapper.findByPayNo(payNo);
- if (Objects.isNull(paymentDO)) {
- log.error("轮询订单,支付单不存在。orderNo:{},payNo:{}", orderDO, payNo);
- return false;
- }
- if (!Objects.equals(orderDO.getStatus(), OrderStatusEnum.UNPAID.getCode()) && !Objects.equals(orderDO.getStatus(), OrderStatusEnum.PAYING.getCode())) {
- // 查询需要取消支付单记录
- List<PaymentDO> paymentList = paymentMapper.queryPaymentList(orderDO.getOrderNo(), PayStatusEnum.UNPAID.getCode(), paymentDO.getPayNo());
- if (ObjectUtil.isNotEmpty(paymentList)) {
- // 修改支付单取消状态
- paymentMapper.cancelPay(orderDO.getOrderNo(), PayStatusEnum.CANCEL.getCode(), paymentDO.getPayNo(), PayStatusEnum.UNPAID.getCode());
- }
- return true;
- }
- PayStatusEnum payStatusEnum = LocalEnumUtils.findByCodeWithoutDefault(PayStatusEnum.class, paymentDO.getStatus());
- if (Objects.equals(payStatusEnum, PayStatusEnum.CANCEL)
- || Objects.equals(payStatusEnum, PayStatusEnum.FAIL)) {
- //取消支付或支付失败,可重新扫码创建支付单
- return false;
- } else if (Objects.equals(payStatusEnum, PayStatusEnum.UNPAID)) {
- //支付单待支付,查询第三方渠道
- WxPayOrderQueryV3Result wxPayOrderQueryV3Result = null;
- try {
- WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request();
- request.setOutTradeNo(paymentDO.getPayNo());
- wxPayOrderQueryV3Result = wxManager.getWxPayService().queryOrderV3(request);
- } catch (WxPayException e) {
- log.error("查询微信支付订单失败。payNo:{}", paymentDO.getPayNo(), e);
- return false;
- }
- //查询第三方支付信息并更新订单
- if (orderManager.queryOrderByWx(wxPayOrderQueryV3Result, orderDO, paymentDO, payStatusEnum)) {
- producerHelper.sendOrderMsg(orderDO);
- return true;
- }
- } else {
- //其他状态,更新订单状态。
- int orgOrderStatus = orderDO.getStatus();
- OrderStatusEnum tarOrderStatus = OrderStatusEnum.PAID;
- if (Objects.equals(payStatusEnum, PayStatusEnum.REFUND)) {
- tarOrderStatus = OrderStatusEnum.REFUND;
- orderDO.setRefundTime(paymentDO.getRefundTime());
- orderDO.setRefundAmount(paymentDO.getRefundAmount());
- }
- orderDO.setFinishTime(paymentDO.getPayTime());
- orderDO.setStatus(tarOrderStatus.getCode());
- orderDO.setUpdateTime(new Date());
- int i = orderMapper.updateStatusByOrderNo(orderDO, orgOrderStatus);
- if (i > 0) {
- producerHelper.sendOrderMsg(orderDO);
- }
- return true;
- }
- return false;
- }
-
- /**
- * jsapi下单并返回前端唤起参数
- */
- @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
- public OrderJsApiRsq jsapiPay(JsAPIReq req) {
- String orderNo = req.getOrderNo();
- String openId = req.getOpenid();
- // 加锁 RLock lock
- if (lock == null) {
- throw BizException.create(CommonErrorCodeEnum.RESUBMIT_ERROR, "订单支付中");
- }
- //查询订单
- OrderDO orderDO = orderMapper.findByOrderNo(orderNo);
- if (Objects.isNull(orderDO)) {
- throw BizException.create(BizErrorCodeEnum.ORDER_NOT_EXITS);
- }
- Integer orgStatus = orderDO.getStatus();
- //校验重复支付
- if (Objects.equals(orgStatus, OrderStatusEnum.PAID.getCode())) {
- throw BizException.create(BizErrorCodeEnum.ORDER_PAY, "订单已支付,请勿重复支付");
- }
- // 查询支付单,没有则新增
- // 对比openid,如果一样直接发起支付,不一样新增支付单
- PaymentDO paymentDO = paymentMapper.findByPayNo(orderDO.getPayNo());
- if (Objects.isNull(paymentDO) || !Objects.equals(paymentDO.getOpenid(), req.getOpenid())) {
- //插入支付单数据
- paymentMapper.insert(paymentDO);
- //更新订单号中支付单号
-
- // 幂等更新
- int i = orderMapper.updateStatusByOrderNo(orderDO, orgStatus);
- if (i == 0) {
- throw BizException.create(BizErrorCodeEnum.ORDER_PAY, "订单已支付");
- }
- }
-
- WxPayUnifiedOrderV3Request request = WxPayConverter.toWxPayUnifiedOrderV3Request(orderDO, paymentDO.getPayNo(), openId);
- WxPayUnifiedOrderV3Result.JsapiResult result = null;
- try {
- result = wxManager.getWxPayService().createOrderV3(TradeTypeEnum.JSAPI, request);
- } catch (WxPayException e) {
- log.error("JSAPI下单支付异常,orderNo:{}", orderNo, e);
- throw BizException.create(BizErrorCodeEnum.ORDER_UNIFIED_ERROR, "支付唤起失败");
- } finally {
- if (lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- return WxPayConverter.toOrderJsApiRsq(result);
- }
-
- /**
- * 支付通知
- */
- @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
- public OrderPayNotify payNotify(JSONObject jsonObject, HttpServletRequest request, HttpServletResponse response) {
- log.info("微信支付结果通知:{}", jsonObject);
- //获取请求头
- SignatureHeader header = PayUtil.getWXRequestHeader(request);
- //请求体
- //解析回调通知
- WxPayOrderNotifyV3Result wxPayOrderNotifyV3Result = getWxPayOrderNotifyV3Result(jsonObject, header);
- WxPayOrderNotifyV3Result.DecryptNotifyResult result = wxPayOrderNotifyV3Result.getResult();
- WxPayTradeStateEnum wxPayStatus = WxPayTradeStateEnum.findByCode(result.getTradeState());
- //中间态,直接返回,继续通知
- if (Objects.equals(wxPayStatus, WxPayTradeStateEnum.NOT_PAY)
- || Objects.equals(wxPayStatus, WxPayTradeStateEnum.ACCEPT)
- || Objects.equals(wxPayStatus, WxPayTradeStateEnum.USER_PAYING)) {
- log.error("微信支付回调,中间态继续通知,payNo:{}", wxPayOrderNotifyV3Result.getResult().getOutTradeNo());
- response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
- return OrderPayNotify.fail();
- }
- //加锁RLock lock
- if (lock == null) {
- throw BizException.create(BizErrorCodeEnum.PAY_FAIL);
- }
- try {
- //查询支付单
- PaymentDO paymentDO
- log.info("支付单结果解析:{},支付单号{}", paymentDO, paymentDO.getPayNo());
- //查询订单
- OrderDO orderDO
- log.info("订单结果解析:{},支付单号{}", orderDO, orderDO.getOrderNo());
- Integer status = paymentDO.getStatus();
- //订单已支付 订单状态不等于未支付和支付中
- if (!Objects.equals(orderDO.getStatus(), OrderStatusEnum.UNPAID.getCode())) {
- if (!Objects.equals(orderDO.getStatus(), OrderStatusEnum.PAYING.getCode())) {
- //订单已支付 判断是否同一支付单, 是则表示同一笔订单重复支付
- if (!Objects.equals(orderDO.getPayNo(), paymentDO.getPayNo())) {
- //支付通知状态
- RefundDO refundDO = null;
- if (Objects.equals(wxPayStatus, WxPayTradeStateEnum.SUCCESS)) {
- //重复支付,新增退款记录
- refundDO = RefundConverter.init(paymentDO);
- refundMapper.insert(refundDO);
- paymentDO.setRefundTime(refundDO.getRefundTime());
- paymentDO.setRefundAmount(refundDO.getRefundAmount());
- //申请退款
- WxPayRefundV3Request wxPayRefundV3Request = WxPayConverter.toWxPayRefundV3(refundDO);
- wxPayRefundV3Request.setNotifyUrl(wxPayProperties.getRefundNotifyUrl());
- WxPayRefundV3Result wxPayRefundV3Result = wxManager.getWxPayRefundService().refundV3(wxPayRefundV3Request);
- log.info("申请退款结果解析:{}", wxPayRefundV3Result);
- }
- //更新支付单
- paymentDO.setStatus(PayStatusEnum.REFUNDING.getCode());
- paymentMapper.updatePayStatus(paymentDO, status);
- response.setStatus(HttpStatus.SC_OK);
- return OrderPayNotify.success();
- }
- response.setStatus(HttpStatus.SC_OK);
- return OrderPayNotify.success();
- }
- }
- //未支付订单
- //更新订单和支付单状态
- if (orderManager.payNotify(result, orderDO, paymentDO, wxPayStatus)) {
- //生成码包
- producerHelper.sendOrderMsg(orderDO);
- }
- response.setStatus(HttpStatus.SC_OK);
- return OrderPayNotify.success();
- } catch (Exception e) {
- log.error("微信回调结果异常,第三方流水号{},异常支付单号{}", result.getTransactionId(), wxPayOrderNotifyV3Result.getResult().getOutTradeNo(), e);
- response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
- return OrderPayNotify.fail();
- } finally {
- if (lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- }
-
- /**
- * 退款通知
- */
- @Transactional(rollbackFor = Exception.class)
- public OrderPayNotify payRefundNotify(JSONObject jsonObject, HttpServletRequest request, HttpServletResponse response) {
- //获取请求头
- SignatureHeader header = PayUtil.getWXRequestHeader(request);
- //解析回调
- WxPayRefundNotifyV3Result wxPayRefundNotifyV3Result = getWxPayRefundNotifyV3Result(jsonObject, header);
- WxPayRefundNotifyV3Result.DecryptNotifyResult result = wxPayRefundNotifyV3Result.getResult();
- log.info("微信退款结果通知:{}", result);
- WxPayRefundStateEnum wxPayRefundStateEnum = WxPayRefundStateEnum.findByCode(result.getRefundStatus());
- //退款关闭或者退款异常,直接返回,继续通知
- if (Objects.equals(wxPayRefundStateEnum, WxPayRefundStateEnum.CLOSED) || Objects.equals(wxPayRefundStateEnum, WxPayRefundStateEnum.ABNORMAL)
- ) {
- log.error("微信退款异常回调,退款单号,refundNo:{}", result.getOutRefundNo());
- response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
- return OrderPayNotify.fail();
- }
- //加锁 RLock lock
- if (lock == null) {
- throw BizException.create(BizErrorCodeEnum.REFUND_NOTIFY_FAIL);
- }
- try {
- //查询退款单
- RefundDO refundDo
- log.info("微信退款单解析:{},退款单号", refundDo, refundDo.getRefundNo());
- //查询支付单
- PaymentDO payment
- log.info("支付单结果解析:{},支付单号{}", payment, payment.getPayNo());
- //查询订单
- OrderDO order
- log.info("订单结果解析:{},订单号{}", order, order.getOrderNo());
-
- Integer paymentStatus = payment.getStatus();
- Integer orderStatus = order.getStatus();
- Integer refundStatus = refundDo.getStatus();
-
- //退款单状态退款中 并且退款通知成功 更新支付单和退款单
- if (Objects.equals(refundStatus, RefundStateEnum.REFUNDING.getCode())) {
- //更新退款单
- if (!Objects.equals(refundStatus, RefundStateEnum.SUCCESS.getCode())) {
- refundDo = RefundConverter.toRefund(wxPayRefundNotifyV3Result, refundDo);
- int r = refundMapper.updateStatus(refundDo, refundStatus);
- if (r == 0) {
- throw BizException.create(BizErrorCodeEnum.REFUND_UPDATE_FAIL, "退款单更新失败");
- }
- }
- //更新支付单
- payment.setStatus(PayStatusEnum.REFUND.getCode());
- payment.setRefundTime(DateUtil.parse(result.getSuccessTime()));
- BigDecimal refundAmount = LocalMoneyUtils.fen2yuan(Long.valueOf(result.getAmount().getRefund()));
- payment.setPayAmount(refundAmount);
- int p = paymentMapper.updatePayStatus(payment, paymentStatus);
- if (p == 0) {
- throw BizException.create(BizErrorCodeEnum.PAYMENT_UPDATE_FAIL, "支付单状态更新失败");
- }
- response.setStatus(HttpStatus.SC_OK);
- return OrderPayNotify.success();
- }
- response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
- return OrderPayNotify.fail();
- } catch (Exception e) {
- response.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
- return OrderPayNotify.fail();
- } finally {
- if (lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- }
-
- /**
- * 订单列表
- */
- public PageData<OrderListRsp> queryOrderList(OrderListReq req, MerchantContext loginUser) {
- Long count = orderMapper.orderTotal(req, loginUser.getMerchantId());
- if (count <= 0) {
- return PageData.create(Lists.newArrayList(), count, req.getPage(), req.getSize());
- }
- List<OrderDO> orderList = orderMapper.queryOrderList(req, loginUser.getMerchantId());
- List<OrderListRsp> OrderRsp = OrderConverter.toOrderListReq(orderList);
- return PageData.create(OrderRsp, count, req.getPage(), req.getSize());
- }
-
- /**
- * 关闭订单
- */
- @Transactional(rollbackFor = Exception.class)
- public boolean closeOrder(String orderNo) throws WxPayException {
- //查询订单是否已支付
- OrderDO orderDO = orderMapper.findByOrderNo(orderNo);
- if (!OrderStatusEnum.UNPAID.getCode().equals(orderDO.getStatus())) {
- return false;
- }
- Date expireTime = orderDO.getExpireTime();
- Date date = new Date();
- if (expireTime.compareTo(date) > 0) {
- //时间未到
- return false;
- }
-
- log.info("订单超期关闭,单号为{}", orderDO.getOrderNo());
- orderDO.setCloseTime(date);
- orderDO.setUpdateTime(date);
- orderDO.setStatus(OrderStatusEnum.CLOSED.getCode());
- int i = orderMapper.updateStatusByOrderNo(orderDO, OrderStatusEnum.UNPAID.getCode());
- if (i == 0) {
- //订单状态以改变
- return false;
- }
- //关闭支付单
- PaymentDO paymentDO = paymentMapper.findByPayNo(orderDO.getPayNo());
- if (Objects.isNull(paymentDO)) {
- return false;
- }
- //更新支付单
- Integer payStatus = paymentDO.getStatus();
- paymentDO.setStatus(PayStatusEnum.CANCEL.getCode());
- paymentDO.setUpdateTime(date);
- paymentMapper.updatePayStatus(paymentDO, payStatus);
- //第三方渠道关单
- WxPayOrderCloseV3Request request = new WxPayOrderCloseV3Request();
- request.setOutTradeNo(paymentDO.getPayNo());
- wxManager.getWxPayService().closeOrderV3(request);
- return true;
- }
-
- /**
- * 解析微信支付回调通知
- */
- private WxPayOrderNotifyV3Result getWxPayOrderNotifyV3Result(JSONObject jsonObject, SignatureHeader header) {
-
- WxPayOrderNotifyV3Result wxPayOrderNotifyV3Result = null;
- try {
- wxPayOrderNotifyV3Result = wxManager.getWxPayService().parseOrderNotifyV3Result(jsonObject.toJSONString(), header);
- log.info("微信支付结果解析:{}", wxPayOrderNotifyV3Result.getResult());
- } catch (Exception e) {
- log.info("微信支付结果异常解析:{},异常信息{}", wxPayOrderNotifyV3Result.getResult(), e);
- }
- return wxPayOrderNotifyV3Result;
- }
-
- /**
- * 解析微信退款回调通知
- */
- private WxPayRefundNotifyV3Result getWxPayRefundNotifyV3Result(JSONObject jsonObject, SignatureHeader header) {
-
- WxPayRefundNotifyV3Result wxPayRefundNotifyV3Result = null;
- try {
- wxPayRefundNotifyV3Result = wxManager.getWxPayRefundService().parseRefundNotifyV3Result(jsonObject.toJSONString(), header);
- log.info("微信退款结果解析:{}", wxPayRefundNotifyV3Result.getResult());
- } catch (WxPayException e) {
- log.info("微信退款结果异常解析:{},异常信息{}", wxPayRefundNotifyV3Result.getResult(), e);
- }
- return wxPayRefundNotifyV3Result;
- }
- }

- @Slf4j
- @Component
- public class WxManager {
-
- @Autowired
- WxPayProperties wxPayProperties;
- @Resource
- private RedissonClient redissonClient;
- @Autowired
- private WxMpProperties wxMpProperties;
-
- public WxMpService getWxMpService() {
- WxMpRedissonConfigImpl config = new WxMpRedissonConfigImpl(redissonClient, CommonConstants.NAMESPACE);
- config.setAppId(wxMpProperties.getAppId());
- config.setSecret(wxMpProperties.getSecret());
-
- WxMpService service = new WxMpServiceImpl();
- service.setWxMpConfigStorage(config);
- return service;
- }
-
- public WxPayService getWxPayService() {
- WxPayConfig payConfig = new WxPayConfig();
- payConfig.setAppId(wxPayProperties.getAppid());
- payConfig.setMchId(wxPayProperties.getMchId());
- payConfig.setPrivateKeyPath(wxPayProperties.getPrivateKeyPath());
- payConfig.setNotifyUrl(wxPayProperties.getNotifyUrl());
- payConfig.setApiV3Key(wxPayProperties.getApiV3key());
- payConfig.setPrivateCertPath(wxPayProperties.getPrivateCertPath());
- WxPayService wxPayService = new WxPayServiceImpl();
- wxPayService.setConfig(payConfig);
- return wxPayService;
- }
-
- public WxPayService getWxPayRefundService() {
- WxPayConfig payConfig = new WxPayConfig();
- payConfig.setAppId(wxPayProperties.getAppid());
- payConfig.setMchId(wxPayProperties.getMchId());
- payConfig.setPrivateKeyPath(wxPayProperties.getPrivateKeyPath());
- payConfig.setNotifyUrl(wxPayProperties.getRefundNotifyUrl());
- payConfig.setApiV3Key(wxPayProperties.getApiV3key());
- payConfig.setPrivateCertPath(wxPayProperties.getPrivateCertPath());
- WxPayService wxPayService = new WxPayServiceImpl();
- wxPayService.setConfig(payConfig);
- return wxPayService;
- }
-
-
- }

- @Slf4j
- @Component
- public class OrderManager {
- @Autowired
- OrderMapper orderMapper;
- @Autowired
- PaymentMapper paymentMapper;
- @Autowired
- WxManager wxManager;
-
- /**
- * 查询第三方支付,更新订单
- *
- * @param orderDO
- * @param paymentDO
- */
- @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
- public Boolean queryOrderByWx(WxPayOrderQueryV3Result wxPayOrderQueryV3Result, OrderDO orderDO, PaymentDO paymentDO, PayStatusEnum payStatusEnum) {
- //未支付 支付中 等待扣款 直接返回
- WxPayTradeStateEnum wxPayTradeStateEnum = WxPayTradeStateEnum.findByCode(wxPayOrderQueryV3Result.getTradeState());
- if (Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.NOT_PAY)
- || Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.ACCEPT)
- || Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.USER_PAYING)) {
- return false;
- }
-
- if (!wxPayOrderQueryV3Result.getPayer().getOpenid().equals(paymentDO.getOpenid())) {
- //记录日志,更新openid
- log.error("查询微信支付,openid与本地不一致,paymentDO:{},payer:{}", paymentDO, wxPayOrderQueryV3Result.getPayer());
- }
- //更新支付单状态
- paymentDO = PaymentConverter.toPaymentByWxPayOrderQueryV3Result(wxPayOrderQueryV3Result, paymentDO);
- int p = paymentMapper.updatePayStatus(paymentDO, payStatusEnum.getCode());
- if (p == 0) {
- throw BizException.create(BizErrorCodeEnum.PAYMENT_UPDATE_FAIL, "支付单状态更新失败");
- }
- //已关闭 已撤销 支付失败 不更新订单状态 可重新支付
- if (Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.CLOSED)
- || Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.REVOKED)
- || Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.PAY_ERROR)) {
- return false;
- }
- //更新订单状态 幂等
- int orgOrderStatus = orderDO.getStatus();
- orderDO = OrderConverter.toOrderByPayment(paymentDO, orderDO, payStatusEnum);
- int o = orderMapper.updateStatusByOrgStatus(orderDO, orgOrderStatus);
- if (o == 0) {
- throw BizException.create(BizErrorCodeEnum.ORDER_UPDATE_FAIL, "订单状态更新失败");
- }
- return true;
- }
-
- /**
- * 支付回调 更新订单
- */
- public Boolean payNotify(WxPayOrderNotifyV3Result.DecryptNotifyResult result, OrderDO order, PaymentDO payment, WxPayTradeStateEnum wxPayTradeStateEnum) {
- if (!result.getPayer().getOpenid().equals(payment.getOpenid())) {
- //记录日志
- log.error("查询微信支付,openid与本地不一致,paymentDO:{},payer:{}", payment, result.getPayer());
- }
- PayStatusEnum payStatusEnum = LocalEnumUtils.findByCodeWithoutDefault(PayStatusEnum.class, payment.getStatus());
- Integer orderStatus = order.getStatus();
- //非 未支付 代扣款 支付中 更新支付单信息
- if (Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.NOT_PAY)
- || Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.ACCEPT)
- || Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.USER_PAYING)) {
- return false;
- }
- //更新支付单
- payment = PaymentConverter.fromWxPayOrderNotifyV3Result(result, payment);
- int p = paymentMapper.updatePayStatus(payment, payStatusEnum.getCode());
- if (p == 0) {
- throw BizException.create(BizErrorCodeEnum.PAYMENT_UPDATE_FAIL, "支付单状态更新失败");
- }
- //已关闭 已撤销 支付失败 不更新订单状态 可重新支付
- if (Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.CLOSED)
- || Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.REVOKED)
- || Objects.equals(wxPayTradeStateEnum, WxPayTradeStateEnum.PAY_ERROR)) {
- return false;
- }
- PayStatusEnum statusEnum = LocalEnumUtils.findByCodeWithoutDefault(PayStatusEnum.class, payment.getStatus());
- //更新订单状态 幂等
- order = OrderConverter.toOrderByPayment(payment, order, statusEnum);
- int o = orderMapper.updateStatusByOrgStatus(order, orderStatus);
- if (o == 0) {
- throw BizException.create(BizErrorCodeEnum.ORDER_UPDATE_FAIL, "订单状态更新失败");
- }
- return true;
- }
- }

- @Data
- @Component
- @Configuration
- @ConfigurationProperties(prefix = "wechat-pay")
- public class WxPayProperties {
- /**
- * 商户号
- */
- private String mchId;
- /**
- * 证书解密的密钥
- */
- private String apiV3key;
- /**
- * 商户私钥文件
- */
- private String privateKeyPath;
-
- /**
- * apiclient_cert.pem证书文件
- */
- private String privateCertPath;
-
- /**
- * 商户证书序列号
- */
- private String serialNo;
- /**
- * 赋选供应链 服务号appid
- */
- private String appid;
- /**
- * 支付回调通知地址
- */
- private String notifyUrl;
-
- /**
- * 退款回调通知地址
- */
- private String refundNotifyUrl;
- }

以上就是核心业务代码,涉及到具体业务mapper没有放上来,但是核心的处理步骤已经体现出来了。主要是对订单状态需要仔细判断,不同操作会引起状态的变更。业务中,当多个人扫同一个码,后续扫码成功会调用退款接口。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。