一、前文
参考 基于WxJava实现微信支付SpringBoot后端接口的使用 微信支付—开发者文档—小程序—小程序调起支付API(V3版本) 微信支付—开发文档—小程序支付—小程序调起支付API(V2) 微信支付接口签名校验工具 微信官方文档—小程序—支付 /wx.requestPayment(V3)
- V2版本的API,通过MD5加密(本博文主要简述)
- V3版本的API,使用RAS加密
二、流程图
sequenceDiagram
微信小程序 ->> 微信小程序: 用户点击付款按钮
微信小程序 ->> SpringBoot后端: 调用后端下单接口
SpringBoot后端->>SpringBoot后端: JSAPI统一下单
SpringBoot后端->>SpringBoot后端: 微信订单数据存入数据库
SpringBoot后端->>SpringBoot后端: 生成小程序调起支付所需的数据
SpringBoot后端->>微信小程序: 返回小程序调起支付所需的数据
微信小程序->>微信小程序: wx.requestPayment发起微信支付
微信小程序->>SpringBoot后端: 支付成功/失败回调
SpringBoot后端->>SpringBoot后端: JSAPI查询订单
SpringBoot后端->>SpringBoot后端: 确认支付成功,更新数据库
三、SpringBoot接口实现
2.1 微信调起支付所需数据
Md5Utils
/**
* Md5加密方法
*
* @author weijian
*/
public class Md5Utils
{
private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);
/**
* 生成 MD5
*
* @param data 待处理数据
* @return MD5结果
*/
public static String MD5(String data) {
try {
java.security.MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
复制代码
WxPayment
/**
* 微信调起支付数据 WxPayment
*
* @author weijian
*/
@ApiModel(value="WxPayment",description="微信调起支付数据")
public class WxPayment
{
@ApiModelProperty(value="wxTradeId", required = true)
@Excel(name = "wxTradeId")
private Long wxTradeId;
@ApiModelProperty(value="小程序id", required = true)
@Excel(name = "小程序id")
private String appId;
@ApiModelProperty(value="时间戳", required = true)
@Excel(name = "时间戳")
private String timeStamp;
@ApiModelProperty(value="随机字符串", required = true)
@Excel(name = "随机字符串")
private String nonceStr;
@ApiModelProperty(value="订单详情扩展字符串", required = true)
@Excel(name = "订单详情扩展字符串")
private String _package;
@ApiModelProperty(value="签名方式", required = true)
@Excel(name = "签名方式")
private String signType;
@ApiModelProperty(value="签名", required = true)
@Excel(name = "签名")
private String paySign;
public void sign(String key){
String sign = ("appId="+appId+"&");
sign += ("nonceStr="+nonceStr+"&");
sign += ("package="+_package+"&");
sign += ("signType="+signType+"&");
sign += ("timeStamp="+timeStamp+"&");
sign += ("key="+key);
System.out.println("sign="+sign);
setPaySign(Md5Utils.MD5(sign).toUpperCase());
}
public Long getWxTradeId() {
return wxTradeId;
}
public void setWxTradeId(Long wxTradeId) {
this.wxTradeId = wxTradeId;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
public String get_package() {
return _package;
}
public void set_package(String _package) {
this._package = _package;
}
public String getSignType() {
return signType;
}
public void setSignType(String signType) {
this.signType = signType;
}
public String getPaySign() {
return paySign;
}
public void setPaySign(String paySign) {
this.paySign = paySign;
}
@Override
public String toString() {
return "WxPayment{" +
"wxTradeId=" + wxTradeId +
", appId='" + appId + '\'' +
", timeStamp='" + timeStamp + '\'' +
", nonceStr='" + nonceStr + '\'' +
", _package='" + _package + '\'' +
", signType='" + signType + '\'' +
", paySign='" + paySign + '\'' +
'}';
}
}
复制代码
2.2 下单接口
WxPayController
@ApiOperation("微信统一下单")
// @PreAuthorize("@ss.hasPermi('wallet:update')")
@Log(title = "微信统一下单", businessType = BusinessType.UPDATE)
@PostMapping("/wx/unifiedOrder")
public AjaxResult wxUnifiedOrder(@ApiParam() Long billId) throws Exception
{
Bill bill = billService.selectBillById(billId);
if(ObjectUtil.isNull(bill)){
return AjaxResult.error("bill异常");
}
//1. JSAPI微信统一下单
WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
wxPayUnifiedOrderRequest.setOutTradeNo(IdUtils.fastSimpleUUID(16));
wxPayUnifiedOrderRequest.setTotalFee(1);
wxPayUnifiedOrderRequest.setSpbillCreateIp(IpUtils.getHostIp());
wxPayUnifiedOrderRequest.setNotifyUrl("https://www.nb.cn:8080/v1/wx/notify");
wxPayUnifiedOrderRequest.setTradeType("JSAPI");
wxPayUnifiedOrderRequest.setBody("账单支付");
wxPayUnifiedOrderRequest.setOpenid(SecurityUtils.getLoginUser().getUser().getTenantOpenId());
wxPayUnifiedOrderRequest.setAppid("wx********");
WxPayUnifiedOrderResult wxPayUnifiedOrderResult = wxService.unifiedOrder(wxPayUnifiedOrderRequest);
//2. 微信订单数据存入数据库
WxTrade wxTrade = new WxTrade();
wxTrade.setBillId(billId);
wxTrade.setUserId(SecurityUtils.getUserId());
wxTrade.setUserName(SecurityUtils.getUsername());
wxTrade.setAppId(wxPayUnifiedOrderResult.getAppid());
wxTrade.setMchId(wxPayUnifiedOrderResult.getMchId());
wxTrade.setSubMchId(wxPayUnifiedOrderResult.getSubMchId());
wxTrade.setOutTradeNo(wxPayUnifiedOrderRequest.getOutTradeNo());
wxTrade.setTotalFee(wxPayUnifiedOrderRequest.getTotalFee());
wxTrade.setBody(wxPayUnifiedOrderRequest.getBody());
wxTrade.setStatus(Constants.TRADE_UNKNOWN);
wxTradeService.insertWxTrade(wxTrade);
//3. 生成小程序调起支付所需的数据
WxPayment wxPayment = new WxPayment();
wxPayment.setWxTradeId(wxTrade.getId());
wxPayment.setAppId(wxPayUnifiedOrderResult.getAppid());
wxPayment.setTimeStamp((System.currentTimeMillis()/1000)+"");
wxPayment.set_package("prepay_id="+wxPayUnifiedOrderResult.getPrepayId());
wxPayment.setNonceStr(IdUtils.fastSimpleUUID(32));
wxPayment.setSignType("MD5");
wxPayment.sign(wxPayProperties.getMchKey());
logger.info(wxPayment.toString());
//4. 返回wxPayment
return AjaxResult.success(wxPayment);
}
复制代码
2.3 支付回调接口
支付回调接口
- 查询该微信订单是否完成
- 确认支付完成,则执行具体的业务逻辑
/**
* 订单状态, -1:未知;0:支付失败;1:支付成功
*/
public static final int TRADE_UNKNOWN = -1;
public static final int TRADE_FAIL = 0;
public static final int TRADE_SUCCESS = 1;
复制代码
public int queryWxOrder(String outTradeNo){
try {
WxPayOrderQueryResult wxPayOrderQueryResult = wxService.queryOrder(null, outTradeNo);
logger.info(wxPayOrderQueryResult.toString());
if(wxPayOrderQueryResult.getTradeState().equals("NOTPAY")){
return Constants.TRADE_UNKNOWN;
}
return Constants.TRADE_SUCCESS;
}catch (Exception e){
// e.printStackTrace();
//异常,订单不存在
}
return Constants.TRADE_FAIL;
}
复制代码
三、微信小程序实现
大部分的加密校验,以及与微信支付接口的交互都在Java后台操作,所以微信小程序的代码就相对简洁简单。
3.1 JSAP统一下单
//统一下单
unifiedOrder(){
var _this = this
app.showLoading(true)
keyueliSdk.wxUnifiedOrder(
{
billId: _this.data.id,
},
(res) => {
console.log("wxUnifiedOrder", res)
_this.requestPayment(res.data.data)
},
(res) => {})
},
复制代码
3.2 小程序调起支付
//官方标准的支付方法,调起支付界面
requestPayment(payData) {
var _this = this
wx.requestPayment({
timeStamp: payData.timeStamp,
nonceStr: payData.nonceStr,
package: payData._package,
signType: payData.signType,
paySign: payData.paySign,
success(res) {
console.log("支付成功", res)
_this.paySuccess(payData)
},
fail(res) {
console.log("支付失败", res)
app.showLoading(false)
app.showToast("支付失败")
}
})
},
复制代码
3.3 支付回调
//支付成功记录
paySuccess(payData){
keyueliSdk.wxPay(
payData.wxTradeId,
(res) => {
wx.hideLoading()
console.log("wxPay", res)
if(res.data.code==200){
app.showToast("支付成功")
wx.navigateBack({
delta: 1,
})
return
}
app.showToast(res.data.msg)
},
(res) => {})
},
复制代码
觉得好,就一键三连呗(点赞+收藏+关注)