微信支付V3版商家转账到零钱

微信支付V3版商家转账到零钱

在对接微信中作为技术小白,可真是煞费苦心呀,特此参考了大佬文档,和微信文档进行开发。特意记录一下,以便在工作中遗忘。

操作步骤:

  1. 登录微信支付商户平台-产品中心,开通商家转账到零钱。
    在这里插入图片描述
    在这里插入图片描述

  2. 商户号已入驻90日且截止今日回推30天商户号保持连续不间的交易。(这点要满足才能开通使用)

  3. 开启验密批量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的id
    private 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";        //用户微信中的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<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);
            //获取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();
    }
}

到此商家转账到零钱完成,希望能帮助到你。不喜勿喷!

  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值