微信支付--商家转账到零钱
时间:2022-09-15 01:30:00
/** * 微信接口要求参数对象 */ @Data @ToString @NoArgsConstructor @AllArgsConstructor public class TransfersVO {
private byte[] certData; /** * 与商户号相关的应用(如微信微信官方账号/小程序)APPID */ private String mchAppid; /** * 微信支付分配的商户号 */ private String mchId; /** * 商户名称, 如'XXX服务号' */ private String mchName; /** * 商户订单号需要保持独特性(只能是字母或数字,不能包含其他字符) */ private String partnerTradeNo; /** * 商户appid下,用户的openid */ private String openid; /** * NO_CHECK:不验证真实姓名 FORCE_CHECK:强行验证真实姓名 */ private String checkName = "NO_CHECK"; /** * 企业支付金额分为单位 */ private Double amount; /** * 随机字符串不超过32位 */ private String nonceStr; /** * 企业付款备注 */ private String desc; private String appKey; private String sceneId; /** * 发起者IP地址 该IP可传输用户端或服务端IP。 */ private String spbillCreateIp = "127.0.0.1"; @Transient public Map<String, String> map() {
Map<String, String> map = new HashMap<String, String>(); map.put("mch_appid", this.mchAppid); map.put("mchid", this.mchId); map.put("mch_name", this.mchName); map.put("openid", this.openid); map.put("amount", String.valueOf(this.amount)); map.put("desc", this.desc); map.put("appkey", this.appKey); map.put("nonce_str", this.nonceStr); map.put("partner_trade_no", this.partnerTradeNo); map.put("spbill_create_ip", this.spbillCreateIp); return map; } /** * 获取证书流 * @param certPath 证书路径 */ public InputStream getCertStream(String certPath) throws IOException {
File file = new File(certPath); InputStream certStream = new FileInputStream(file); this.certData = new byte[(int) file.length()]; certStream.read(this.certData); certStream.close(); ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData); return certBis; } }
/** * 微信工具类 */
@Component
@Slf4j
public class WxUtils {
/** * 付款 * * @param mchKey 商户密钥 * @param certPath 证书路径 * @param model 微信接口请求参数对象 */
public static void doTransfers(String mchKey, String certPath, TransfersVO model) {
// 微信商户证书路径
try {
// 1.计算参数签名
String paramStr = WxUtils.createLinkString(model,mchKey);
String sign = DigestUtils.md5Hex(paramStr).toUpperCase();
// 2.封装请求参数
StringBuilder reqXmlStr = new StringBuilder();
reqXmlStr.append("" );
reqXmlStr.append("" + model.getMchId() + "");
reqXmlStr.append("" + model.getMchAppid() + "");
reqXmlStr.append("" + model.getNonceStr() + "");
reqXmlStr.append("" + model.getCheckName() + "");
reqXmlStr.append("" + model.getOpenid() + "");
reqXmlStr.append("" + model.getAmount().intValue() + "");
reqXmlStr.append("" + model.getDesc() + "");
reqXmlStr.append("" + sign + "");
reqXmlStr.append("" + model.getPartnerTradeNo() + "");
//reqXmlStr.append("" + model.getSpbillCreateIp() + " ");
reqXmlStr.append("");
// 3.加载证书请求接口
String result = WxPayRequestUtils.httpsRequest(TRANS_URL, reqXmlStr.toString(),
model, certPath);
if (result.contains("CDATA[FAIL]")) {
log.info("领取红包结果:"+result); //领取失败
throw new ServiceException(ResultCodeEnum.BUSINESS_ERROR.getCode(), "领取红包失败");
} else {
//领取成功
}
} catch (Exception e) {
log.error("领取红包出现异常:{}", e); //领取失败
}
}
private static String createLinkString(TransfersVO model,String mchKey) {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("mch_appid", model.getMchAppid());
paramMap.put("mchid", model.getMchId());
paramMap.put("openid", model.getOpenid());
paramMap.put("amount", model.getAmount().intValue());
paramMap.put("check_name", model.getCheckName());
paramMap.put("desc", model.getDesc());
paramMap.put("partner_trade_no", model.getPartnerTradeNo());
paramMap.put("nonce_str", model.getNonceStr());
List<String> keys = new ArrayList(paramMap.keySet());
Collections.sort(keys);
StringBuilder preStr = new StringBuilder();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
Object value = paramMap.get(key);
if (i == keys.size() - 1) {
// 拼接时,不包括最后一个&字符
preStr.append(key).append("=").append(value);
} else {
preStr.append(key).append("=").append(value).append("&");
}
}
preStr.append("&key="+mchKey);
return preStr.toString();
}
}
@Component
public class WxPayRequestUtils {
// 连接超时时间,默认10秒
private int socketTimeout = 10000;
// 传输超时时间,默认30秒
private int connectTimeout = 30000;
// 请求器的配置
private static RequestConfig requestConfig;
// HTTP请求器
private static CloseableHttpClient httpClient;
/** * 加载证书 * @param path * @param transfer * @throws Exception */
private static void initCert(String path, TransfersVO transfer) throws Exception {
BasicHttpClientConnectionManager connManager;
// 拼接证书的路径
char[] password = transfer.getMchId().toCharArray();
InputStream certStream = transfer.getCertStream(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());
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslContext,
new DefaultHostnameVerifier());
connManager = new BasicHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build(),
null,
null,
null
);
httpClient = HttpClientBuilder.create()
.setConnectionManager(connManager)
.build();
/**if (CommonUtils.isPro()){ // 代理 HttpHost httpHost = new HttpHost("代理", 80); // 根据默认超时限制初始化requestConfig requestConfig = RequestConfig.custom() .setSocketTimeout(10000) .setConnectTimeout(30000) .setProxy(httpHost) .build(); }*/
}
/** * 通过Https往API post xml数据 * * @param url API地址 * @param xmlObj 要提交的XML数据对象 * @param path 当前目录,用于加载证书 * @return 支付结果 * @throws Exception 异常 */
public static String httpsRequest(String url, String xmlObj, TransfersVO model, String path) throws Exception {
// 加载证书
initCert(path, model);
String result = null;
HttpPost httpPost = new HttpPost(url);
// 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
/**if (CommonUtils.isPro()){ // 设置请求器的配置 httpPost.setConfig(requestConfig); }*/
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity, "UTF-8");
httpPost.abort();
return result;
}
}
@Test
public void testReward() throws Exception {
TransfersVO model = new TransfersVO();
model.setMchId("");
model.setMchAppid("");
model.setMchName("");
model.setOpenid("");
model.setAmount(40.0);
model.setDesc("红包");
model.setSceneId("PRODUCT_4");
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 15; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
model.setNonceStr(sb.toString());
String partnerTradeNo = model.getMchId()
+ new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
+ (int) ((Math.random() * 9 + 1) * 1000);
model.setPartnerTradeNo(partnerTradeNo);
WxUtils.doTransfers("商户密钥","证书路径",model);
}