本地模拟微信支付回调
- 因微信支付回调是由拉起支付时的
notify_url 属性设置,notify_url 是由微信服务器请求自己项目暴露出的指定的接口地址(公网IP);在生产环境中项目接口地址微信服务器请求必须可达; - 则在本地服务支付回调接口需要测试时,可以通过从线上服务器中获取微信回调XML数据,在本地使用Postman模拟支付回调进行接口测试。
示例代码:
1.微信支付SDK
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
2.微信支付小程序配置
public class OurWxPayConfig implements WXPayConfig {
private final static String APP_KEY = "APPId";
private final static String MCH_ID = "商户ID";
private final static String KEY = "小程序Key";
private final static String SECRET = "小程序密钥";
private byte[] certData;
public OurWxPayConfig() throws Exception {
InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("apiclient_cert.p12");
this.certData = IOUtils.toByteArray(certStream);
certStream.close();
}
@Override
public String getAppID() {
return APP_KEY;
}
@Override
public String getMchID() {
return MCH_ID;
}
@Override
public String getKey() {
return KEY;
}
@Override
public InputStream getCertStream() {
return new ByteArrayInputStream(this.certData);
}
@Override
public int getHttpConnectTimeoutMs() {
return 0;
}
@Override
public int getHttpReadTimeoutMs() {
return 0;
}
public String getSecret() {
return SECRET;
}
}
2.1.支付POJO
@ToString
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class PayOrderInfo implements Serializable {
private static final long serialVersionUID = -3133004352432358931L;
@TableId(type = IdType.INPUT)
private String id;
private Float money;
private Date createTime;
private Date endTime;
private Float payMoney;
private String payOrder;
private Date orderPayTime;
}
2.2.支付后台关键业务方法
@Override
public JSONObject execPay(JSONObject requestParam, HttpServletRequest request) throws Exception {
JSONObject attach = new JSONObject();
String spbill_create_ip = request.getRemoteAddr();
String out_trade_no = requestParam.getString("order_id");
String openid = requestParam.getString("openid");
PayOrderInfo orderById = payOrderInfoService.getById(out_trade_no);
Float total_fee = orderById.getPayMoney();
String body = "订单实付金额:" + orderById.getPayMoney();
OurWxPayConfig ourWxPayConfig = new OurWxPayConfig();
WXPay wxPay = new WXPay(ourWxPayConfig);
Map<String, String> data = new HashMap<>();
data.put("appid", ourWxPayConfig.getAppID());
data.put("mch_id", ourWxPayConfig.getMchID());
data.put("spbill_create_ip", spbill_create_ip);
data.put("trade_type", "JSAPI");
data.put("notify_url", notifyUrl);
data.put("total_fee", String.valueOf(Math.round(total_fee * 100)));
data.put("fee_type", "CNY");
data.put("out_trade_no", out_trade_no);
data.put("body", body);
data.put("openid", openid);
data.put("sign_type", "MD5");
String sign = WXPayUtil.generateSignature(data, ourWxPayConfig.getKey());
data.put("sign", sign);
Map<String, String> wxRespData = wxPay.unifiedOrder(data);
if (wxRespData.get("return_code").equals("SUCCESS")) {
try {
String timeStamp =
String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = WXPayUtil.generateNonceStr();
Map<String, String> sign2Map = new HashMap<>();
sign2Map.put("appId", ourWxPayConfig.getAppID());
sign2Map.put("nonceStr", nonceStr);
sign2Map.put("package", "prepay_id=" + wxRespData.get("prepay_id"));
sign2Map.put("signType", "MD5");
sign2Map.put("timeStamp", timeStamp);
String paySign = WXPayUtil.generateSignature(sign2Map, ourWxPayConfig.getKey());
attach.put("paySign", paySign);
attach.put("prepay_id", wxRespData.get("prepay_id"));
attach.put("appId", ourWxPayConfig.getAppID());
attach.put("key", ourWxPayConfig.getKey());
attach.put("signType", "MD5");
attach.put("nonceStr", nonceStr);
attach.put("timeStamp", timeStamp);
return attach;
} catch (RuntimeException e) {
log.error(" --- 订单拉起支付失败");
}
}
throw new JeecgBootException("微信支付订单出现错误");
}
2.3.前端获取签名进行支付窗口拉起
pay(res){
const packages='wxpay'
let timeStamp = String(Date.now()/1000).substr(0,10)
let nonceStr = res.data.result.nonceStr
let packageStr = 'prepay_id='+res.data.result.prepay_id
let signTypeStr = 'MD5'
let key=res.data.result.key
let sign = res.data.result.paySign
wx.requestPayment({
timeStamp: res.data.result.timeStamp,
nonceStr: nonceStr ,
package: packageStr,
signType: signTypeStr,
paySign: sign,
success: (res) =>{
uni.redirectTo({
url:'***'
})
},
fail: (errs)=> {
this.$u.toast('支付失败')
}
});
},
3.微信支付回调接口
@ApiOperation("blogDemo")
@RequestMapping(value = "/blogDemo")
public void blogDemo(HttpServletRequest request, HttpServletResponse response) throws Exception {
Lock lock = this.lock;
lock.lock();
try {
OurWxPayConfig ourWxPayConfig = new OurWxPayConfig();
WXPay wxpay = new WXPay(ourWxPayConfig);
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.setHeader("Access-Control-Allow-Origin", "*");
DataInputStream in;
String wxNotifyXml = "";
try {
in = new DataInputStream(request.getInputStream());
byte[] dataOrigin = new byte[request.getContentLength()];
in.readFully(dataOrigin);
in.close();
wxNotifyXml = new String(dataOrigin);
log.error(" --- wxNotifyXml->[{}]", wxNotifyXml);
} catch (IOException e) {
e.printStackTrace();
}
Map<String, String> wxResponse = wxpay.processResponseXml(wxNotifyXml);
if (wxResponse.get("result_code").equalsIgnoreCase("SUCCESS") && wxResponse.get("return_code").equalsIgnoreCase("SUCCESS")) {
String out_trade_no = wxResponse.get("out_trade_no");
String transaction_id = wxResponse.get("transaction_id");
}
} finally {
lock.unlock();
}
}
3.1.从公网服务器中获取接口微信回调的xml数据
3.2Postman接口请求配置
本地请求成功!注:服务器行获取的xml数据内容不可改变,如果订单内容有变动,得从服务器上获取新的xml数据
|