微信商户批量转账到零钱

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

微信商户批量转账


一、微信商户批量转账到零钱

1.引入库

代码如下(示例):


/**
 * 微信支付专用类 请求操作方法
 *
 * @author Administrator
 */
public class WeChatNewUtil {
	
    private static Logger log = Logger.getLogger(WeChatNewUtil.class);
    
    public static String transferBatch="/v3/transfer/batches";
    
    public static String domain="https://api.mch.weixin.qq.com";
    
    public static int connectionTimeout=10000;
    public static int readTimeout=10000;
    
    public static String privatekeypath = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/weixin/apiclient_key.pem";//从微信商户平台下载的密钥存放的路径
	/**
	 * 发起批量转账API 批量转账到零钱
	 * @param url 全路径地址
	 * @param requestJson 请求body
	 * @param mchID4M 商户id
	 * @param method 请求方法(get,post)
	 * @param requestUrl (域名后面的请求url)
	 * @return
	 */
	public static String postTransBatRequest(String url,
			String requestJson,
			String mchID,String method,String requestUrl) {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		try {
			String payserialNo= PemUtil.loadCertificate().getSerialNumber().toString(16).toUpperCase();
			//商户私钥证书
			HttpPost httpPost = new HttpPost(url);
			httpPost.addHeader("Content-Type", "application/json");
			httpPost.addHeader("Accept", "application/json");
			httpPost.addHeader("Wechatpay-Serial", payserialNo);
			//-------------------------核心认证 start-----------------------------------------------------------------
			String strToken = V3Util.getToken(method,
					requestUrl,requestJson,mchID,payserialNo, privatekeypath);
			
			// 添加认证信息
			httpPost.addHeader("Authorization",
					"WECHATPAY2-SHA256-RSA2048" + " "
							+ strToken);
			//---------------------------核心认证 end---------------------------------------------------------------
		     RequestConfig requestConfig = RequestConfig.custom()
		                .setSocketTimeout(readTimeout)
		                .setConnectTimeout(connectionTimeout)
		                .build();
		    httpPost.setConfig(requestConfig);
			if(requestJson!=null)httpPost.setEntity(new StringEntity(requestJson, "UTF-8"));
			//发起转账请求
			response = httpclient.execute(httpPost);
			entity = response.getEntity();//获取返回的数据
			return EntityUtils.toString(entity);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭流
		}
		return null;
	}
	/**
	 * get查询订单状态
	* @param url 全路径地址
	 * @param requestJson 请求body
	 * @param mchID4M 商户id
	 * @param method 请求方法(get,post)
	 * @param requestUrl (域名后面的请求url)
	 * @return
	 */
	public static String getTransBatRequest(String url,
			String requestJson,
			String mchID,String method,String requestUrl) {
		CloseableHttpClient httpclient = HttpClients.createDefault();
		CloseableHttpResponse response = null;
		HttpEntity entity = null;
		try {
			String payserialNo= PemUtil.loadCertificate().getSerialNumber().toString(16).toUpperCase();
			//商户私钥证书
		    HttpGet httpGet = new HttpGet(url);
		    httpGet.addHeader("Content-Type", "application/json");
		    httpGet.addHeader("Accept", "application/json");
		    httpGet.addHeader("Wechatpay-Serial", payserialNo);
			//-------------------------核心认证 start-----------------------------------------------------------------
			String strToken = V3Util.getToken(method,
					requestUrl,
					requestJson,mchID,payserialNo, privatekeypath);
			// 添加认证信息
			httpGet.addHeader("Authorization",
					"WECHATPAY2-SHA256-RSA2048" + " "
							+ strToken);
			//---------------------------核心认证 end---------------------------------------------------------------
			RequestConfig requestConfig = RequestConfig.custom()
					.setSocketTimeout(readTimeout)
					.setConnectTimeout(connectionTimeout)
					.build();
			httpGet.setConfig(requestConfig);
			//发起转账请求
			response = httpclient.execute(httpGet);
			entity = response.getEntity();//获取返回的数据
			return EntityUtils.toString(entity);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭流
		}
		return null;
	}

}

2.获取商户序列号密钥

代码如下(示例):

 public class PemUtil {
    public static PrivateKey loadPrivateKey(String privateKey) {
        privateKey = privateKey
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s+", "");

        try {
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(new Base64().decode(privateKey)));

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }

    public static PrivateKey loadPrivateKey() throws Exception {
        String certPath1 = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/weixin/apiclient_key.pem";//从微信商户平台下载的密钥存放的路径
     	File file1 = new File(certPath1);
     	InputStream inputStream = new FileInputStream(file1);
        ByteArrayOutputStream os = new ByteArrayOutputStream(2048);
        byte[] buffer = new byte[1024];
        String privateKey;
        try {
            for (int length; (length = inputStream.read(buffer)) != -1; ) {
                os.write(buffer, 0, length);
            }
            privateKey = os.toString("UTF-8");
        } catch (IOException e) {
            throw new IllegalArgumentException("无效的密钥", e);
        }
        return loadPrivateKey(privateKey);
    }

    public static X509Certificate loadCertificate() throws Exception {
        try {
        	String certPath1 = ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/weixin/apiclient_cert.pem";//从微信商户平台下载的序列号存放的路径
         	File file1 = new File(certPath1);
         	InputStream inputStream = new FileInputStream(file1);
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
            cert.checkValidity();
            return cert;
        } catch (CertificateExpiredException e) {
            throw new RuntimeException("证书已过期", e);
        } catch (CertificateNotYetValidException e) {
            throw new RuntimeException("证书尚未生效", e);
        } catch (CertificateException e) {
            throw new RuntimeException("无效的证书", e);
        }
    }

    private static final String TRANSFORMATION = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";

    public static String encryptOAEP(String message, X509Certificate certificate) throws Exception {
        return encrypt(message, certificate, TRANSFORMATION);
    }
	/**
	 * 敏感信息加密
	 */
    public static String encrypt(String message, X509Certificate certificate, String transformation) throws Exception {
        try {
            Cipher cipher = Cipher.getInstance(transformation);
            cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
            byte[] data = message.getBytes(StandardCharsets.UTF_8);
            byte[] ciphertext = cipher.doFinal(data);
            return new Base64().encodeToString(ciphertext);

        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
        } catch (InvalidKeyException e) {
            throw new IllegalArgumentException("无效的证书", e);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
        }
    }
 }

2.获取签名

代码如下(示例):

public class V3Util {

    private static Logger log = Logger.getLogger(V3Util.class);

	/**
	 * 
	 * @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) {
		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 私钥对象
	 * @throws Exception 
	   */
	  public static PrivateKey getPrivateKey(String filename) throws Exception {
		  return PemUtil.loadPrivateKey();
	  }
	/**
	 * 获取随机位数的字符串
	 * @param length
	 * @return
	 */
	public static String getRandomString(int length) {
		String base = "abcdefghijklmnopqrstuvwxyz0123456789";
		Random random = new Random();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < length; i++) {
			int number = random.nextInt(base.length());
			sb.append(base.charAt(number));
		}
		return sb.toString();
	}
}



2.RFC3339日期转换

代码如下(示例):

	public static String getDateByRFC3339(String time){
	    DateTime dateTime = new DateTime(time);
		long timeInMillis = dateTime.toCalendar(Locale.getDefault()).getTimeInMillis();
	    Date date = new Date(timeInMillis);

	    SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmsss");
	    String time = format.format(date);
	    return time;
	}

总结

这里对文章进行总结:
以上就是今天要讲的内容,本文仅仅简单介绍了微信商户批量转账到零钱,需要注意的是敏感信息需要进行加密处理,请求时需要获取序列号和签名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值