Java之微信现金红包

现金红包,是微信支付商户平台提供的营销工具之一,上线以来深受广大商户与用户的喜爱。商户可以通过公众号或者服务通知向用户发放现金红包。用户领取红包后,资金到达用户微信支付零钱账户,和零钱包的其他资金有一样的使用出口;若用户未领取,资金将会在24小时后退回商户的微信支付账户中。


代码示例

    /**
     * 微信现金红包
     *
     * @return 微信接口响应
     * @throws Exception 异常
     */
    public String red() throws Exception {
        Map<String, Object> map = new HashMap<>();
        // 随机字符串
        map.put("nonce_str", System.currentTimeMillis() + String.valueOf(new java.util.Random().nextInt(900) + 100));
        // 商户订单
        map.put("mch_billno", getOrderNo());
        // 商户号
        map.put("mch_id", "商户号");
        // 公众号appid
        map.put("wxappid", "公众号appid");
        // 商户名称
        map.put("send_name", "商户名称");
        // 用户openid
        map.put("re_openid", "用户openid");
        // 付款金额 单位分
        map.put("total_amount", 100);
        // 红包发送总人数
        map.put("total_num", 1);
        // 红包祝福语
        map.put("wishing", "红包祝福语");
        // 发送端ip地址
        map.put("client_ip", "发送端ip地址");
        // 活动名称
        map.put("act_name", "活动名称");
        // 备注
        map.put("remark", "备注");
        /*
        发放红包使用场景,红包金额大于200或者小于1元时必传
        PRODUCT_1:商品促销
        PRODUCT_2:抽奖
        PRODUCT_3:虚拟物品兑奖 
        PRODUCT_4:企业内部福利
        PRODUCT_5:渠道分润
        PRODUCT_6:保险回馈
        PRODUCT_7:彩票派奖
        PRODUCT_8:税务刮奖
         */
        map.put("scene_id", "PRODUCT_2");
        // 签名
        map.put("sign", createSign(map));
        return doSendMoney(createXML(map));
    }

    /**
     * 发送红包
     *
     * @param data 请求参数
     * @return 微信接口响应
     * @throws Exception 异常
     */
    String doSendMoney(String data) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        // p12文件路径
        try (FileInputStream instream = new FileInputStream(new File("D:\\apiclient_cert.p12"))) {
            // 默认密码为微信支付商户号
            keyStore.load(instream, "密码".toCharArray());
        }
        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, "商户号".toCharArray())
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) {
            HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack");
            httpost.addHeader("Connection", "keep-alive");
            httpost.addHeader("Accept", "*/*");
            httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            httpost.addHeader("Host", "api.mch.weixin.qq.com");
            httpost.addHeader("X-Requested-With", "XMLHttpRequest");
            httpost.addHeader("Cache-Control", "max-age=0");
            httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            try (CloseableHttpResponse response = httpclient.execute(httpost)) {
                HttpEntity entity = response.getEntity();
                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
                EntityUtils.consume(entity);
                return jsonStr;
            }
        }
    }

    /**
     * 创建签名所需要的参数xml格式
     *
     * @param map Map
     * @return xml
     */
    public String createXML(Map<String, Object> map) {
        StringBuilder xml = new StringBuilder("<xml>");
        Set<String> set = map.keySet();
        for (String str : set) {
            xml.append("<").append(str).append(">").append("<![CDATA[").append(map.get(str)).append("]]>").append("</").append(str).append(">");
        }
        xml.append("</xml>");
        return xml.toString();
    }

    /**
     * 创建签名
     *
     * @param map 参数Map
     * @return 签名
     */
    String createSign(Map<String, Object> map) {
        SortedMap<String, String> packageParams = new TreeMap<>();
        for (Map.Entry<String, Object> m : map.entrySet()) {
            packageParams.put(m.getKey(), m.getValue().toString());
        }
        StringBuilder sb = new StringBuilder();
        Set<?> es = packageParams.entrySet();
        for (Object e : es) {
            Map.Entry entry = (Map.Entry) e;
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (!StringUtils.isEmpty(v) && !"sign".equals(k) && !"key".equals(k))
                sb.append(k).append("=").append(v).append("&");
        }
        // API密钥
        sb.append("key=").append("API密钥");
        return md5(sb.toString()).toUpperCase();
    }

    /**
     * md5加密
     *
     * @param string 被加密数据
     * @return 加密数据
     */
    String md5(String string) {
        try {
            byte[] digest = MessageDigest.getInstance("MD5").digest(string.getBytes(StandardCharsets.UTF_8));
            StringBuilder buf = new StringBuilder(digest.length * 2);
            for (byte b : digest) {
                if ((b & 0xFF) < 16) buf.append("0");
                buf.append(Long.toString((b & 0xFF), 16));
            }
            return buf.toString();
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    /**
     * 生成商户流水订单号
     *
     * @return 订单号
     */
    public static String getOrderNo() {
        StringBuilder order = new StringBuilder("商户号" + new SimpleDateFormat("yyyyMMdd").format(new Date()));
        Random r = new Random();
        for (int i = 0; i < 10; i++) {
            order.append(r.nextInt(9));
        }
        return order.toString();
    }

成功响应示例

<xml>
    <return_code>
        <![CDATA[SUCCESS]]>
    </return_code>
    <return_msg>
        <![CDATA[发放成功]]>
    </return_msg>
    <result_code>
        <![CDATA[SUCCESS]]>
    </result_code>
    <err_code>
        <![CDATA[SUCCESS]]>
    </err_code>
    <err_code_des>
        <![CDATA[发放成功]]>
    </err_code_des>
</xml>

常见问题

微信接口返回ip没有权限之类的话 是因为添加ip请求接口权限,添加步骤和上一篇文章的类似


©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容