2019-03-28 java 調(diào)用微信紅包接口

java 調(diào)用微信紅包接口

之前寫的一個(gè)微信紅包接口狐胎,用于公眾號(hào)自動(dòng)發(fā)送紅包給用戶,調(diào)用微信接口思路都是相同的歌馍,其他接口也可以使用這個(gè)方法。

  • jar包

方法涉及的java包過多晕鹊,需要自行查詢下載

  • 方法

    public final static int SEND_FAILED = 0; // 發(fā)放失敗
    public final static int SEND_SENDING = 1; // 發(fā)放中
    public final static int SEND_SENT = 2; // 已發(fā)放
    public final static int SEND_RECEIVED = 3; // 已領(lǐng)取

    @Autowired
    private ConfigMgrService configMgrService;

    @Autowired
    private WXpayorderService wXpayorderService;
// 紅包接口
    public String do_pay(String openid, int price ,String act_name) {
        logger.info("WechatPay::do_pay called");

        if (openid == null) {
            logger.error("WechatPay::openid  is null");
            return "fail";
        }
        Map wx_pay_config = configMgrService.queryWxConfigByGameid(1);//數(shù)據(jù)庫獲取商戶平臺(tái)配置松却,根據(jù)項(xiàng)目更改
        if (wx_pay_config == null) {
            logger.error("WechatPay::wx_pay_config  is null");
            return "fail";
        }

        String ip = wx_pay_config.get("client_ip").toString();
        int game_id = Integer.parseInt(wx_pay_config.get("game_id").toString());

        // 拼接請求參數(shù)
        Map<String, String> paramap = new HashMap<String, String>();

        // 隨機(jī)字符串
        String nonce_str = create_nonce_str();
        paramap.put("nonce_str", nonce_str);
        // 商戶訂單號(hào)
        String orderid = createOrderId();

        paramap.put("mch_billno", orderid);
        // 商戶號(hào)
        paramap.put("mch_id", wx_pay_config.get("mch_id").toString());
        // appid
        paramap.put("wxappid", wx_pay_config.get("app_id").toString());
        // 商戶名稱
        paramap.put("send_name", wx_pay_config.get("send_name").toString());
        // 用戶openid
        paramap.put("re_openid", openid);
        // 付款金額
        paramap.put("total_amount", String.valueOf(price));
        // 紅包發(fā)放總?cè)藬?shù)
        paramap.put("total_num", String.valueOf(1));
        // 紅包祝福語
        paramap.put("wishing", "恭喜中獎(jiǎng)");
        // ip地址
        paramap.put("client_ip", ip);
        // 活動(dòng)名稱
        paramap.put("act_name", act_name);
        // 備注
        paramap.put("remark", "紅包");
        // 場景id
        paramap.put("scene_id", "PRODUCT_5");//查看微信開發(fā)者文檔自行修改

        // 簽名
        try {
            String paysign = getPayCustomSign(paramap, wx_pay_config.get("key")
                    .toString()); // todo get sign
            // key
            paramap.put("sign", paysign);
        } catch (Exception e) {
            logger.error(e.toString());
            return "fail";
        }

        String xml = ArrayToXml(paramap);

        // 向微信接口發(fā)起請求
        String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";

        String xmlresponse = "";
        try {
            xmlresponse = sendRedEnvelope(url, xml);
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            logger.error("WechatPay::" + e1);
        }

        // String xmlresponse = dopost(url, xml);
        if (xmlresponse.isEmpty()) {
            logger.error("ActivityWechatPay::dopost failed");
            return "fail";
        }

        // 解析返回?cái)?shù)據(jù)
        try {
            logger.info("ActivityWechatPay::xml response:" + xmlresponse);
            Map<String, String> responsemap = doXMLParse(xmlresponse);
            // 通信標(biāo)識(shí)
            String returncode = responsemap.get("return_code");
            if (!returncode.equals("SUCCESS")) {
                logger.error("WechatPay::wechat return err:" + returncode
                        + ",return_msg:" + responsemap.get("return_msg"));

                return "fail";
            }

            // 業(yè)務(wù)結(jié)果
            returncode = responsemap.get("result_code");
            if (!returncode.equals("SUCCESS")) {
                logger.error("WechatPay::wechat return err:"
                        + responsemap.get("err_code") + ",err_code_des:"
                        + responsemap.get("err_code_des"));
                return "fail";
            }

        } catch (XmlPullParserException e) {
            logger.error(e.toString());
        } catch (IOException ioe) {
            logger.error(ioe.toString());
        }
        return "success";
    }

// 生成簽名
    private String getPayCustomSign(Map<String, String> bizObj, String key)
            throws Exception {

        String bizString = FormatBizQueryParaMap(bizObj, false);
        // logger.info(bizString);
        return sign(bizString, key);
    }
private String FormatBizQueryParaMap(Map<String, String> paraMap,
            boolean urlencode) throws Exception {
        String buff = "";
        try {
            List<Map.Entry<String, String>> infoIds = new ArrayList<Entry<String, String>>(
                    paraMap.entrySet());

            Collections.sort(infoIds,
                    new Comparator<Map.Entry<String, String>>() {
                        public int compare(Map.Entry<String, String> o1,
                                Map.Entry<String, String> o2) {
                            return (o1.getKey()).toString().compareTo(
                                    o2.getKey());
                        }
                    });

            for (int i = 0; i < infoIds.size(); i++) {
                Map.Entry<String, String> item = infoIds.get(i);
                // System.out.println(item.getKey());
                if (item.getKey() != "") {

                    String key = item.getKey();
                    String val = item.getValue();
                    if (urlencode) {
                        val = URLEncoder.encode(val, "utf-8");

                    }
                    buff += key + "=" + val + "&";

                }
            }

            if (buff.isEmpty() == false) {
                buff = buff.substring(0, buff.length() - 1);
            }
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
        return buff;
    }
// 生成訂單號(hào)
    private String createOrderId() {
        int machineId = 1;// 最大支持1-9個(gè)集群機(jī)器部署
        int hashCodeV = UUID.randomUUID().toString().hashCode();
        if (hashCodeV < 0) {
            hashCodeV = -hashCodeV;
        }
        return machineId + String.format("%027d", hashCodeV);
    }

    // 將拼接的字符串轉(zhuǎn)化為xml文件
    public String ArrayToXml(Map<String, String> arr) {
        String xml = "<xml>";
        Iterator<Entry<String, String>> iter = arr.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<String, String> entry = iter.next();
            String key = entry.getKey();
            String val = entry.getValue();
            xml += "<" + key + ">" + val + "</" + key + ">";
        }

        xml += "</xml>";
        return xml;
    }

    /**
     * 帶證書httpPost請求
     * 
     * @param url
     *            接口地址
     * @param param
     *            參數(shù)
     * @return
     * @throws Exception
     */
    public static String sendRedEnvelope(String url, String param)
            throws Exception {
        // PKCS12的密碼
        String PKCS12 = "";
        // 指定讀取證書格式為PKCS12
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        InputStream instream = WechatPayMgr.class
                .getResourceAsStream("apiclient_cert.p12");
        // 讀取本機(jī)存放的PKCS12證書文件
        if (instream == null) {
            instream = WechatPayMgr.class.getClassLoader().getResourceAsStream(
                    "apiclient_cert.p12");
        }
        if (instream == null) {
            instream = WechatPayMgr.class.getClassLoader()
                    .getSystemResourceAsStream("apiclient_cert.p12");
        }
        try {
            // 指定PKCS12的密碼
            keyStore.load(instream, PKCS12.toCharArray());
        } finally {
            instream.close();
        }
        // 指定TLS版本
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, PKCS12.toCharArray()).build();
        // 設(shè)置httpclient的SSLSocketFactory
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext, new String[] { "TLSv1" }, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf).build();
        StringBuffer stringBuffer = new StringBuffer();
        try {
            HttpPost httpPost = new HttpPost(url);
            InputStream is = new ByteArrayInputStream(param.getBytes("UTF-8"));
            // InputStreamEntity嚴(yán)格是對內(nèi)容和長度相匹配的暴浦。用法和BasicHttpEntity類似
            InputStreamEntity inputStreamEntity = new InputStreamEntity(is,
                    is.available());
            httpPost.setEntity(inputStreamEntity);
            CloseableHttpResponse response = httpclient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(entity.getContent(), "UTF-8"));
                String inputLine;
                while ((inputLine = reader.readLine()) != null) {
                    stringBuffer.append(inputLine);
                }
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
        return stringBuffer.toString();
    }
// 解析xml
    private Map<String, String> doXMLParse(String xml)
            throws XmlPullParserException, IOException {

        InputStream inputStream = new ByteArrayInputStream(xml.getBytes());

        Map<String, String> map = null;

        XmlPullParserFactory dbf = XmlPullParserFactory.newInstance();
        String FEATURE = null;
        FEATURE = "http://xml.org/sax/features/external-general-entities";
        dbf.setFeature(FEATURE, false);
        FEATURE = "http://xml.org/sax/features/external-parameter-entities";
        dbf.setFeature(FEATURE, false);
        FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
        dbf.setFeature(FEATURE, false);

        XmlPullParser pullParser = dbf.newPullParser();

        pullParser.setInput(inputStream, "UTF-8"); // 為xml設(shè)置要解析的xml數(shù)據(jù)

        int eventType = pullParser.getEventType();

        while (eventType != XmlPullParser.END_DOCUMENT) {
            switch (eventType) {
            case XmlPullParser.START_DOCUMENT:
                map = new HashMap<String, String>();
                break;

            case XmlPullParser.START_TAG:
                String key = pullParser.getName();
                if (key.equals("xml"))
                    break;

                // xml無法解析多層標(biāo)簽,單獨(dú)加保護(hù)(紅包查詢時(shí)需要)
                /*if (key.equals("hblist")) {
                    pullParser.next();
                    pullParser.next();
                    key = pullParser.getName();
                }*/

                String value = pullParser.nextText();
                map.put(key, value);

                break;

            case XmlPullParser.END_TAG:
                break;

            }

            eventType = pullParser.next();

        }

        return map;
    }

以上是紅包發(fā)放方法晓锻,由于發(fā)送可能被微信駁回等失敗因素歌焦,建議根據(jù)各自需求寫一個(gè)紅包是否發(fā)送成功的查詢的方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砚哆,一起剝皮案震驚了整個(gè)濱河市独撇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌躁锁,老刑警劉巖纷铣,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異战转,居然都是意外死亡搜立,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門槐秧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啄踊,“玉大人,你說我怎么就攤上這事刁标〉咄ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵膀懈,是天一觀的道長顿锰。 經(jīng)常有香客問我,道長吏砂,這世上最難降的妖魔是什么撵儿? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮狐血,結(jié)果婚禮上淀歇,老公的妹妹穿的比我還像新娘。我一直安慰自己匈织,他們只是感情好浪默,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缀匕,像睡著了一般纳决。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乡小,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天阔加,我揣著相機(jī)與錄音,去河邊找鬼满钟。 笑死胜榔,一個(gè)胖子當(dāng)著我的面吹牛胳喷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播夭织,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吭露,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了尊惰?” 一聲冷哼從身側(cè)響起讲竿,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弄屡,沒想到半個(gè)月后题禀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡琢岩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年投剥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片担孔。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡江锨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出糕篇,到底是詐尸還是另有隱情啄育,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布拌消,位于F島的核電站挑豌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏墩崩。R本人自食惡果不足惜氓英,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鹦筹。 院中可真熱鬧铝阐,春花似錦、人聲如沸铐拐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽遍蟋。三九已至吹害,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間虚青,已是汗流浹背它呀。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人钟些。 一個(gè)月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓烟号,卻偏偏與公主長得像,于是被迫代替她去往敵國和親政恍。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355