package org.yeshi.utils.wx;
|
|
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
|
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
|
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
|
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
|
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
|
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
|
import net.sf.json.JSONObject;
|
import org.apache.commons.io.Charsets;
|
import org.apache.commons.io.IOUtils;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.entity.ContentType;
|
import org.apache.http.entity.StringEntity;
|
import org.apache.http.impl.client.CloseableHttpClient;
|
import org.apache.http.util.EntityUtils;
|
import org.yeshi.utils.StringUtil;
|
import org.yeshi.utils.entity.wx.WXAPPInfo;
|
import org.yeshi.utils.entity.wx.WXPlaceOrderParams;
|
import org.yeshi.utils.exception.WXOrderException;
|
import org.yeshi.utils.exception.WXPlaceOrderParamsException;
|
|
import java.io.ByteArrayInputStream;
|
import java.io.FileInputStream;
|
import java.math.BigDecimal;
|
import java.net.URLEncoder;
|
import java.nio.file.Files;
|
import java.nio.file.Paths;
|
import java.security.PrivateKey;
|
|
/**
|
* 微信支付帮助类(基于微信支付V3接口)
|
*
|
* @author Administrator
|
*/
|
public class WXPayV3Util {
|
|
private static CloseableHttpClient getHttpClient(WXAPPInfo app) throws Exception {
|
// 加载商户私钥(privateKey:私钥字符串)
|
PrivateKey merchantPrivateKey = PemUtil
|
.loadPrivateKey(new ByteArrayInputStream(app.getPrivateKey().getBytes("utf-8")));
|
|
// 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3秘钥)
|
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
|
new WechatPay2Credentials(app.getMchId(), new PrivateKeySigner(app.getMchSerialNo(), merchantPrivateKey)), app.getApiV3Key().getBytes("utf-8"));
|
|
// 初始化httpClient
|
return WechatPayHttpClientBuilder.create()
|
.withMerchant(app.getMchId(), app.getMchSerialNo(), merchantPrivateKey)
|
.withValidator(new WechatPay2Validator(verifier)).build();
|
}
|
|
/**
|
* 网络请求
|
*
|
* @param url
|
* @param requestData
|
* @param app
|
* @return
|
* @throws Exception
|
*/
|
private static JSONObject request(String url, String requestData, WXAPPInfo app) throws Exception {
|
HttpPost httpPost = new HttpPost(url);
|
|
if (!StringUtil.isNullOrEmpty(requestData)) {
|
StringEntity entity = new StringEntity(requestData, ContentType.APPLICATION_JSON.withCharset(Charsets.UTF_8));
|
entity.setContentType("application/json;charset=utf-8");
|
httpPost.setEntity(entity);
|
}
|
httpPost.setHeader("Accept", "application/json;charset=utf-8");
|
|
//完成签名并执行请求
|
CloseableHttpClient httpClient = getHttpClient(app);
|
CloseableHttpResponse response = httpClient.execute(httpPost);
|
try {
|
int statusCode = response.getStatusLine().getStatusCode();
|
if (statusCode == 200) {
|
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
|
String result = EntityUtils.toString(response.getEntity());
|
JSONObject resultJson = JSONObject.fromObject(result);
|
return resultJson;
|
} else if (statusCode == 204) {
|
System.out.println("success");
|
} else {
|
System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
|
throw new Exception("request failed");
|
}
|
} finally {
|
response.close();
|
}
|
return null;
|
}
|
|
/**
|
* H5支付统一下单接口
|
*
|
* @param params
|
* @return 支付链接
|
* @throws WXPlaceOrderParamsException
|
* @throws Exception
|
*/
|
public static String createH5Order(WXPlaceOrderParams params, String redirectUrl) throws WXPlaceOrderParamsException, Exception {
|
if (params == null)
|
throw new WXPlaceOrderParamsException(1, "请传入下单参数");
|
|
if (params.getApp() == null)
|
throw new WXPlaceOrderParamsException(2, "请传入下单应用信息");
|
|
if (StringUtil.isNullOrEmpty(params.getApp().getAppId()))
|
throw new WXPlaceOrderParamsException(201, "请传入下单应用信息-appId");
|
|
if (StringUtil.isNullOrEmpty(params.getApp().getMchId()))
|
throw new WXPlaceOrderParamsException(203, "请传入下单应用信息-mchId");
|
if (StringUtil.isNullOrEmpty(params.getApp().getApiV3Key()))
|
throw new WXPlaceOrderParamsException(204, "请传入下单应用信息apiV3Key");
|
if (StringUtil.isNullOrEmpty(params.getBody()))
|
throw new WXPlaceOrderParamsException(3, "请传入body");
|
|
if (StringUtil.isNullOrEmpty(params.getOrderNo()))
|
throw new WXPlaceOrderParamsException(4, "请传入orderNo");
|
|
if (params.getFee() == null)
|
throw new WXPlaceOrderParamsException(5, "请传入fee");
|
|
if (StringUtil.isNullOrEmpty(params.getIp()))
|
throw new WXPlaceOrderParamsException(6, "请传入ip");
|
|
if (StringUtil.isNullOrEmpty(params.getNotifyUrl()))
|
throw new WXPlaceOrderParamsException(7, "请传入notifyUrl");
|
|
// 请求body参数
|
String reqdata = "{"
|
+ "\"amount\": {"
|
+ "\"total\": " + params.getFee().multiply(new BigDecimal(100)).intValue() + ","
|
+ "\"currency\": \"CNY\""
|
+ "},"
|
+ "\"scene_info\": {"
|
+ "\"payer_client_ip\":\"" + params.getIp() + "\","
|
+ "\"h5_info\": {"
|
+ "\"type\": \"Wap\"" + "}},"
|
+ "\"mchid\": \"" + params.getApp().getMchId() + "\","
|
+ "\"description\": \"" + params.getBody() + "\","
|
+ "\"notify_url\": \"" + params.getNotifyUrl() + "\",";
|
//附加数据,在支付结果通知中会原样返回
|
if (params.getAttach() != null)
|
reqdata += ("\"attach\": \"" + params.getAttach() + "\",");
|
|
reqdata += ("\"out_trade_no\": \"" + params.getOrderNo() + "\","
|
+ "\"appid\": \"" + params.getApp().getAppId() + "\"" + "}");
|
JSONObject result = request("https://api.mch.weixin.qq.com/v3/pay/transactions/h5", reqdata, params.getApp());
|
if (result == null)
|
return null;
|
return result.optString("h5_url") + "&redirect_url=" + URLEncoder.encode(redirectUrl, "UTF-8");
|
}
|
|
/**
|
* 查询订单号是否支付成功
|
*
|
* @param orderNo
|
* @param app
|
* @return
|
* @throws WXOrderException
|
*/
|
public static boolean isPaySuccess(String orderNo, WXAPPInfo app) throws Exception {
|
String url = String.format("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s?mchid=%s", URLEncoder.encode(orderNo), app.getMchId());
|
JSONObject result = request(url, null, app);
|
if (result == null)
|
return false;
|
return "SUCCESS".equalsIgnoreCase(result.optString("trade_state"));
|
}
|
|
|
public static void main(String[] args) {
|
String privateKey = "";
|
try {
|
String content = IOUtils.toString(new FileInputStream("D:\\项目\\返利券\\商户平台\\1520950211_20210125_cert\\apiclient_key.pem"));
|
privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
|
.replace("-----END PRIVATE KEY-----", "")
|
.replaceAll("\\s+", "");
|
} catch (Exception e) {
|
|
}
|
WXPlaceOrderParams params = new WXPlaceOrderParams();
|
params.setBody("影视大全VIP-包月");
|
params.setFee(new BigDecimal("0.1"));
|
params.setNotifyUrl("http://api.ysdq.yeshitv.com:8089/BuWan/wx/pay/vip");
|
params.setOrderNo("buwan-vip-8");
|
params.setIp("113.249.192.231");
|
params.setApp(new WXAPPInfo("wxa99686bb65a9f466", "1520950211", "454328C324C6CC21355D064B44D6524CD7506DD0", privateKey, "XYJkJ2018FAfaodCCx899mLl138rfGVd"));
|
try {
|
String payUrl = WXPayV3Util.createH5Order(params, "http://vip.ysdq.yeshitv.com/wx_result.html");
|
System.out.println(payUrl);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
}
|
|
}
|