Java之微信現(xiàn)金紅包

現(xiàn)金紅包堂飞,是微信支付商戶平臺提供的營銷工具之一圃泡,上線以來深受廣大商戶與用戶的喜愛。商戶可以通過公眾號或者服務通知向用戶發(fā)放現(xiàn)金紅包蛙讥。用戶領取紅包后薪丁,資金到達用戶微信支付零錢賬戶遇西,和零錢包的其他資金有一樣的使用出口;若用戶未領取严嗜,資金將會在24小時后退回商戶的微信支付賬戶中粱檀。


代碼示例

    /**
     * 微信現(xiàn)金紅包
     *
     * @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);
        // 紅包發(fā)送總?cè)藬?shù)
        map.put("total_num", 1);
        // 紅包祝福語
        map.put("wishing", "紅包祝福語");
        // 發(fā)送端ip地址
        map.put("client_ip", "發(fā)送端ip地址");
        // 活動名稱
        map.put("act_name", "活動名稱");
        // 備注
        map.put("remark", "備注");
        /*
        發(fā)放紅包使用場景,紅包金額大于200或者小于1元時必傳
        PRODUCT_1:商品促銷
        PRODUCT_2:抽獎
        PRODUCT_3:虛擬物品兌獎 
        PRODUCT_4:企業(yè)內(nèi)部福利
        PRODUCT_5:渠道分潤
        PRODUCT_6:保險回饋
        PRODUCT_7:彩票派獎
        PRODUCT_8:稅務刮獎
         */
        map.put("scene_id", "PRODUCT_2");
        // 簽名
        map.put("sign", createSign(map));
        return doSendMoney(createXML(map));
    }

    /**
     * 發(fā)送紅包
     *
     * @param data 請求參數(shù)
     * @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;
            }
        }
    }

    /**
     * 創(chuàng)建簽名所需要的參數(shù)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();
    }

    /**
     * 創(chuàng)建簽名
     *
     * @param map 參數(shù)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 被加密數(shù)據(jù)
     * @return 加密數(shù)據(jù)
     */
    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[發(fā)放成功]]>
    </return_msg>
    <result_code>
        <![CDATA[SUCCESS]]>
    </result_code>
    <err_code>
        <![CDATA[SUCCESS]]>
    </err_code>
    <err_code_des>
        <![CDATA[發(fā)放成功]]>
    </err_code_des>
</xml>

常見問題

微信接口返回ip沒有權限之類的話 是因為添加ip請求接口權限漫玄,添加步驟和上一篇文章的類似


?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茄蚯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌渗常,老刑警劉巖壮不,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異皱碘,居然都是意外死亡忆畅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門尸执,熙熙樓的掌柜王于貴愁眉苦臉地迎上來家凯,“玉大人,你說我怎么就攤上這事如失“砘澹” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵褪贵,是天一觀的道長掂之。 經(jīng)常有香客問我,道長脆丁,這世上最難降的妖魔是什么世舰? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮槽卫,結(jié)果婚禮上跟压,老公的妹妹穿的比我還像新娘。我一直安慰自己歼培,他們只是感情好震蒋,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著躲庄,像睡著了一般查剖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上噪窘,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天笋庄,我揣著相機與錄音,去河邊找鬼倔监。 笑死直砂,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的丐枉。 我是一名探鬼主播哆键,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼瘦锹!你這毒婦竟也來了籍嘹?” 一聲冷哼從身側(cè)響起闪盔,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辱士,沒想到半個月后泪掀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡颂碘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年异赫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片头岔。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡塔拳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出峡竣,到底是詐尸還是另有隱情靠抑,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布适掰,位于F島的核電站颂碧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏类浪。R本人自食惡果不足惜载城,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望费就。 院中可真熱鬧诉瓦,春花似錦、人聲如沸受楼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艳汽。三九已至,卻和暖如春对雪,著一層夾襖步出監(jiān)牢的瞬間河狐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工瑟捣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留馋艺,地道東北人。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓迈套,卻偏偏與公主長得像捐祠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子桑李,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容