一、通过微信统一下单接口下单预支付
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
二、JSAPI调起支付接口
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
必填参数
Map<String, Object> map = new HashMap<>();
map.put("appid", appid);
map.put("mch_id", mchId);
map.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));
map.put("body", requestParam.getBody());
map.put("out_trade_no", requestParam.getOutTradeNo());
map.put("fee_type", requestParam.getFeeType());
map.put("total_fee", requestParam.getTotalFee());
map.put("spbill_create_ip", Inet4Address.getLocalHost().getHostAddress());
map.put("notify_url", redirectUrl);
map.put("trade_type", requestParam.getTradeType());
//签名放到最后,前面的参数都已经存储进来
map.put("sign", SignUtil.md5Sign(map));
//sign_type不参与签名
map.put("sign_type", "MD5");
String xmlBody = Map2XmlUtil.map2Xml(map);
参数 | 描述 | 获取值 |
---|---|---|
spbill_create_ip | 系统服务器ip地址 | Inet4Address.getLocalHost().getHostAddress() |
sign | 签名 | https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3 |
必填参数设置
①在Java中将各个参数设置好值
Map<String, Object> map = new HashMap<>();
map.put("appId", appid);
map.put("timeStamp", System.currentTimeMillis()/1000);
map.put("nonceStr", UUID.randomUUID().toString().replaceAll("-", ""));
//统一下单接口返回的prepay_id值
map.put("package", "prepay_id=123456789");
map.put("paySign", SignUtil.md5Sign(map));
//此处需要与统一下单的签名类型一致,sign_type参数不参与签名
map.put("signType", "MD5");
String jsonBody = Map2JsonUtil.map2Json(map);
②传到html中调起支付
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":"wx2421b1c4370ec43b", //公众号ID,由商户传入
"timeStamp":"1395712654", //时间戳,自1970年以来的秒数
"nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串
"package":"prepay_id=u802345jgfjsdfgsdg888",
"signType":"MD5", //微信签名方式:
"paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名
},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ){
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
});
}
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady();
}
微信v2版本在退款的时候,需要在客户端添加api证书(如下OkHttp3Util)。
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
必填参数设置
Map<String, Object> map = new HashMap<>();
map.put("appId", appid);
map.put("mch_id", mchId);
map.put("nonceStr", UUID.randomUUID().toString().replaceAll("-", ""));
map.put("out_trade_no", refundRequest.getOutTradeNo());
map.put("out_refund_no", refundRequest.getOutRefundNo());
map.put("total_fee", refundRequest.getTotalFee());
map.put("refund_fee", refundRequest.getRefundFee());
map.put("refund_fee_type", "CNY");
//签名放到最后,前面的参数都已经存储进来
map.put("sign", SignUtil.md5Sign(map));
//sign_type参数不参与签名
map.put("signType", "MD5");
String xmlBody = Map2XmlUtil.map2Xml(map);
备注:以上接口都是微信v2版本接口,请求数据都是xml格式v2版本接口地址;
v3版本的接口是为json格式v3版本接口地址
public class SignUtil {
private static String signKey = "1234567890";
/**
* md5签名
*
* @return
*/
public static String md5Sign(Map<String, Object> signParam) {
//对参数按照key=value的格式,并按照参数名ASCII字典序排序
List<String> keySet = signParam.keySet().stream().sorted().collect(Collectors.toList());
StringBuilder stringA = new StringBuilder();
for (String key : keySet) {
stringA.append(key).append("=").append(signParam.get(key)).append("&");
}
//拼接API密钥
String stringSignTemp = stringA.append("key=").append(signKey).toString();
System.out.println("签名参数[" + stringSignTemp + "]");
//apache的md5工具
return DigestUtils.md5DigestAsHex(stringSignTemp.getBytes()).toUpperCase();
}
}
public class Map2XmlUtil {
/**
* md5签名
*
* @return
*/
public static String map2Xml(Map<String, Object> signParam) {
StringBuilder sb = new StringBuilder("" );
for(String key : signParam.keySet()) {
sb.append("<" + key + ">");
sb.append(signParam.get(key).toString());
sb.append("" + key + ">");
}
sb.append("");
System.out.println("map转xml后的数据[" + sb.toString() + "]");
return sb.toString();
}
}
public class OkHttp3Util {
/**
* 交易客户端
*/
public static OkHttpClient httpClient = new OkHttpClient.Builder()
//忽略hostname验证
.hostnameVerifier((s, sslSession) -> true)
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.build();
/**
* 退款客户端
*
* @return
*/
public static OkHttpClient sslHttpClient = new OkHttpClient.Builder()
//忽略hostname验证
.hostnameVerifier((s, sslSession) -> true)
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
//退款需要api证书
.sslSocketFactory(SslFactoryUtil.createSSLSocketFactory(), SslFactoryUtil.createNoTrustManager())
.build();
}
@Slf4j
public class SslFactoryUtil {
/**
* 文件位置:/resources/cert/wx_isv.p12
*/
private static final String wxIsvCertPath = "/cert/wx_isv.p12";
/**
* mchId值
*/
private static final String wxIsvCertPassword = "mchId";
/**
* 初始化证书容器
*
* @return
*/
public static SSLSocketFactory createSSLSocketFactory() {
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(SslFactoryUtil.class.getResourceAsStream(wxIsvCertPath), wxIsvCertPassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, wxIsvCertPassword.toCharArray());
SSLContext serverContext = SSLContext.getInstance("TLS");
serverContext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
return serverContext.getSocketFactory();
} catch (Exception e) {
log.error("初始化证书失败!");
throw new RuntimeException("初始化SSLContext失败", e);
}
}
/**
* 证书管理器
*
* @return
*/
public static X509TrustManager createNoTrustManager() {
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("非默认管理器:" + Arrays.toString(trustManagers));
}
return (X509TrustManager) trustManagers[0];
} catch (Exception e) {
log.error("初始化证书失败", e);
throw new RuntimeException("初始化证书失败", e);
}
}
}