微信支付
场景:需要微信支付完成业务流程,首先商户申请了微信支付商户端的认证,然后我们就可以拿到关键的参数:mchId,mchKey,appid。
商户使用微信支付的条件
首先看一下微信的官方文档:微信支付文档
这里使用的是JSAPI支付方式。
JSAPI支付是指商户通过调用微信支付提供的JSAPI接口,在支付场景中调起微信支付模块完成收款。
商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易会话标识后再按Native、JSAPI、APP等不同场景生成交易串调起支付。
1.配置项
首先是小程序的配置(yml文件中)
wx:
miniapp:
app-id: 小程序appid
app-secret: 小程序密钥
pay:
appId: id
mchId: mchid
mchKey: mchkey
notifyUrl: http://xxx.com/pay/notify 微信支付回调地址
接着把这些写成配置类
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMiniappProperties {
private String appId;
private String appSecret;
}
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayProperties {
private String appId;
private String mchId;
private String mchKey;
private String createIp;
private String notifyUrl;
private String tradeType = "JSAPI";
}
接着就是这些参数的配置
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@AllArgsConstructor
public class WxConfig {
private final WxMiniappProperties miniappProperties;
private final WxPayProperties wxPayProperties;
@Bean
public WxMaService wxMaService() {
WxMaDefaultConfigImpl wxMaConfig = new WxMaDefaultConfigImpl();
wxMaConfig.setAppid(this.miniappProperties.getAppId());
wxMaConfig.setSecret(this.miniappProperties.getAppSecret());
WxMaService wxMaService = new WxMaServiceImpl();
wxMaService.setWxMaConfig(wxMaConfig);
return wxMaService;
}
@Bean
public WxPayService wxService() {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(StringUtils.trimToNull(this.wxPayProperties.getAppId()));
payConfig.setMchId(StringUtils.trimToNull(this.wxPayProperties.getMchId()));
payConfig.setMchKey(StringUtils.trimToNull(this.wxPayProperties.getMchKey()));
payConfig.setUseSandboxEnv(false);
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
return wxPayService;
}
}
到此我们的微信配置就完成了。
2.微信支付核心逻辑
首先要弄清楚支付的逻辑
- 首先前端调用我们预提交接口:这个接口就是为前端准备一些页面数据,还调用微信
- 然后前端再调用我们的微信支付接口,拿到我们接口返回的数据之后,前端掉起支付页面。
- 至此用户支付,前端不需要进行其他操作。
- 然后微信会自动调用我们写的微信支付回调接口,去告诉微信是否成功。
- 这样就形成了一个闭环。
具体的流程图在下面。左边是用户操作流程,右边是对应的代码逻辑
用户浏览商品页面
用户点击立购买
商品详情页面
前端调用预提交接口
进入商品订单信息页
后台返回商品信息
提交订单
后台调用微信支付返回参数
付钱
前端调起微信支付页面
结束
微信调用后台的支付回调
后台处理业务返回结果告诉微信
结束代码
从上面看到,我们需要一个订单预提交接口:这个接口的主要目的就是展示给用户看,他这个订单需要花多少钱,需要他填写一些电话,物流地址等信息;
主要是掉起微信支付的接口,在这个接口里面就是拿到参数,调用微信的jspa下单接口。
这只是一个核心方法,具体的业务逻辑需要自己写,自己根据需求设计
private WxPayResultVO doWxPay(String orderNo, BigDecimal payPrice,String openid) {
Date now = new Date();
String startTime = DateUtil.format(now, DatePattern.PURE_DATETIME_PATTERN);
String expireTime = DateUtil.format(DateUtil.offsetHour(now, 1), DatePattern.PURE_DATETIME_PATTERN);
Integer totalFee = BaseWxPayRequest.yuanToFen(payPrice.toString());
String ip = InetAddress.getLoopbackAddress().getHostAddress();
WxPayUnifiedOrderRequest orderRequest = WxPayUnifiedOrderRequest
.newBuilder()
.outTradeNo(orderNo)
.body("测试商品")
.totalFee(totalFee)
.openid(user.getOpenid())
.spbillCreateIp(ip)
.tradeType(wxPayProperties.getTradeType())
.notifyUrl(wxPayProperties.getNotifyUrl())
.timeStart(startTime)
.timeExpire(expireTime)
.build();
try {
WxPayMpOrderResult result = this.wxPayService.createOrder(orderRequest);
log.info("微信支付返回参数: {}", result);
WxPayResultVO payResult = new WxPayResultVO();
BeanUtil.copyProperties(result, payResult);
return payResult;
} catch (WxPayException e) {
log.error("微信支付失败!订单号:{}, 错误码:{}, 原因:{}",
orderNo, e.getErrCode(), e.getMessage());
throw new ApiException(2000,"微信支付失败");
}
}
微信支付的返回参数(前端拿到这些参数去吊起微信的支付页面)
import lombok.Data;
@Data
public class WxPayResultVO {
private String timeStamp;
private String nonceStr;
private String packageValue;
private String signType;
private String paySign;
}
下面就是微信的支付回调
@PostMapping("/notify")
public String notify(@RequestBody String xmlData) throws WxPayException {
final WxPayOrderNotifyResult notifyResult = this.wxPayService.parseOrderNotifyResult(xmlData);
String orderNo = notifyResult.getOutTradeNo();
String totalFee = BaseWxPayResult.fenToYuan(notifyResult.getTotalFee());
log.error("===支付回调=== 订单:{}, 金额: {}", orderNo, totalFee);
return this.paySerivice.notify(orderNo,totalFee);
}
具体方法
@Override
@Transactional(rollbackFor = Exception.class)
public String notify(String orderNo, String totalFee) {
return WxPayNotifyResponse.fail("失败");
return WxPayNotifyResponse.fail("失败");
return WxPayNotifyResponse.success("成功");
}
这里面的业务逻辑就是你进行判断这个订单是否存在啊,这个订单是否出现其他问题,如果有问题返给微信失败;如果没有问题,就处理一下你的业务逻辑,返回成功给微信。 至此微信支付就结束了。
从上可以看到其实没有什么难的地方,主要是你的业务逻辑必须理清楚。因为涉及到支付,也就是涉及到钱,所以会给人一种畏惧感,但是这些是必须要学习的,必须要尝试的。
|