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字吧,不少了,慢慢写别急,多要工期,摸摸鱼学学习,还是希望能帮到你,如果实在来不及就不用点赞了,来得及就还是点点赞哈哈哈哈哈哈!!!都兄弟客气啥,回见了您吶;
?
|