网站首页> 文章专栏> 微信支付V3版商家转账到零钱
工作中避免不少不了对资金的开发,微信支付更是主流,为了避免遗忘,在这里记录一下开发工程!
1,登录微信支付商户平台-产品中心,开通商家转账到零钱。
创建一个MyWxPayTest类,这是主方法启动.
public class MyWxPayTest {
private static String APPID = "wxsd3611a0c"; //可以是公众号的id/小程序的id/app的id
private static String PATH = "https://api.mch.weixin.qq.com/v3/transfer/batches"; //转账的路径
private static String MCHID = "15351"; //商户号就是在商户注册平台的账号
private static String privatekeypath = "H:\\zs\\apiclient_key.pem"; //商户私钥证书路径
private static String WECHARPAYSERIALNO = "60A6ADC2DE79314D78C635D96"; //商户证书序列号 在你的账户中心---API安全---申请API证书--证书管理--点击管理证书就会出现
private static String openId = "oKU3sccDzF2fWaB4IzR1sPw"; //用户微信中的openId
public 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
创建MyHttpUtil类,这是访问微信支付接口的服务类
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);
//获取token
String 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();
}
}
2024-03-13 10:56:13 回复