天天看點

微信發放紅包接口(java)

微信官方文檔:發放紅包接口

代碼前的準備:

1.開通現金紅包功能

◆ 根據監管要求,新申請商戶号使用現金紅包需要滿足兩個條件:1、入駐時間超過90天 2、連續正常交易30天。 

2.拿到使用者的openid

3.登入微信商戶平台拿到:商戶号+商戶秘鑰+商戶證書 

接下來可以敲代碼了,把文檔中需要的請求參數 全部準備好。

4.随機字元串

/**
     * 随機字元串的生成
     *
     * @return
     */
    public static String getNonce_str() {
        return UUID.randomUUID().toString().replace("-", "").toUpperCase();
    }
           

5.生成商戶訂單号:商戶号+時間戳+4位随機數 我的商戶号10位 時間戳 14  加上4位随機數 剛好符合28位

//商戶訂單号預設用商戶号+時間戳+4位随機數
String mchBillno = model.getMchId()
                 + new SimpleDateFormat("yyyyMMddHHmmss").format(date)
                 + (int) ((Math.random() * 9 + 1) * 1000);
           

 因為 Math.random() 是随機生成0.0~1.0 前閉後開的随機數,為了保證是4位數,是以(Math.random() * 9 + 1) * 1000。

6.簽名 簽名算法 
           

簽名生成的通用步驟如下:

第一步,設所有發送或者接收到的資料為集合M,将集合M内非空參數值的參數按照參數名ASCII碼從小到大排序(字典序),使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字元串stringA。

特别注意以下重要規則:

  1. ◆ 參數名ASCII碼從小到大排序(字典序);
  2. ◆ 如果參數的值為空不參與簽名;
  3. ◆ 參數名區分大小寫;
  4. ◆ 驗證調用傳回或微信主動通知簽名時,傳送的sign參數不參與簽名,将生成的簽名與該sign值作校驗。
  5. ◆ 微信接口可能增加字段,驗證簽名時必須支援增加的擴充字段

第二步,在stringA最後拼接上key得到stringSignTemp字元串,并對stringSignTemp進行MD5運算,再将得到的字元串所有字元轉換為大寫,得到sign值signValue。

以上是官方給出的步驟,然後我們一步一步來

6.1 設所有發送或者接收到的資料為集合M  這裡最好單獨寫一個方法裝參數集合,因為後面的簽名步驟是一樣的,調用查詢接口,企業付款到零錢等需要簽名的接口用得上。

/**
     * 簽名算法
     * 算法說明:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3
     * @param model
     * @return
     */
    private static String getSign(TransfersDto model) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        //随機字元串
        paramMap.put("nonce_str", model.getNonceStr());
        //商戶訂單号
        paramMap.put("mch_billno", model.getMchBillno());
        //商戶号
        paramMap.put("mch_id", model.getMchId());
        //公衆賬号appid
        paramMap.put("wxappid", model.getWxAppId());
        //商戶名稱
        paramMap.put("send_name", model.getSendName());
        //使用者openid
        paramMap.put("re_openid", model.getReOpenId());
        //付款金額
        paramMap.put("total_amount", model.getTotalAmount());
        //紅包發放總人數
        paramMap.put("total_num", model.getTotalNum());
        //紅包祝福語
        paramMap.put("wishing", model.getWishing());
        //Ip位址
        paramMap.put("client_ip", model.getClientIp());
        //活動名稱
        paramMap.put("act_name", model.getActName());
        //備注
        paramMap.put("remark", model.getRemark());
        //場景id 發放紅包使用場景,紅包金額大于200或者小于1元時必傳,以外非必須。
        paramMap.put("scene_id", model.getSceneId());
        //活動資訊 非必須參數。
        paramMap.put("risk_info", model.getRiskInfo());
        
        return WXUtil.getSign(paramMap,KEY);
    }
           

6.2  傳入需要進行的簽名的參數,注意官網對于簽名的要求,都要滿足,然後拿到簽名。(此處用了商戶秘鑰)+md5對于參數進行了加密,保證資料安全。

/**
     * 簽名算法
     * 算法說明:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3
     * @param paramMap
     * @return
     */
    public static String getSign( Map<String, Object> paramMap,String key) {

        List<String> keys = new ArrayList(paramMap.keySet());
        //參數名ASCII碼從小到大排序(字典序)
        Collections.sort(keys);
        String sortString = "";
        for (int i = 0; i < keys.size(); i++ )
        {
            String mapKey = keys.get(i);
            Object value = paramMap.get(mapKey);
            //參數的值為空不參與簽名
            if (value != null) {
                sortString = sortString + mapKey + "=" + value + "&";
            }
        }
        //去掉最後一個 "&" 符号
        sortString = sortString.substring(0, sortString.length() -1);
        //拼接API密鑰
        String mysign = sortString + "&key=" + key;
        //進行MD5運算,再将得到的字元串所有字元轉換為大寫
        String sign = DigestUtils.md5Hex(mysign).toUpperCase();
        return sign;
    }
           

 7.封裝請求參數,下面的參數中上面介紹沒有用到的屬性,就是需要你手動設定的,如多少錢啊,openid,商戶号,紅包祝福語等等。

//封裝請求參數
            StringBuilder reqXmlStr = new StringBuilder();
            reqXmlStr.append("<xml>");
            reqXmlStr.append("<sign><![CDATA[" + model.getSign() + "]]></sign>");
            reqXmlStr.append("<mch_billno><![CDATA[" + model.getMchBillno() + "]]></mch_billno>");
            reqXmlStr.append("<mch_id><![CDATA[" + model.getMchId() + "]]></mch_id>");
            reqXmlStr.append("<wxappid><![CDATA[" + model.getWxAppId() + "]]></wxappid>");
            reqXmlStr.append("<send_name><![CDATA[" + model.getSendName() + "]]></send_name>");
            reqXmlStr.append("<re_openid><![CDATA[" + model.getReOpenId() + "]]></re_openid>");
            reqXmlStr.append("<total_amount><![CDATA[" + model.getTotalAmount() + "]]></total_amount>");
            reqXmlStr.append("<total_num><![CDATA[" + model.getTotalNum() + "]]></total_num>");
            reqXmlStr.append("<wishing><![CDATA[" + model.getWishing() + "]]></wishing>");
            reqXmlStr.append("<client_ip><![CDATA[" + model.getClientIp() + "]]></client_ip>");
            reqXmlStr.append("<act_name><![CDATA[" + model.getActName() + "]]></act_name>");
            reqXmlStr.append("<remark><![CDATA[" + model.getRemark() + "]]></remark>");
            reqXmlStr.append("<nonce_str><![CDATA[" + model.getNonceStr() + "]]></nonce_str>");
            if (model.getNonceStr() != null) {
                reqXmlStr.append("<scene_id><![CDATA[" + model.getSceneId() + "]]></scene_id>");
            }
            if (model.getRiskInfo() != null) {
                reqXmlStr.append("<risk_info>" + model.getRiskInfo() + "</risk_info>");
            }
            reqXmlStr.append("</xml>");
           
8.加載證書 證書的位置在測試時可以放在本地,路徑給絕對路徑,如果要正式使用前面的商戶秘鑰+商戶證書 都是不能直接暴露在代碼裡面的,這涉及商戶号金額,權限等操作,十分重要,十分重要,十分重要,切記找個安全的地方。
           
/**
     * 加載證書
     *
     * @throws KeyStoreException
     * @throws IOException
     * @throws CertificateException
     * @throws NoSuchAlgorithmException
     * @throws UnrecoverableKeyException
     * @throws KeyManagementException
     */
    private static void loadCertificate(String mchId, String certificatePath) throws KeyStoreException, IOException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyManagementException {

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        // 讀驗證書
        FileInputStream fileInputStream = new FileInputStream(new File("apiclient_cert.p12"));

        try {
            // 加載證書密碼,預設為商戶ID
            keyStore.load(fileInputStream, mchId.toCharArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            fileInputStream.close();
        }

        //信任自簽名證書
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,
                mchId.toCharArray()).build();
        SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(sslcontext,
                new String[] {"TLSv1"}, null,new DefaultHostnameVerifier());

        httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
    }
           

9.請求接口

 TRANS_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack"; 

微信發放紅包接口(java)

reqXmlStr:步驟7封裝好的請求資料

HttpPost httpPost = new HttpPost(transUrl);
        try {
            // 得指明使用UTF-8編碼,否則到API伺服器XML的中文不能被成功識别
            StringEntity postEntity = new StringEntity(reqXmlStr, "UTF-8");
            httpPost.addHeader("Content-Type", "text/xml");
            httpPost.setEntity(postEntity);

            //根初始化requestConfig 連接配接逾時時間,預設10秒 傳輸逾時時間,預設30秒
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(30000).build();
            httpPost.setConfig(requestConfig);
            HttpResponse response = httpClient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                result = EntityUtils.toString(entity, "UTF-8");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpPost.abort();
        }
           
10.傳回的結果是string型的xml資料
           
微信發放紅包接口(java)

怎麼把xml檔案的内容拿出來存儲到資料庫,請移步這裡:怎麼把微信紅包傳回的xml字元串值取出來

繼續閱讀