首先要明白微信支付相关的三个账号
微信公众平台
微信支付-商户平台
微信-开放平台
1:一定要认真阅读官方开发文档,不然好多坑啊
微信公众号开发文档
官方sdk-maven
com.github.wxpay
wxpay-sdk
0.0.3
开发的相关流程:
a>:通过统一下单方法获取到预付订单信息(prepay_id-预付订单信息)
b>:对预付订单进行二次签名返回json数据给前端准备调起支付(二次签名需要自己实现,微信不提供,可参考微信签名方法)
c>:前端根据获取到的数据唤起支付页面进行支付
2:根据自己项目需求写相关的接口实现(从前端获取官方文档中的相关参数)
3:调官方sdk填充数据的方法进行关键信息的填充
//调官方sdk方法填充数据
data = wxPay.fillRequestData(data);
/**
* 向 Map 中添加 appid、mch_id、nonce_str、sign_type、sign
* 该函数适用于商户适用于统一下单等接口,不适用于红包、代金券接口
*
* @param reqData
* @return
* @throws Exception
*/
public Map fillRequestData(Map reqData) throws Exception {
reqData.put("appid", config.getAppID());
reqData.put("mch_id", config.getMchID());
reqData.put("nonce_str", WXPayUtil.generateNonceStr());
if (SignType.MD5.equals(this.signType)) {
reqData.put("sign_type", WXPayConstants.MD5);
}
else if (SignType.HMACSHA256.equals(this.signType)) {
reqData.put("sign_type", WXPayConstants.HMACSHA256);
}
reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));
return reqData;
}
4:完成相关数据填充后调官方sdk的统一下单方法
//调官方sdk统一下单方法
Map result = wxPay.unifiedOrder(data);
/**
* 作用:统一下单
* 场景:公共号支付、扫码支付、APP支付
* @param reqData 向wxpay post的请求数据
* @return API返回数据
* @throws Exception
*/
public Map unifiedOrder(Map reqData) throws Exception {
return this.unifiedOrder(reqData, config.getHttpConnectTimeoutMs(), this.config.getHttpReadTimeoutMs());
}
/**
* 作用:统一下单
* 场景:公共号支付、扫码支付、APP支付
* @param reqData 向wxpay post的请求数据
* @param connectTimeoutMs 连接超时时间,单位是毫秒
* @param readTimeoutMs 读超时时间,单位是毫秒
* @return API返回数据
* @throws Exception
*/
public Map unifiedOrder(Map reqData, int connectTimeoutMs, int readTimeoutMs) throws Exception {
String url;
if (this.useSandbox) {
url = WXPayConstants.SANDBOX_UNIFIEDORDER_URL;
}
else {
url = WXPayConstants.UNIFIEDORDER_URL;
}
String respXml = this.requestWithoutCert(url, this.fillRequestData(reqData), connectTimeoutMs, readTimeoutMs);
return this.processResponseXml(respXml);
}
5:对统一下单方法返回数据进行二次签名准备返回给前端(注意该方法需要自己去实现,官方没有单独提供二次签名方法,我是把官方签名方法copy出来自己建了一个工具类,然后调自己的工具类进行的二次签名,仅供参考)
if (req.getTradeType().equals(PayRequest.TRADE_TYPE_JSAPI)) {
out.put("appId", result.get("appid"));
out.put("nonceStr", String.valueOf(System.currentTimeMillis()));
out.put("package", "prepay_id=" + result.get("prepay_id"));
out.put("signType", "MD5");
out.put("timeStamp", String.valueOf(System.currentTimeMillis()/1000));
//##对返回数据进行二次签名 TODO
String packageSign = WXPayUtil.generateSignature(out,wxPayProperties.getKey());
out.put("paySign", packageSign);
}
/**
* 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
*
* @param data 待签名数据
* @param key API密钥
* @param signType 签名方式
* @return 签名
*/
public static String generateSignature(final Map data, String key, SignType signType) throws Exception {
Set keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
if (k.equals(WXPayConstants.FIELD_SIGN)) {
continue;
}
if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
sb.append("key=").append(key);
if (SignType.MD5.equals(signType)) {
return MD5(sb.toString()).toUpperCase();
}
else if (SignType.HMACSHA256.equals(signType)) {
return HMACSHA256(sb.toString(), key);
}
else {
throw new Exception(String.format("Invalid sign_type: %s", signType));
}
}
/**
* 生成 MD5
*
* @param data 待处理数据
* @return MD5结果
*/
public static String MD5(String data) throws Exception {
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();
}
6:把签名后的数据返回给前端,剩下的事就交给前端实现