import com.alibaba.fastjson.JSONObject;
import com.bhudy.entity.BhudyPlugin;
import com.bhudy.service.BhudyPluginService;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.MessageDigest;
import java.util.*;

/**
 * Created by Administrator on 2019/8/23/023.
 */
@Component
public final class WeChatUtils {

    @Autowired
    private WeChatUtils(BhudyPluginService bhudyPluginService) {
        WeChatUtils.bhudyPluginService = bhudyPluginService;
    }

    private static BhudyPluginService bhudyPluginService; // 获取微信appid的接口

    private static Map<String, String> tokenMap = null;

    public static String wxGzhWorkOrder = "xxxxx"; // 工单状态通知Key
    public static String weGzhReport = "xxxxxx"; // 报告生成通知Key


    private static String authorizationCode = "authorization_code"; // 微信调用接口使用参数authorization_code
    private static String clientCredential = "client_credential"; // 微信调用接口使用参数client_credential


    /**
     * 发送报告生成通知
     * 报告生成通知Id: P9U-LYY4qtcKKqSoDb7sfqK4GlFQvDu8G5JxWOTkUQk
     * <p>
     * {{first.DATA}}
     * 报告类型:{{keyword1.DATA}}
     * 生成时间:{{keyword2.DATA}}
     * {{remark.DATA}}
     *
     * @return 是否发送成功
     */
    public static boolean sendWeGzhReport(String openId, String first, String remark, Map<String, Object> keywordMap) {
        return sendWxGzh(openId, WeChatUtils.weGzhReport, first, remark, keywordMap);
    }

    /**
     * 发送微信公众号工单消息提醒
     * 工单模板信息id: i5JtheQBLYM9VyByYR2EqrGlbdZiiFZVyA7rndbOAuM
     * <p>
     * {{first.DATA}}
     * 工单编号:{{keyword1.DATA}}
     * 工单标题:{{keyword2.DATA}}
     * 时间:{{keyword3.DATA}}
     * {{remark.DATA}}
     *
     * @return 是否发送成功
     */
    public static boolean sendWxGzhWorkOrder(String openId, String first, String remark, Map<String, Object> keywordMap) {
        return sendWxGzh(openId, WeChatUtils.wxGzhWorkOrder, first, remark, keywordMap);
    }

    /**
     * 发送微信公众号信息
     * <p>
     * 参数  是否必填   说明
     * touser  是  接收者openid
     * template_id 是  模板ID
     * url 否  模板跳转链接(海外帐号没有跳转能力)
     * miniprogram 否  跳小程序所需数据,不需跳小程序可不用传该数据
     * appid   是  所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏)
     * pagepath    否  所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),要求该小程序已发布,暂不支持小游戏
     * data    是  模板数据
     * color   否  模板内容字体颜色,不填默认为黑色
     * <p>
     * json数据模板
     * {"touser":"OPENID","template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY","url":"http://weixin.qq.com/download",
     * "miniprogram":{"appid":"xiaochengxuappid12345","pagepath":"index?foo=bar"},"data":{"first":{"value":"恭喜你购买成功!","color":"#173177"},
     * "keyword1":{"value":"巧克力","color":"#173177"},"keyword2":{"value":"39.8元","color":"#173177"},"keyword3":{"value":"2014年9月22日","color":"#173177"},
     * "remark":{"value":"欢迎再次购买!","color":"#173177"}}}
     *
     * @param openId     接收消息的用户openid
     * @param templateId 消息模板id
     * @param first      标题
     * @param remark     结尾
     * @param keywordMap 内容map
     * @return 是否发送成功
     */
    public static boolean sendWxGzh(String openId, String templateId, String first, String remark, Map<String, Object> keywordMap) {
        if (openId == null || openId.equals("")) return false;

        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + WeChatUtils.getToken(BhudyPlugin.TENCENT_TAS);
        Map<String, Object> map = new HashMap<>();
        map.put("touser", openId);
        map.put("template_id", templateId);
        map.put("url", null);

        Map<String, Object> miniprogramMap = new HashMap<>();


        miniprogramMap.put("appid", bhudyPluginService.getBhudyPluginDataByType(BhudyPlugin.TENCENT_TAS).get(BhudyPlugin.appId));
        //miniprogramMap.put("pagepath", "index");
        map.put("miniprogram", miniprogramMap);

        Map<String, Object> dataMap = new HashMap<>();

        Map firstMap = new HashMap<>();
        firstMap.put("value", first);
        dataMap.put("first", firstMap);

        for (Map.Entry entrySet : keywordMap.entrySet()) {
            Map keyword1Map = new HashMap<>();
            keyword1Map.put("value", entrySet.getValue());
            dataMap.put(entrySet.getKey().toString(), keyword1Map);
        }

        Map remarkMap = new HashMap<>();
        remarkMap.put("value", remark);
        dataMap.put("remark", remarkMap);

        map.put("data", dataMap);

        Map<String, Object> resultMap = WeChatUtils.wxReqDataPost(url, JSONObject.toJSONString(map));
        return resultMap != null;
    }

    /**
     * 获取用户基本信息(UnionID机制)
     * 在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的。对于不同公众号,同一用户的openid不同)。公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称、头像、性别、所在城市、语言和关注时间。
     * 请注意,如果开发者有在多个公众号,或在公众号、移动应用之间统一用户帐号的需求,需要前往微信开放平台(open.weixin.qq.com)绑定公众号后,才可利用UnionID机制来满足上述需求。
     * <p>
     * 参数  是否必须   说明
     * access_token    是  调用接口凭证
     * openid  是  普通用户的标识,对当前公众号唯一
     * lang    否  返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语
     * ***********************************
     *
     * @return <br>
     * 参数  说明
     * subscribe   用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
     * openid  用户的标识,对当前公众号唯一
     * nickname    用户的昵称
     * sex 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
     * city    用户所在城市
     * country 用户所在国家
     * province    用户所在省份
     * language    用户的语言,简体中文为zh_CN
     * headimgurl  用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
     * subscribe_time  用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
     * unionid 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
     * remark  公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
     * groupid 用户所在的分组ID(兼容旧的用户分组接口)
     * tagid_list  用户被打上的标签ID列表
     * subscribe_scene 返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENEPROFILE LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_OTHERS 其他
     * qr_scene    二维码扫码场景(开发者自定义)
     * qr_scene_str    二维码扫码场景描述(开发者自定义)
     * UnionID
     */
    public static Map<String, Object> getUserInfo(String openId, Integer type) {
        String url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=" + WeChatUtils.getToken(type) + "&openid=" + openId + "&lang=zh_CN";
        Map resultMap = WeChatUtils.wxReqDataGet(url);
        return resultMap;
    }

    /**
     * 获取公众号用户列表
     * 公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。
     * <p>
     * 参数  是否必须   说明
     * access_token    是  调用接口凭证
     * next_openid 是  第一个拉取的OPENID,不填默认从头开始拉取
     *
     * @param nextOpenid 第一个拉取的OPENID,不填默认从头开始拉取
     * @return <br>
     * 参数    说明
     * total   关注该公众账号的总用户数
     * count   拉取的OPENID个数,最大值为10000
     * data    列表数据,OPENID的列表
     * next_openid 拉取列表的最后一个用户的OPENID
     */
    public static Map<String, Object> getOpenIdListMap(String nextOpenid) {
        String url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + getToken(BhudyPlugin.TENCENT_TAS);
        if (nextOpenid != null && nextOpenid.equals("")) {
            url += "&next_openid=" + nextOpenid;
        }

        Map resultMap = WeChatUtils.wxReqDataGet(url);
        return resultMap;
    }

    /**
     * @param type 1是公众号请求
     * @return * * *
     * 属性 类型 说明
     * access_token    string 获取到的凭证
     * expires_in  number 凭证有效时间,单位:秒。目前是7200秒之内的值。
     * errcode number 错误码
     * errmsg  string 错误信息
     * <p>
     * =====================================
     * <p>
     * errcode 的合法值
     * 值   说明 最低版本
     * -1  系统繁忙,此时请开发者稍候再试
     * 0   请求成功
     * 40001   AppSecret 错误或者 AppSecret 不属于这个小程序,请开发者确认 AppSecret 的正确性
     * 40002   请确保 grant_type 字段值为 client_credential
     * 40013   不合法的 AppID,请开发者检查 AppID 的正确性,避免异常字符,注意大小写
     */
    public static String getToken(Integer type) {
        Map<String, String> tokenMap = WeChatUtils.tokenMap;
        // 微信的access_token有效期是7200秒,所以我们的过期时间要比微信的快token
        if (tokenMap != null && Utils.formatLong(tokenMap.get("date")) >= (new Date().getTime() + (7200 * 1000))) {
            return tokenMap.get("access_token");
        }

        Map<String, String> weChatMap = bhudyPluginService.getBhudyPluginDataByType(type);
        String url = "https://api.weixin.qq.com/cgi-bin/token?appid=" + weChatMap.get(BhudyPlugin.appId) + "&secret=" + weChatMap.get(BhudyPlugin.appSecret) + "&grant_type=" + clientCredential;

        Map<String, Object> resultMap = WeChatUtils.wxReqDataGet(url);
        if (resultMap == null) throw new BhudyException(BhudyExceptionCode.CODE_29);

        String token = (String) resultMap.get("access_token");
        WeChatUtils.tokenMap = new HashMap<>();
        WeChatUtils.tokenMap.put("date", String.valueOf(new Date().getTime()));
        WeChatUtils.tokenMap.put("access_token", token);

        return token;
    }


    /**
     * @param code string 是    登录时获取的 code
     * @return * * *
     * 属性  类型 说明
     * openid  string 用户唯一标识
     * session_key string 会话密钥
     * unionid string 用户在开放平台的唯一标识符,在满足 UnionID 下发条件的情况下会返回,详见 UnionID 机制说明。
     * errcode number 错误码
     * errmsg  string 错误信息
     * <p>
     * ===================================
     * <p>
     * errcode 的合法值
     * 值   说明 最低版本
     * -1  系统繁忙,此时请开发者稍候再试
     * 0   请求成功
     * 40029   code 无效
     * 45011   频率限制,每个用户每分钟100次
     */
    public static Map<String, Object> getOpenIdAndSessionKey(String code, Integer type) {
        Map<String, String> weChatMap = bhudyPluginService.getBhudyPluginDataByType(type);
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + weChatMap.get(BhudyPlugin.appId) + "&secret=" + weChatMap.get(BhudyPlugin.appSecret) + "&grant_type=" + authorizationCode + "&js_code=" + code;
        return WeChatUtils.wxReqDataGet(url);
    }


    /**
     * 微信Post请求
     * 如果微信端返回错误码或者没有返回数据,这个方法直接返回null
     * 该方法没有使用线程,可能会卡死
     *
     * @param url    请求的url
     * @param params
     * @return
     */
    public static Map<String, Object> wxReqDataPost(String url, String params) {
        try {
            Map<String, Object> reulstMap = Utils.reqPost(url, params);
            if (reulstMap == null || (reulstMap.containsKey("errcode") && (Integer) reulstMap.get("errcode") != 0)) {
                return null;
            }
            return reulstMap;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 微信Get请求
     * 如果微信端返回错误码或者没有返回数据,这个方法直接返回null
     * 该方法没有使用线程,可能会卡死
     *
     * @param url 请求的url
     * @return
     */
    public static Map<String, Object> wxReqDataGet(String url) {
        try {
            Map<String, Object> reulstMap = Utils.reqGetMap(url);
            if (reulstMap == null || (reulstMap.containsKey("errcode") && (Integer) reulstMap.get("errcode") != 0)) {
                return null;
            }
            return reulstMap;
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 接收事件推送
     * 用法@RequestMapping(value = "/wx/api/v1/receiveEventPush.do", method = RequestMethod.POST, consumes = {"application/xml", "text/xml"}, produces = {"application/xml;charset=utf-8", "text/xml;charset=utf-8"})
     * public Object receiveEventPush(@RequestBody DOMSource domSource) {
     * return WxUtils.receiveEventPush(domSource);
     * }
     *
     * @param domSource
     * @return * * *
     * <p>
     * 目录 MsgType Event
     * 1 关注/取消关注事件
     * 2 扫描带参数二维码事件
     * 3 上报地理位置事件
     * 4 自定义菜单事件
     * 5 点击菜单拉取消息时的事件推送
     * 6 点击菜单跳转链接时的事件推送
     * <p>
     * <p>
     * 》》》1.关注/取消关注事件《《《
     * 参数  描述
     * ToUserName  开发者微信号
     * FromUserName    发送方帐号(一个OpenID)
     * CreateTime  消息创建时间 (整型)
     * MsgType 消息类型,event
     * Event   事件类型,subscribe(订阅)、unsubscribe(取消订阅)
     * <p>
     * <p>
     * 》》》2.扫描带参数二维码事件《《《
     * 参数  描述
     * ToUserName  开发者微信号
     * FromUserName    发送方帐号(一个OpenID)
     * CreateTime  消息创建时间 (整型)
     * MsgType 消息类型,event
     * Event   事件类型,subscribe
     * EventKey    事件KEY值,qrscene_为前缀,后面为二维码的参数值
     * Ticket  二维码的ticket,可用来换取二维码图片
     * <p>
     * <p>
     * 》》》3.上报地理位置事件《《《
     * 参数  描述
     * ToUserName  开发者微信号
     * FromUserName    发送方帐号(一个OpenID)
     * CreateTime  消息创建时间 (整型)
     * MsgType 消息类型,event
     * Event   事件类型,LOCATION
     * Latitude    地理位置纬度
     * Longitude   地理位置经度
     * Precision   地理位置精度
     * <p>
     * <p>
     * 》》》5.点击菜单拉取消息时的事件推送《《《
     * 参数  描述
     * ToUserName  开发者微信号
     * FromUserName    发送方帐号(一个OpenID)
     * CreateTime  消息创建时间 (整型)
     * MsgType 消息类型,event
     * Event   事件类型,CLICK
     * EventKey    事件KEY值,与自定义菜单接口中KEY值对应
     * <p>
     * <p>
     * 》》》6.点击菜单跳转链接时的事件推送《《《
     * 参数  描述
     * ToUserName  开发者微信号
     * FromUserName    发送方帐号(一个OpenID)
     * CreateTime  消息创建时间 (整型)
     * MsgType 消息类型,event
     * Event   事件类型,VIEW
     * EventKey    事件KEY值,设置的跳转URL
     * <p>
     * <p>
     * MsgType
     * 消息类型,接收事件推送为event
     * 消息类型,文本为text
     * 消息类型,图片为image
     * 消息类型,语音为voice
     * 消息类型,视频为video
     * 消息类型,音乐为music
     * 消息类型,图文为news
     */
    public static String receiveEventPush(DOMSource domSource) {
        Map<String, Object> xmlMap = domSourceToMap(domSource);

        if (xmlMap == null) return "";

        String msgType = (String) xmlMap.get("MsgType");
        String fromUserName = (String) xmlMap.get("FromUserName");
        String toUserName = (String) xmlMap.get("ToUserName");
        String event = (String) xmlMap.get("Event");
        String text;
        if (msgType.equals("event")) {
            if (event.equals("subscribe")) {
                // 关注事件
                text = "关注事件";
            } else if (event.equals("unsubscribe")) {
                // 取消关注事件
                text = "取消关注事件";
            } else {
                text = "对不起,无法识别消息类型";
            }
        } else if (msgType.equals("text")) {
            // 消息类型,为text
            text = "消息类型,文本为text";
        } else if (msgType.equals("image")) {
            // 消息类型,图片为image
            text = "消息类型,图片为image";
        } else if (msgType.equals("voice")) {
            // 消息类型,语音为voice
            text = "消息类型,语音为voice";
        } else if (msgType.equals("video")) {
            // 消息类型,视频为video
            text = "消息类型,视频为video";
        } else if (msgType.equals("music")) {
            // 消息类型,音乐为music
            text = "消息类型,音乐为music";
        } else if (msgType.equals("news")) {
            // 消息类型,图文为news
            text = "消息类型,图文为news";
        } else {
            text = "对不起,无法识别消息类型";
        }

        String returnData = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" +
                "    <xml>" +
                "        <Content>" + text + "</Content>" +
                "        <ToUserName>" + fromUserName + "</ToUserName>" +
                "        <FromUserName>" + toUserName + "</FromUserName>" +
                "        <CreateTime>" + new Date().getTime() / 1000 + "</CreateTime>" +
                "        <MsgType>text</MsgType>" +
                "    </xml>";

        //输出格式化后的json
        return returnData;
    }

    private static Map<String, Object> domSourceToMap(DOMSource domSource) {
        try {
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(domSource, result);

            SAXBuilder sb = new SAXBuilder();
            Document doc = sb.build(new StringReader(writer.toString()));
            Element root = doc.getRootElement();

            JSONObject json = new JSONObject();
            json.put(root.getName(), iterateElement(root));

            Map<String, Object> dataMap = JSONObject.parseObject(json.toJSONString(), Map.class);
            Map<String, Object> xmlMap = (Map<String, Object>) dataMap.get("xml");
            return xmlMap;
        } catch (TransformerConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JDOMException e) {
            e.printStackTrace();
        }

        return null;
    }

    private static JSONObject iterateElement(Element element) {
        List<Element> node = element.getChildren();
        JSONObject obj = new JSONObject();
        List list = null;
        for (Element child : node) {
            list = new LinkedList();
            String text = child.getTextTrim();
            if (text == null || text.equals("")) {
                if (child.getChildren().size() == 0) {
                    continue;
                }
                if (obj.containsKey(child.getName())) {
                    list = (List) obj.get(child.getName());
                }
                list.add(iterateElement(child)); //遍历child的子节点
                obj.put(child.getName(), list);
            } else {
                if (obj.containsKey(child.getName())) {
                    Object value = obj.get(child.getName());
                    try {
                        list = (List) value;
                    } catch (ClassCastException e) {
                        list.add(value);
                    }
                }
                if (child.getChildren().size() == 0) { //child无子节点时直接设置text
                    obj.put(child.getName(), text);
                } else {
                    list.add(text);
                    obj.put(child.getName(), list);
                }
            }
        }
        return obj;
    }

    /**
     * 验证微信绑定服务器的方法
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        //1.定义数组存放tooken,timestamp,nonce
        String[] arr = {"7i6L5SEu4NPuYiGVAXMy0ZnFxd6", timestamp, nonce};

        //2.对数组进行排序
        Arrays.sort(arr);

        //3.生成字符串
        StringBuffer sb = new StringBuffer();
        for (String s : arr) {
            sb.append(s);
        }

        //4.sha1加密,网上均有现成代码
        String temp = getSha(sb.toString());

        //5.将加密后的字符串,与微信传来的加密签名比较,返回结果
        return temp.equals(signature);
    }


    public static String getSha(String str) {
        if (str == null || str.length() == 0) {
            return null;
        }
        char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {

            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");

            mdTemp.update(str.getBytes("UTF-8"));


            byte[] md = mdTemp.digest();

            int j = md.length;

            char buf[] = new char[j * 2];

            int k = 0;

            for (int i = 0; i < j; i++) {

                byte byte0 = md[i];

                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];

                buf[k++] = hexDigits[byte0 & 0xf];

            }

            return new String(buf);

        } catch (Exception e) {

            // TODO: handle exception

            return null;

        }

    }


}

微信工具类需要的其他方法 

/**
 * 发送HttpPost请求
 *
 * @param strURL 服务地址
 * @param params json字符串,例如: "{ \"id\":\"12345\" }" ;其中属性名必须带双引号<br/>
 * @return 成功:返回json字符串<br/>
 */
public static Map<String, Object> reqPost(String strURL, String params) {
    BufferedReader reader;
    try {
        URL url = new URL(strURL);// 创建连接
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setUseCaches(false);
        connection.setInstanceFollowRedirects(true);
        connection.setRequestMethod("POST"); // 设置请求方式
        connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式
        connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式
        connection.connect();
        //一定要用BufferedReader 来接收响应, 使用字节来接收响应的方法是接收不到内容的
        OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // utf-8编码
        out.append(params);
        out.flush();
        out.close();
        // 读取响应
        reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
        String line;
        String res = "";
        while ((line = reader.readLine()) != null) {
            res += line;
        }
        reader.close();

        return JSON.parseObject(res, Map.class);
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

/**
 * 请求url
 *
 * @param url
 * @return
 */
public static Map<String, Object> reqGetMap(String url) {
    try {
        URL reqURL = new URL(url);
        HttpsURLConnection openConnection = (HttpsURLConnection) reqURL.openConnection();
        openConnection.setConnectTimeout(10000);
        //这里我感觉获取openid的时间比较长,不过也可能是我网络的问题,
        //所以设置的响应时间比较长
        openConnection.connect();
        InputStream in = openConnection.getInputStream();

        StringBuilder builder = new StringBuilder();
        BufferedReader bufreader = new BufferedReader(new InputStreamReader(in));
        for (String temp = bufreader.readLine(); temp != null; temp = bufreader
                .readLine()) {
            builder.append(temp);
        }

        String result = builder.toString();
        in.close();
        openConnection.disconnect();

        Map<String, Object> resultMap = JSON.parseObject(result, Map.class);

        return resultMap;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}