网站首页> 文章专栏> 微信支付V3版商家转账到零钱
微信支付V3版商家转账到零钱
原创 时间:2024-03-13 07:42 作者:AI智能 浏览量:3344

工作中避免不少不了对资金的开发,微信支付更是主流,为了避免遗忘,在这里记录一下开发工程!


一,微信支付V3版商家转账到零钱(API请求方式)

操作步骤:

1,登录微信支付商户平台-产品中心,开通商家转账到零钱。

1710314902632.webp

1710314908930.webp


2,商户号已入驻90日且截止今日回推30天商户号保持连续不间的交易。
3,开启验密批量API,这样才能使用api请求
1710314922570.webp
注意,开启 ip
1710314935541.webp
具体实现效果:如同拼多多这样,转账到用户微信账户

1710314972867.webp1710314979907.webp
准备工作:
1,APPID:需要有一个微信社交载体,即微信公众号,小程序,自己开发的app(注意要在微信开发平台注册)
2,mchid:商户id 这里在商户平台申请以后,就是你的账号。,
3,绑定APPID及mchid
这里我们是公众号平台APPID绑定了商户平台的mchid(关联了才能实现)
1710314996134.webp
4,配置API key
5,下载并配置商户证书
6,权限操作指引
具体查看产品——>接入前准备,按操作来!
代码实现:
这里我们用main方法来启动;

创建一个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 list = new ArrayList<>();

        Map 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类,这是访问微信支付接口的服务类

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();
    }
}
到此商家转账到零钱完成,希望能帮助到你。

动动小手 !!!
来说两句吧
最新评论
  • 代码王子
    很容易看进去,学到了很多知识,感谢博主分享,支持博主

  • 初时模样
    请问各位大佬谁有pdf版的吗想下载下来看

  • 零距离技师
    文章写的很详细,条理清晰。

  • 网路侠客
    支持大佬原创好文,内容丰富,排版精美,望大佬回访指点