
Java对接微信支付及支付回调通知的全流程
一、所用框架。对接微信支付我们技术组用的是payment框架,因为该框架已整合springboot因此很方便快捷
cn.felord payment-spring-boot-starter 1.0.12.RELEASE
二、YML配置文件参数。我们对接的是微信最新的V3版本支付接口
pay:
v3:
202112:
# 应用appId 服务商模式下为服务商的appid 必填
app-id: XXX
# v3 密钥 必填
app-v3-secret: XXX
# 微信支付商户号 服务商模式下为服务商的mchid 必填
mch-id: XXX
# 商户服务器域名 用于回调 需要放开回调接口的安全策略 必填
domain: XXX
# 商户 api 证书路径 必填 填写classpath路径 位于 maven项目的resources文件下
cert-path: config/wechat/apiclient_cert.p12
三、JSAPI支付调用的接口。调用框架内部已经封装好的api很方便(有兴趣可以看看源码)
1、封装请求参数实体:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class WechatJsApiDTO implements Serializable {
private static final long serialVersionUID = -1949915352969937043L;
@NotNull(message = "金额不能为空")
private BigDecimal total;
@NotBlank(message = "小程序用户的openId不能为空")
private String openid;
@NotBlank(message = "商品描述不能为空")
private String description;
private String outTradeNo;
}
2、接口调用代码:
@Autowired private WechatApiProvider wechatApiProvider;
private WechatJsApiVO sendPay(WechatJsApiDTO w) {
// 生成商户订单号
final String outTradeNo =
StringUtils.isNotBlank(w.getOutTradeNo()) ? w.getOutTradeNo() : IdGenerator.getIdStr();
// 获取支付请求参数
final PayParams payParams = new PayParams();
final Amount amount = new Amount();
amount.setTotal(w.getTotal().setScale(0, BigDecimal.ROUND_DOWN).intValue());
final Payer payer = new Payer();
payer.setOpenid(w.getOpenid());
payParams.setAppid(APP_ID);
payParams.setMchid(MCH_ID);
payParams.setDescription(w.getDescription());
payParams.setOutTradeNo(outTradeNo);
payParams.setNotifyUrl(支付后微信服务回调地址);
payParams.setAmount(amount);
payParams.setPayer(payer);
// 请求操作
final WechatResponseEntity weChaRes =
wechatApiProvider.directPayApi("202112").jsPay(payParams);
// 构建返回参数
if (Objects.nonNull(weChaRes) && weChaRes.getHttpStatus() == 200) {
return WechatJsApiVO.builder().outTradeNo(outTradeNo).node(weChaRes.getBody()).build();
}
throw new WechatPayException(
ErrorConstants.WECHAT_PAY_JSAPI_ERROR_CODE, ErrorConstants.WECHAT_PAY_JSAPI_ERROR_MSG);
}
四、如果要调用其他的支付方式类型可调用以下服务接口,可查看源码(清晰的标出支付方式类型)
1、wechatApiProvider.directPayApi("202112") 下有很多支付方式的api接口供调用
五、接收微信支付回调通知,此通知会告诉你用户支付的状态(必须在此通知中来判断用户支付成功。不能靠前端告诉你支付是否成功,若靠前端来告诉你用户支付是否成功会坑死你的!)
1、Controller:
@PostMapping(path = "")
public void receive(
@RequestHeader("Wechatpay-Serial") String wechatpaySerial,
@RequestHeader("Wechatpay-Signature") String wechatpaySignature,
@RequestHeader("Wechatpay-Timestamp") String wechatpayTimestamp,
@RequestHeader("Wechatpay-Nonce") String wechatpayNonce,
@RequestBody String callback) {
log.info("接收支付回调通知:");
log.info("Wechatpay-Serial为:{}", wechatpaySerial);
log.info("Wechatpay-Signature为:{}", wechatpaySignature);
log.info("Wechatpay-Timestamp为:{}", wechatpayTimestamp);
log.info("Wechatpay-Nonce为:{}", wechatpayNonce);
log.info("callback为:{}", callback);
// 接收微信服务器返回的参数
wechatPayService.receive(
wechatpaySerial, wechatpaySignature, wechatpayTimestamp, wechatpayNonce, callback);
}
2、Service:
@Override
public void receive(
String wechatpaySerial,
String wechatpaySignature,
String wechatpayTimestamp,
String wechatpayNonce,
String callback) {
ResponseSignVerifyParams res = new ResponseSignVerifyParams();
res.setBody(callback);
res.setWechatpayNonce(wechatpayNonce);
res.setWechatpaySerial(wechatpaySerial);
res.setWechatpaySignature(wechatpaySignature);
res.setWechatpayTimestamp(wechatpayTimestamp);
// 解密微信支付响应参数
wechatApiProvider.callback("202112").transactionCallback(res, this::payTrigger);
}
public void payTrigger( TransactionConsumeData t) {
//TODO 此处用于用户支付后的逻辑
}