?近日,在開發(fā)微信支付、微信退款、微信付款到零錢、微信訂單查詢、微信付款到銀行卡的功能。以及其他微信API的使用。發(fā)現(xiàn)微信API的開發(fā)都是同樣的套路~~封裝參數(shù)–》包裝成Xml—》提交到Api—》獲取返回的內(nèi)容就行了。因為會有多個API都設(shè)計到這些操作,特地抽取出來封裝成工具類單獨講,學(xué)習(xí)完以下這5~8個放法、那么你的開發(fā)就很簡便了 ~ ~ 一個支付方法簡單的十五行代碼立馬搞定。希望對你們有幫助。個人淺薄的見解
???一、微信簽名的工具類 ???【溫馨提示:】數(shù)字簽名是一般開發(fā)人員容易遇到的錯誤,記住“你沒遇到數(shù)字簽名錯誤,都不好意思說自己做過微信開發(fā)”。
耐心解決就行 【Description】簡單來解釋,就是對自己要發(fā)送的數(shù)據(jù)進行加密處理、換句話說假如說你要傳遞A/B/C,就對這三者進行加密。初開發(fā)者的誤區(qū):例如看到別人代碼拿D和E等去數(shù)字簽名、然后在自己的開發(fā)中就拿D和E去簽名,這是錯誤的做法,會出現(xiàn)數(shù)字簽名錯誤。你要看一下你的開發(fā)需要傳遞D和F去后臺,那么你應(yīng)該拿D和F去簽名就對了
?package com.fh.util.weixin;?
?import java.util.Iterator;?
?import java.util.Map;?
?import java.util.Set;?
?import java.util.SortedMap;?
?import com.fh.controller.app.nrb.bargain.wxconfig;
?/**?
??* 簽名工具類?
??* @author 小鄭?
??* @date 2018年02月22日?
??* @Notice:wxconfig.apikey。這句代碼是獲取商務(wù)號設(shè)置的api秘鑰。這里不方便貼出來,?
??* 復(fù)制簽名代碼的人,需要把該常量改成自己商務(wù)號的key值。原因是Api規(guī)定了簽名必須加上自己的key值哦??
??* */
?public class SignUtils {?
?? ? /**?
?? ? ?* @param characterEncoding 編碼格式 utf-8?
?? ? ?* */
public static String creatSign(String characterEncoding,?
?? ? ? ? ? ? SortedMap parameters) {?
?? ? ? ? StringBuffer sb = new StringBuffer();?
?? ? ? ? Set es = parameters.entrySet();?
?? ? ? ? Iterator it = es.iterator();?
?? ? ? ? while(it.hasNext()) {?
?? ? ? ? ? ? Map.Entry entry = (Map.Entry)it.next();?
?? ? ? ? ? ? String k = (String)entry.getKey();?
?? ? ? ? ? ? Object v = entry.getValue();?
?? ? ? ? ? ? if(null != v && !"".equals(v)??
?? ? ? ? ? ? ? ? ? ? && !"sign".equals(k) && !"key".equals(k)) {?
?? ? ? ? ? ? ? ? sb.append(k + "=" + v + "&");?
?? ? ? ? ? ? }?
?? ? ? ? }
//wxconfig.apikey。這句代碼是獲取商務(wù)號設(shè)置的api秘鑰。這里不方便貼出來,?
?? ? ? ? //復(fù)制簽名代碼的人,需要把該常量改成自己商務(wù)號的key值。原因是Api規(guī)定了簽名必須加上自己的key值哦??
?? ? ? ? sb.append("key=" + wxconfig.apikey);?
?? ? ? ? String sign = MD5Utils.MD5Encode(sb.toString(), characterEncoding).toUpperCase();?
?? ? ? ? System.out.println(sign);?
?? ? ? ? return sign;?
?? ? }?
?}
?二、將當前的map結(jié)合轉(zhuǎn)化成xml格式 ~~ 微信請求參數(shù)是必須要封裝成Xml格式的,在java中寫xml很不方便,但是寫Map集合很方便。故需要提供map轉(zhuǎn)化xml的方法
?/**?
?? ? ?* 將Map轉(zhuǎn)換為XML格式的字符串?
?? ? ?*?
?? ? ?* @param data Map類型數(shù)據(jù)?
?? ? ?* @return XML格式的字符串?
?? ? ?* @throws Exception?
?? ? ?*/
public static String mapToXml(Map data) throws Exception {?
?? ? ? ? DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();?
?? ? ? ? DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();?
?? ? ? ? org.w3c.dom.Document document = documentBuilder.newDocument();?
?? ? ? ? org.w3c.dom.Element root = document.createElement("xml");?
?? ? ? ? document.appendChild(root);?
?? ? ? ? for (String key: data.keySet()) {?
?? ? ? ? ? ? String value = data.get(key);?
?? ? ? ? ? ? if (value == null) {?
?? ? ? ? ? ? ? ? value = "";?
?? ? ? ? ? ? }?
?? ? ? ? ? ? value = value.trim();?
?? ? ? ? ? ? org.w3c.dom.Element filed = document.createElement(key);?
?? ? ? ? ? ? filed.appendChild(document.createTextNode(value));?
?? ? ? ? ? ? root.appendChild(filed);?
?? ? ? ? }
TransformerFactory tf = TransformerFactory.newInstance();?
?? ? ? ? Transformer transformer = tf.newTransformer();?
?? ? ? ? DOMSource source = new DOMSource(document);?
?? ? ? ? transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");?
?? ? ? ? transformer.setOutputProperty(OutputKeys.INDENT, "yes");?
?? ? ? ? StringWriter writer = new StringWriter();?
?? ? ? ? StreamResult result = new StreamResult(writer);?
?? ? ? ? transformer.transform(source, result);?
?? ? ? ? String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");?
?? ? ? ? try {?
?? ? ? ? ? ? writer.close();?
?? ? ? ? }?
?? ? ? ? catch (Exception ex) {?
?? ? ? ? }?
?? ? ? ? return output;?
?? ? }
?/*?
?? ? ?* 將SortedMap 集合轉(zhuǎn)化成 xml格式?
?? ? ?*/?
?? ? public static String getRequestXml(SortedMap parameters){?
?? ? ? ? StringBuffer sb = new StringBuffer();?
?? ? ? ? sb.append("");?
?? ? ? ? Set es = parameters.entrySet();?
?? ? ? ? Iterator it = es.iterator();?
?? ? ? ? while(it.hasNext()) {?
?? ? ? ? ? ? Map.Entry entry = (Map.Entry)it.next();?
?? ? ? ? ? ? String k = (String)entry.getKey();?
?? ? ? ? ? ? String v = (String)entry.getValue();?
?? ? ? ? ? ? if ("attach".equalsIgnoreCase(k)||"body".equalsIgnoreCase(k)||"sign".equalsIgnoreCase(k)) {?
?? ? ? ? ? ? ? ? sb.append("<"+k+">"+"");?
?? ? ? ? ? ? }else {?
?? ? ? ? ? ? ? ? sb.append("<"+k+">"+v+"");?
?? ? ? ? ? ? }?
?? ? ? ? }?
?? ? ? ? sb.append("");?
?? ? ? ? return sb.toString();?
?? ? }
??三、xml轉(zhuǎn)化成map或者Bean? ?微信返回的信息是Xml格式、需要一個工具類把它解析成Map集合或者是一個Bean。方便我們?nèi)カ@取里面返回值。這里會介紹兩種方式,一種是轉(zhuǎn)化成Map集合,通過get出來使用,這個方法是通用的,第二種是轉(zhuǎn)化成Bean、這種的話不通用。每個bean基本都不大一樣,需要定制
/**?
?? ? ?* XML格式字符串轉(zhuǎn)換為Map?
?? ? ?*?
?? ? ?* @param strXML XML字符串?
?? ? ?* @return XML數(shù)據(jù)轉(zhuǎn)換后的Map?
?? ? ?* @throws Exception?
?? ? ?*/
public static Map xmlToMap(String strXML) throws Exception {?
?? ? ? ? try {?
?? ? ? ? ? ? Map data = new HashMap();?
?? ? ? ? ? ? DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();?
?? ? ? ? ? ? DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();?
?? ? ? ? ? ? InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));?
?? ? ? ? ? ? org.w3c.dom.Document doc = documentBuilder.parse(stream);?
?? ? ? ? ? ? doc.getDocumentElement().normalize();?
?? ? ? ? ? ? NodeList nodeList = doc.getDocumentElement().getChildNodes();?
?? ? ? ? ? ? for (int idx = 0; idx < nodeList.getLength(); ++idx) {?
?? ? ? ? ? ? ? ? Node node = nodeList.item(idx);?
?? ? ? ? ? ? ? ? if (node.getNodeType() == Node.ELEMENT_NODE) {?
?? ? ? ? ? ? ? ? ? ? org.w3c.dom.Element element = (org.w3c.dom.Element) node;?
?? ? ? ? ? ? ? ? ? ? data.put(element.getNodeName(), element.getTextContent());?
?? ? ? ? ? ? ? ? }?
?? ? ? ? ? ? }
? try {?
?? ? ? ? ? ? ? ? stream.close();?
?? ? ? ? ? ? } catch (Exception ex) {?
?? ? ? ? ? ? ? ? // do nothing?
?? ? ? ? ? ? }?
?? ? ? ? ? ? return data;?
?? ? ? ? } catch (Exception ex) {?
?? ? ? ? ? ? WXPayUtil.getLogger().warn("Invalid XML, can not convert to map.??
?? ? ? ? ? ? Error message: {}. XML content: {}", ex.getMessage(), strXML);?
?? ? ? ? ? ? throw ex;?
?? ? ? ? }?
?? ? }?
?//不通用的、返回Bean格式?
?//以企業(yè)付款到零錢為例子~~根據(jù)Api會返回的參數(shù),書寫一個Bean類型?
?package com.fh.entity.nrb.xiaozheng;?
?/**?
??*??
??* 企業(yè) 付款到 客戶? 的 實體類?
??* @author xiaozheng?
??* @version 1.0??
??* @description: 收集企業(yè) 支付給客戶成功后的返回信息?
??* @time : 2018-01-16 16:00:00?
??*/
?public class EnterpriceToCustomer {?
?? ? /*? ?
?? ? ? ? ?
?? ? ? ? ?
?? ? ? ? ?
?? ? ? ? ?
?? ? ? ? ?
?? ? ? ? ?
?? ? ? ? ?
?? ? ? ? ?
?? ? ? ? ?
?? ? */
private String return_code;?
?? ? private String return_msg;?
?? ? private String mchid;?
?? ? private String nonce_str;?
?? ? private String result_code;?
?? ? private String partner_trade_no;?
?? ? private String payment_no;?
?? ? private String payment_time;?
/*?
?? ? ?* 支付錯誤時,返回的代碼?
?? ? ?*? key是:return_code,值是:SUCCESS?
?? ? ? ? key是:return_msg,值是:支付失敗?
?? ? ? ? key是:mch_appid,值是:wx49c22ad731b679c3?
?? ? ? ? key是:mchid,值是:1488323162?
?? ? ? ? key是:result_code,值是:FAIL?
?? ? ? ? key是:err_code,值是:AMOUNT_LIMIT?
?? ? ? ? key是:err_code_des,值是:付款金額超出限制。低于最小金額1.00元或累計超過20000.00元。?
?? ? ?*??
?? ? ?*/
private String err_code;?
?? ? private String err_code_des;?
?? ? public String getErr_code() {?
?? ? ? ? return err_code;?
?? ? }?
?? ? public void setErr_code(String errCode) {?
?? ? ? ? err_code = errCode;?
?? ? }?
?? ? public String getErr_code_des() {?
?? ? ? ? return err_code_des;?
?? ? }?
?? ? public void setErr_code_des(String errCodeDes) {?
?? ? ? ? err_code_des = errCodeDes;?
?? ? }?
?? ? public String getReturn_code() {?
?? ? ? ? return return_code;?
?? ? }
public void setReturn_code(String returnCode) {?
?? ? ? ? return_code = returnCode;?
?? ? }?
?? ? public String getReturn_msg() {?
?? ? ? ? return return_msg;?
?? ? }?
?? ? public void setReturn_msg(String returnMsg) {?
?? ? ? ? return_msg = returnMsg;?
?? ? }?
?? ? public String getMchid() {?
?? ? ? ? return mchid;?
?? ? }?
?? ? public void setMchid(String mchid) {?
?? ? ? ? this.mchid = mchid;?
?? ? }
? public String getNonce_str() {?
?? ? ? ? return nonce_str;?
?? ? }?
?? ? public void setNonce_str(String nonceStr) {?
?? ? ? ? nonce_str = nonceStr;?
?? ? }?
?? ? public String getResult_code() {?
?? ? ? ? return result_code;?
?? ? }?
?? ? public void setResult_code(String resultCode) {?
?? ? ? ? result_code = resultCode;?
?? ? }?
?? ? public String getPartner_trade_no() {?
?? ? ? ? return partner_trade_no;?
?? ? }?
?? ? public void setPartner_trade_no(String partnerTradeNo) {?
?? ? ? ? partner_trade_no = partnerTradeNo;?
?? ? }?
?? ? public String getPayment_no() {?
?? ? ? ? return payment_no;?
?? ? }
? public String getPayment_time() {?
?? ? ? ? return payment_time;?
?? ? }?
?? ? public void setPayment_time(String paymentTime) {?
?? ? ? ? payment_time = paymentTime;?
?? ? }?
?? ? @Override
public String toString() {?
?? ? ? ? return "EnterpriceToCustomer [err_code=" + err_code + ", err_code_des="?
?? ? ? ? ? ? ? ? + err_code_des + ", mchid=" + mchid + ", nonce_str="?
?? ? ? ? ? ? ? ? + nonce_str + ", partner_trade_no=" + partner_trade_no?
?? ? ? ? ? ? ? ? + ", payment_no=" + payment_no + ", payment_time="?
?? ? ? ? ? ? ? ? + payment_time + ", result_code=" + result_code?
?? ? ? ? ? ? ? ? + ", return_code=" + return_code + ", return_msg=" + return_msg?
?? ? ? ? ? ? ? ? + "]";?
?? ? }?
?}?
?/**??
?? ? 下面是需要通過跟節(jié)點,找找到對應(yīng)的類屬性,手動把它set進去。因此API返回的參數(shù)不一樣。需要寫每個返回的Bean??磦€人的習(xí)慣唄~~我喜歡用bean存儲數(shù)據(jù)的方式?
?? ? * 解析企業(yè)支付申請??
?? ? * 解析的時候自動去掉CDMA??
?? ? * @param xml??
?? ? */?
? @SuppressWarnings("unchecked")??
?? ? public static EnterpriceToCustomer parseXmlToMapEnterpriceToCustomer(String xml){??
?? ? ? ? ? ? EnterpriceToCustomer enterpriceToCustomer = new EnterpriceToCustomer();??
?? ? ? ? ? ? try {??
?? ? ? ? ? ? ? ? ? ? StringReader read = new StringReader(xml);??
?? ? ? ? ? ? ? ? ? ? // 創(chuàng)建新的輸入源SAX 解析器將使用 InputSource 對象來確定如何讀取 XML 輸入??
?? ? ? ? ? ? ? ? ? ? InputSource source = new InputSource(read);??
?? ? ? ? ? ? ? ? ? ? // 創(chuàng)建一個新的SAXBuilder??
?? ? ? ? ? ? ? ? ? ? SAXBuilder sb = new SAXBuilder();??
?? ? ? ? ? ? ? ? ? ? // 通過輸入源構(gòu)造一個Document??
?? ? ? ? ? ? ? ? ? ? Document doc;??
?? ? ? ? ? ? ? ? ? ? doc = (Document) sb.build(source);?
Element root = doc.getRootElement();// 指向根節(jié)點??
?? ? ? ? ? ? ? ? ? ? List list = root.getChildren();??
?? ? ? ? ? ? ? ? ? ? if(list!=null&&list.size()>0){??
?? ? ? ? ? ? ? ? ? ? for (Element element : list) {??
?? ? ? ? ? ? ? ? ? ? ? ? System.out.println("key是:"+element.getName()+",值是:"+element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? if("return_code".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setReturn_code(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? }?
if("return_msg".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setReturn_msg(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? }??
?? ? ? ? ? ? ? ? ? ? ? ? if("mchid".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setMchid(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? }?
?? ? ? ? ? ? ? ? ? ? ? ? if("nonce_str".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setNonce_str(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? }?
?? ? ? ? ? ? ? ? ? ? ? ? if("result_code".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setResult_code(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? }?
?? ? ? ? ? ? ? ? ? ? ? ? if("partner_trade_no".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setPartner_trade_no(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? }?
?? ? ? ? ? ? ? ? ? ? ? ? if("payment_no".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setPayment_no(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? }?
?? ? ? ? ? ? ? ? ? ? ? ? if("payment_time".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setPayment_time(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? }? ?
? ? ? //錯誤的編碼?
?? ? ? ? ? ? ? ? ? ? ? ? /*?
?? ? ? ? ? ? ? ? ? ? ? ? ? ?private String err_code;?
?? ? ? ? ? ? ? ? ? ? ? ? ? ?private String err_code_des;?
?? ? ? ? ? ? ? ? ? ? ? ? ?* */?
?? ? ? ? ? ? ? ? ? ? ? ? if("err_code".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setErr_code(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? }?
?? ? ? ? ? ? ? ? ? ? ? ? if("err_code_des".equals(element.getName())){??
?? ? ? ? ? ? ? ? ? ? ? ? ? ? enterpriceToCustomer.setErr_code_des(element.getText());??
?? ? ? ? ? ? ? ? ? ? ? ? }? ??
?? ? ? ? ? ? ? ? ? ? }?
?? ? ? ? ? ? ? ? }
? } catch (JDOMException e) {??
?? ? ? ? ? ? e.printStackTrace();??
?? ? ? ? ? ? } catch (IOException e) {??
?? ? ? ? ? ? e.printStackTrace();??
?? ? ? ? ? ? }catch (Exception e) {??
?? ? ? ? ? ? e.printStackTrace();??
?? ? ? ? ? ? }??
?? ? ? ? ? ? return enterpriceToCustomer;??
?? ? ? ? }?
??四、Post請求+證書~~親測可以的
package com.fh.entity.nrb.weixinResult;?
?import java.io.File;??
?import java.io.FileInputStream;??
?import java.security.KeyStore;??
?import javax.net.ssl.SSLContext;??
?import org.apache.http.HttpEntity;??
?import org.apache.http.client.methods.CloseableHttpResponse;??
?import org.apache.http.client.methods.HttpPost;??
?import org.apache.http.conn.ssl.SSLConnectionSocketFactory;??
?import org.apache.http.conn.ssl.SSLContexts;??
?import org.apache.http.entity.StringEntity;??
?import org.apache.http.impl.client.CloseableHttpClient;??
?import org.apache.http.impl.client.HttpClients;??
?import org.apache.http.util.EntityUtils;??
?import com.fh.controller.app.nrb.bargain.wxconfig;
?/**??
?* This example demonstrates how to create secure connections with a custom SSL??
?* context.??
?*/?
?public class ClientCustomSSL {??
?@SuppressWarnings("deprecation")?
?public static String doRefund(String url,String data) throws Exception {??
?? ? ? ? /**??
?? ? ? ? * 注意PKCS12證書 是從微信商戶平臺-》賬戶設(shè)置-》 API安全 中下載的??
?? ? ? ? */??
?? ? ? ? KeyStore keyStore = KeyStore.getInstance("PKCS12");??
?? ? ? ? /**?
?? ? ? ? *此處要改?
?? ? ? ? *wxconfig.SSLCERT_PATH : 指向你的證書的絕對路徑,帶著證書去訪問?
?? ? ? ? */
FileInputStream instream = new FileInputStream(new File(wxconfig.SSLCERT_PATH));//P12文件目錄??
?? ? ? ? try {??
?? ? ? ? /**??
?? ? ? ? * 此處要改??
?? ? ? ? *??
?? ? ? ? * 下載證書時的密碼、默認密碼是你的MCHID mch_id?
?? ? ? ? * */??
?? ? ? ? keyStore.load(instream, wxconfig.SSLCERT_PASSWORD.toCharArray());//這里寫密碼?
?? ? ? ? } finally {??
?? ? ? ? ? ? instream.close();??
?? ? ? ? }??
// Trust own CA and all self-signed certs??
?? ? ? ? /**??
?? ? ? ? * 此處要改??
?? ? ? ? * 下載證書時的密碼、默認密碼是你的MCHID mch_id?
?? ? ? ? * */??
?? ? ? ? SSLContext sslcontext = SSLContexts.custom()??
?? ? ? ? .loadKeyMaterial(keyStore, wxconfig.SSLCERT_PASSWORD.toCharArray())//這里也是寫密碼的??
?? ? ? ? .build();??
?? ? ? ? // Allow TLSv1 protocol only??
?? ? ? ? SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(??
?? ? ? ? sslcontext,??
?? ? ? ? new String[] { "TLSv1" },??
?? ? ? ? null,??
?? ? ? ? SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);??
?? ? ? ? CloseableHttpClient httpclient = HttpClients.custom()??
?? ? ? ? .setSSLSocketFactory(sslsf)??
?? ? ? ? .build();??
?? ? ? ? try {??
?? ? ? ? HttpPost httpost = new HttpPost(url); // 設(shè)置響應(yīng)頭信息??
?? ? ? ? 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"));??
?? ? ? ? CloseableHttpResponse response = httpclient.execute(httpost);?
? try {??
?? ? ? ? HttpEntity entity = response.getEntity();??
?? ? ? ? String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");??
?? ? ? ? EntityUtils.consume(entity);??
?? ? ? ? return jsonStr;??
?? ? ? ? } finally {??
?? ? ? ? response.close();??
?? ? ? ? }??
?? ? ? ? } finally {??
?? ? ? ? httpclient.close();??
?? ? ? ? }??
?? ? }??
?}?