diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/NotifyUserCommandController.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/NotifyUserCommandController.java index 74c2cd3..dbfdc30 100644 --- a/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/NotifyUserCommandController.java +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/NotifyUserCommandController.java @@ -1,6 +1,7 @@ package com.qniao.dam.api.command.notify.user; import cn.hutool.core.util.StrUtil; +import com.qniao.dam.api.command.notify.user.response.WeChatNotificationVo; import com.qniao.dam.application.service.notify.NotifyApplicationService; import com.qniao.framework.annotation.IgnoreResponseAdvice; import com.qniao.framework.exception.BizException; @@ -23,12 +24,8 @@ public class NotifyUserCommandController { @RequestMapping("/notify/wx") @IgnoreResponseAdvice - public String wx(HttpServletRequest request) throws IOException { - String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding()); - if (StrUtil.isBlank(xmlResult)) { - throw new BizException("回调内容不能为空"); - } - return notifyApplicationService.wx(xmlResult); + public WeChatNotificationVo wx(HttpServletRequest request){ + return notifyApplicationService.wx(request); } } \ No newline at end of file diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/response/WeChatNotification.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/response/WeChatNotification.java new file mode 100644 index 0000000..21a7e6f --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/response/WeChatNotification.java @@ -0,0 +1,21 @@ +package com.qniao.dam.api.command.notify.user.response; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +public class WeChatNotification { + + private String code; + + private String message; + + @ApiModelProperty("微信支付系统生成的订单号") + private String transactionId; + + @ApiModelProperty("商户系统内部订单号") + private String outTradeNo; + + @ApiModelProperty("支付完成时间") + private String successTime; +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/response/WeChatNotificationVo.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/response/WeChatNotificationVo.java new file mode 100644 index 0000000..8a83bc9 --- /dev/null +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/api/command/notify/user/response/WeChatNotificationVo.java @@ -0,0 +1,11 @@ +package com.qniao.dam.api.command.notify.user.response; + +import lombok.Data; + +@Data +public class WeChatNotificationVo { + private String code = "FAIL"; + + private String message = "失败"; + +} diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/notify/NotifyApplicationService.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/notify/NotifyApplicationService.java index 0d0b171..676d81d 100644 --- a/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/notify/NotifyApplicationService.java +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/notify/NotifyApplicationService.java @@ -6,6 +6,9 @@ import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; +import com.qniao.dam.api.command.notify.user.response.WeChatNotification; +import com.qniao.dam.api.command.notify.user.response.WeChatNotificationVo; +import com.qniao.dam.application.service.paymentchannelorder.processor.wechat.utils.WXPayV3Util; import com.qniao.dam.domain.aggregate.paymentchannelorder.PaymentChannelOrderAggregate; import com.qniao.dam.domain.aggregate.paymentchannelorder.entity.PaymentChannelOrder; import com.qniao.dam.domian.aggregate.paymentchannelorder.constant.PaymentChannelOrderStatusEnum; @@ -13,14 +16,18 @@ import com.qniao.dam.infrastructure.persistent.dao.domain.PaymentChannelOrderDao import com.qniao.domain.BaseApplicationService; import com.qniao.domain.BaseDomainEvent; import com.qniao.framework.exception.BizException; +import com.qniao.framework.utils.TypeConvertUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.math.RoundingMode; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; @Service @Slf4j @@ -34,29 +41,34 @@ public class NotifyApplicationService extends BaseApplicationService { private static final String WX_FAIL_RTN = ""; public static final String RETURN_VALUE_SUCCESS = "SUCCESS"; + public DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + @Resource private PaymentChannelOrderDao paymentChannelOrderDao; @Resource private PaymentChannelOrderAggregate paymentChannelOrderAggregate; + @Resource + private WXPayV3Util wxPayV3Util; - public String wx(String xmlResult) { + public WeChatNotificationVo wx(HttpServletRequest request) { + WeChatNotificationVo notificationVo = new WeChatNotificationVo(); try { - WxPayOrderNotifyResult result = parseOrderNotifyResult(xmlResult); - // 查询订单 - PaymentChannelOrder paymentChannelOrder = paymentChannelOrderDao.selectById(result.getOutTradeNo()); - Assert.notNull(paymentChannelOrder, "支付订单不存在"); - // 验证业务数据是否正确 - checkWxPayParams(result, paymentChannelOrder); - // 更新订单信息 - paymentChannelOrder.setPaidTime(DateUtil.parseLocalDateTime(result.getTimeEnd(), "yyyyMMddHHmmss")); - paymentChannelOrder.setExtOrderNo(result.getTransactionId()); - BaseDomainEvent event = paymentChannelOrderAggregate.paid(paymentChannelOrder); - this.sendEvent(event); - return WX_SUCCESS_RTN; - } catch (WxPayException e) { + WeChatNotification notification = wxPayV3Util.weChatNotificationHandler(request); + notificationVo = TypeConvertUtils.convert(notification, WeChatNotificationVo.class); + if (RETURN_VALUE_SUCCESS.equals(notification.getCode())) { + // 查询订单 + PaymentChannelOrder paymentChannelOrder = paymentChannelOrderDao.selectById(notification.getOutTradeNo()); + Assert.notNull(paymentChannelOrder, "支付订单不存在"); + // 更新订单信息 + paymentChannelOrder.setPaidTime(LocalDateTime.parse(notification.getSuccessTime(), formatter)); + paymentChannelOrder.setExtOrderNo(notification.getTransactionId()); + BaseDomainEvent event = paymentChannelOrderAggregate.paid(paymentChannelOrder); + this.sendEvent(event); + } + } catch (Exception e) { log.error("微信回调结果异常,异常原因", e); } - return WX_FAIL_RTN; + return notificationVo; } private WxPayOrderNotifyResult parseOrderNotifyResult(String xmlResult) throws WxPayException { diff --git a/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/paymentchannelorder/processor/wechat/utils/WXPayV3Util.java b/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/paymentchannelorder/processor/wechat/utils/WXPayV3Util.java index 07a5a26..101c204 100644 --- a/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/paymentchannelorder/processor/wechat/utils/WXPayV3Util.java +++ b/dating-agency-mall-server/src/main/java/com/qniao/dam/application/service/paymentchannelorder/processor/wechat/utils/WXPayV3Util.java @@ -1,12 +1,16 @@ package com.qniao.dam.application.service.paymentchannelorder.processor.wechat.utils; import com.alibaba.fastjson.JSONObject; +import com.qniao.dam.api.command.notify.user.response.WeChatNotification; import com.qniao.framework.exception.BizException; import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; import com.wechat.pay.contrib.apache.httpclient.auth.Verifier; import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials; import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager; +import com.wechat.pay.contrib.apache.httpclient.notification.Notification; +import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler; +import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest; import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; @@ -20,6 +24,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.springframework.util.Base64Utils; +import javax.servlet.http.HttpServletRequest; import java.io.*; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; @@ -226,4 +231,55 @@ public class WXPayV3Util { throw new RuntimeException("无效的密钥格式"); } } + + + public WeChatNotification weChatNotificationHandler(HttpServletRequest request) { + WeChatNotification weChatNotification = new WeChatNotification(); + try { + BufferedReader br = request.getReader(); + String str = null; + StringBuilder sb = new StringBuilder(); + while ((str = br.readLine()) != null) { + sb.append(str); + } + // 构建request,传入必要参数 + NotificationRequest requests = new NotificationRequest.Builder() + .withSerialNumber(request.getHeader("Wechatpay-Serial")) + .withNonce(request.getHeader("Wechatpay-Nonce")) + .withTimestamp(request.getHeader("Wechatpay-Timestamp")) + .withSignature(request.getHeader("Wechatpay-Signature")) + .withBody(String.valueOf(sb)) + .build(); + //验签 + NotificationHandler handler = new NotificationHandler(verifier, v3Key.getBytes(StandardCharsets.UTF_8)); + //解析请求体 + Notification notification = handler.parse(requests); + String decryptData = notification.getDecryptData(); + //解析 + JSONObject jsonObject = JSONObject.parseObject(decryptData); + //支付状态交易状态,枚举值: SUCCESS:支付成功 REFUND:转入退款 NOTPAY:未支付 CLOSED:已关闭 REVOKED:已撤销(付款码支付) + // USERPAYING:用户支付中(付款码支付) PAYERROR:支付失败(其他原因,如银行返回失败) + String trade_state = String.valueOf(jsonObject.get("trade_state")); + if (trade_state.equals("SUCCESS")) { + //订单号 + String outTradeNo = String.valueOf(jsonObject.get("out_trade_no")); + //微信支付微信生成的订单号 + String transactionId = String.valueOf(jsonObject.get("transaction_id")); + //支付时间 + String successTime = String.valueOf(jsonObject.get("success_time")); + weChatNotification.setOutTradeNo(outTradeNo); + weChatNotification.setTransactionId(transactionId); + weChatNotification.setSuccessTime(successTime); + //此处处理业务 + weChatNotification.setCode("SUCCESS"); + weChatNotification.setMessage("成功"); + } else { + weChatNotification.setCode("FAIL"); + weChatNotification.setMessage("失败"); + } + } catch (Exception e) { + e.printStackTrace(); + } + return weChatNotification; + } }