微信支付V3版商家转账到零钱
在对接微信中作为技术小白,可真是煞费苦心呀,特此参考了大佬文档,和微信文档进行开发。特意记录一下,以便在工作中遗忘。
操作步骤:
-
登录微信支付商户平台-产品中心,开通商家转账到零钱。
-
商户号已入驻90日且截止今日回推30天商户号保持连续不间的交易。(这点要满足才能开通使用)
-
开启验密批量API,这样才能使用api请求
具体实现效果:如同这样,转账到用户微信账户
准备工作:
1,APPID:需要有一个微信社交载体,即微信公众号,小程序,自己开发的app(注意要在微信开发平台注册)
2,mchid:商户id 这里在商户平台申请以后,就是你的账号。,
3,绑定APPID及mchid
这里我们是公众号平台APPID绑定了商户平台的mchid(关联了才能实现)
4,配置API key
5,下载并配置商户证书
6,权限操作指引
具体查看产品——>接入前准备,按操作来!
https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter4_3_2.shtml
代码实现:
这里我们用main方法来启动;
创建一个MyWxPayTest类,这是主方法启动.
public class MyWxPayTest {private static String APPID = "wxsd36e6fc8e111a0c"; //可以是公众号的id/小程序的id/app的idprivate static String PATH = "https://api.mch.weixin.qq.com/v3/transfer/batches"; //转账的路径private static String MCHID = "1522311551"; //商户号就是在商户注册平台的账号 private static String privatekeypath = "H:\\zs\\apiclient_key.pem"; //商户私钥证书路径private static String WECHARPAYSERIALNO = "60A6ADC2DE79314D78C6C3CASSSDDD9635D96"; //商户证书序列号 在你的账户中心---API安全---申请API证书--证书管理--点击管理证书就会出现private static String openId = "oKU3sccDzF3lXSSD2fWaB4IzR1sPw"; //用户微信中的openIdpublic static void main(String[] args) {weixinTransferBat();}//整合数据发送private static void weixinTransferBat() {JSONObject object = new JSONObject();object.put("appid",APPID);object.put("out_batch_no","app123413"); //商家批次单号object.put("batch_name","测试"); //批次名称object.put("batch_remark","测试转账"); //批次备注object.put("total_amount",100); //转账总金额 单位分object.put("total_num",1); //转账总笔数List<Map> list = new ArrayList<>();Map<String,Object> map = new HashMap<>();map.put("out_detail_no","xj123456"); //商家明细单号map.put("transfer_amount",100); //转账金额map.put("transfer_remark","测试转账"); //测试转账map.put("openid",openId); //用户openid//还有用户收款姓名,建议不填list.add(map);object.put("transfer_detail_list",list);String resStr = MyHttpUtil.postTransBatRequest(PATH,object.toJSONString(),WECHARPAYSERIALNO,MCHID,privatekeypath);System.out.println("返回消息==="+resStr);}}
创建MyHttpUtil类,这是访问微信支付接口的服务类用的是 HttpURLConnectionl来进行接口 访问
public class MyHttpUtil {/*** 发起批量转账API 批量转账到零钱** @param requestUrl* @param requestJson 组合参数* @param wechatPayserialNo 商户证书序列号* @param mchID4M 商户号* @param privatekeypath 商户私钥证书路径* @return*/public static String postTransBatRequest(String requestUrl,String requestJson,String wechatPayserialNo,String mchID4M,String privatekeypath) {HttpURLConnection con = null;try {con = (HttpURLConnection) new URL(requestUrl).openConnection();con.setRequestProperty("Content-Type", "application/json");con.setRequestProperty("Accept", "application/json");con.setRequestProperty("Wechatpay-Serial", wechatPayserialNo);//获取tokenString token = VechatPayV3Util.getToken("POST", "/v3/transfer/batches", requestJson, mchID4M, wechatPayserialNo, privatekeypath);System.out.println("微信转账的token===" + token);con.setRequestProperty("Authorization", "WECHATPAY2-SHA256-RSA2048" + " " + token);con.setReadTimeout(3000);con.setConnectTimeout(3000);con.setDoInput(true);con.setDoOutput(true);con.setUseCaches(false);//携带参数BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(con.getOutputStream(), "utf-8"));writer.write(requestJson);writer.close();con.connect(); //连接int code = con.getResponseCode();String line;StringBuilder builder = new StringBuilder();BufferedReader buffer = null;if (con.getResponseCode() == HttpURLConnection.HTTP_OK) {//将响应流转换成字符串builder = new StringBuilder();buffer = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8"));while ((line = buffer.readLine()) != null) {builder.append(line);}return builder.toString();} else {buffer = new BufferedReader(new InputStreamReader(con.getErrorStream(), "utf-8")); //code != 200的时候还能返回while ((line = buffer.readLine()) != null) {builder.append(line);}return builder.toString();}} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();} finally {if (con != null) {con.disconnect();}}return null;}
}
创建VechatPayV3Util类 这是生成token的类
public class VechatPayV3Util {/**** @param method 请求方法 post* @param canonicalUrl 请求地址* @param body 请求参数* @param merchantId 这里用的商户号* @param certSerialNo 商户证书序列号* @param keyPath 商户证书地址* @return* @throws Exception*/public static String getToken(String method,String canonicalUrl,String body,String merchantId,String certSerialNo,String keyPath) throws Exception {String signStr = "";//获取32位随机字符串String nonceStr = getRandomString(32);//当前系统运行时间long timestamp = System.currentTimeMillis() / 1000;if (StringUtils.isEmpty(body)) {body = "";}//签名操作String message = buildMessage(method, canonicalUrl, timestamp, nonceStr, body);//签名操作String signature = sign(message.getBytes("utf-8"), keyPath);//组装参数signStr = "mchid=\"" + merchantId + "\",timestamp=\"" + timestamp+ "\",nonce_str=\"" + nonceStr+ "\",serial_no=\"" + certSerialNo + "\",signature=\"" + signature + "\"";return signStr;}public static String buildMessage(String method, String canonicalUrl, long timestamp, String nonceStr, String body) {
// String canonicalUrl = url.encodedPath();
// if (url.encodedQuery() != null) {
// canonicalUrl += "?" + url.encodedQuery();
// }return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";}public static String sign(byte[] message, String keyPath) throws Exception {Signature sign = Signature.getInstance("SHA256withRSA");sign.initSign(getPrivateKey(keyPath));sign.update(message);return Base64.encodeBase64String(sign.sign());}/*** 微信支付-前端唤起支付参数-获取商户私钥** @param filename 私钥文件路径 (required)* @return 私钥对象*/public static PrivateKey getPrivateKey(String filename) throws IOException {System.out.println("签名 证书地址是 "+filename);String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");try {String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");//System.out.println("--------privateKey---------:"+privateKey);KeyFactory kf = KeyFactory.getInstance("RSA");return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)));} catch (NoSuchAlgorithmException e) {throw new RuntimeException("当前Java环境不支持RSA", e);} catch (InvalidKeySpecException e) {throw new RuntimeException("无效的密钥格式");}}/*** 获取随机位数的字符串* @param length* @return*/public static String getRandomString(int length) {String base = "abcdefghijklmnopqrstuvwxyz0123456789";Random random = new Random();StringBuilder sb = new StringBuilder();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}
}
到此商家转账到零钱完成,希望能帮助到你。不喜勿喷!