cxdm我又来了。这次我带来了微信Native退款V1.同样需要沟通的踩坑日记,请添加wx:w18013425493 大哥们轻点!!少说闲话,上菜!
先给你发垃圾微信官方支付文件地址。我用的是v1:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_4
我没有使用过这个新的官方文件:
https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/index.shtml
好了,开始正片
退款流程:
接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund
看需要双向证书的字吗? 这是点,他没有告诉你怎么用。 我来告诉你:
申请证书的流程:
首先:你要和你的财务部门协商,让他申请证书,也就是注册这个微信的人,也就是说app_id 和 mch_id至于申请流程,我理解你。那些人可能不明白。你必须去找它。让我告诉你这个过程
一步一步完成,这就是证书的样子
第二步 将证书放在改放的位置 当时自测放在当地 测试是放在linux服务器,映射到docker
代码实现:
点击使用证书
点击SDK与DEMO下载
把下载的解压出来你使劲往里点,这里会解压出来好多工具类,可以点进去看看,有些用不到的
这个是我导入的工具类,可以参考一下
参数拼接 调用验证证书:
/** * 微信退款 */ @RefreshScope @Component @Slf4j public class WxRefund { // =======【微信小程序】======== public static String WXMINI_APPID = ""; private static String WXMINI_MCHID = ""; public static String KEY = ""; /** * 这些URl本来要写nacos在动态配置中,但当事人赶工期,就没时间写了,有空就搬过去,别骂!!!!???? */ // @Value("${wxRefundUrl}") private static String wxRefundUrl = "https://api.mch.weixin.qq.com/secapi/pay/refund"; private static String mac_file_path = ""; private static String linux_file_path = ""; /** * 调用微信退款流程 * @param "" * @param "" * @return * @throws WxPayException * @throws IOException * @throws NoSuchAlgorithmException * @throws ParserConfigurationException * @throws SAXException */ public static Map<String, String> wxRefund(Long "", String "", BigDecimal "") throws Exception { ///参数拼接 SortedMap<String, String> param = new TreeMap<String, String>(); param.put("appid", ""); param.put("mch_id", ""); //这个参数可以是雪花算法就好,这是我们公司生成的工具,你可以去cv一个 param.put("nonce_str", IdWorkerKit.get32UUID()); param.put("out_trade_no",""); param.put("out_refund_no", ""); int moneyToInt = money.multiply(new BigDecimal(100)).intValue(); ///微信支付不接受小数,按分计算 这是个小坑 param.put("total_fee", String.valueOf(moneyToInt)); param.put("refund_fee", String.valueOf(moneyToInt)); ///这个地方用上面提到的工具 String generateSignature = WXPayUtil.generateSignature(param, KEY, WXPayConstants.SignType.MD5); param.put("sign", generateSignature); ///以微信退款格式生成参数 String requestParam = WXPayUtil.generateSignedXml(param, KEY); ///验证证书是否正确,并调用微信退款界面 String result = CommonUtil.postData(wxRefundUrl, requestParam,linux_file_path, WXMINI_MCHID); return WXPayUtil.xmlToMap(result); } }
验证证书 调用微信退款接口
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.security.*; import java.security.cert.CertificateException; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpPost; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.DefaultHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLContexts; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.BasicHttpClientConnectionManager; import org.apache.http.util.EntityUtils; import static com.wxrefund.WXPayConstants.USER_AGENT; @Slf4j public class CommonUtil { // 连接超时间,默认10秒 private static int socketTimeout = 10000; // 超时传输时间默认为30秒 private static int connectTimeout = 30000;
// 请求器的配置
private static RequestConfig requestConfig;
// HTTP请求器
private static CloseableHttpClient httpClient;
/**
* 通过Https往API post xml数据
*
* @param url API地址
* @param xmlObj 要提交的XML数据对象
* @return
*/
public static String postData(String url, String xmlObj, String path, String mchId) throws IOException {
BasicHttpClientConnectionManager basicHttpClientConnectionManager = null;
try {
// 加载证书 和验证证书
basicHttpClientConnectionManager = initCertV1(path, mchId);
} catch (Exception e) {
e.printStackTrace();
}
//调用微信退款接口
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(basicHttpClientConnectionManager)
.build();
HttpPost httpPost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
httpPost.setConfig(requestConfig);
StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.addHeader("User-Agent", USER_AGENT + " " + mchId);
httpPost.setEntity(postEntity);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
return EntityUtils.toString(httpEntity, "UTF-8");
}
/**
* 加载证书和验证证书
* @param path
* @param mchId
* @return
* @throws KeyStoreException
* @throws CertificateException
* @throws IOException
* @throws NoSuchAlgorithmException
* @throws UnrecoverableKeyException
* @throws KeyManagementException
*/
public static BasicHttpClientConnectionManager initCertV1(String path, String mchId) throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {
char[] password = mchId.toCharArray();
InputStream certStream = Files.newInputStream(Paths.get(path));
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(certStream, password);
// 实例化密钥库 & 初始化密钥工厂
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, password);
// 创建 SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
//这里有个大坑,这个调用是微信提供的调用demo,但是会有个问题,就是要去掉一个参数
//这里我已经填平了,放心使用,外面会给你放图片
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslContext,
null,
null,
new DefaultHostnameVerifier());
return new BasicHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build(),
null,
null,
null
);
}
}
这个是一个大坑微信提供的文档是这个样子,一定要把他弄成null,不然他就一直会报错
No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
好了大概到里基本就完事了,5000字吧,不少了,慢慢写别急,多要工期,摸摸鱼学学习,还是希望能帮到你,如果实在来不及就不用点赞了,来得及就还是点点赞哈哈哈哈哈哈!!!都兄弟客气啥,回见了您吶;