微信支付JSAPI支付

記一次微信支付JSAPI支付功能集成。

JSAPI支付前提是必須在微信環(huán)境中(公眾號(hào)艰额、聊天界面打開鏈接)臂港,否則無(wú)法調(diào)起支付卿捎。小程序webview控件中也無(wú)法調(diào)起支付。

準(zhǔn)備工作:
1.首先在微信商戶號(hào)中開通JSAPI支付功能(ps:我的一打開就是開通的径密,可能之前的同事開通的午阵,so開通流程無(wú)法復(fù)現(xiàn))。開通方式如下圖:

image.png

2.申請(qǐng)開通之后在開發(fā)配置中添加域名,按照提示添加即可底桂。
3.然后登錄微信公眾號(hào)后臺(tái)植袍,左側(cè)菜單欄最下方,點(diǎn)擊接口權(quán)限籽懦,然后左側(cè)找到網(wǎng)頁(yè)授權(quán)于个,點(diǎn)擊其右邊修改,在到新頁(yè)面網(wǎng)頁(yè)授權(quán)域名欄點(diǎn)右邊設(shè)置暮顺,添加自己的支付鏈接域名厅篓。步驟圖示:
image.png

image.png

image.png

準(zhǔn)備工作完成。
開發(fā)工作 使用vue寫的頁(yè)面

1.由于JSAPI支付時(shí)需要用戶openid捶码,所以先獲取openid
1.1 在頁(yè)面js中加入以下代碼:

reload(){
      let redirect_uri = window.location.href;
      let state = window.location.href;
      window.location.
    }

代碼中的API.APPID要換成自己的公眾號(hào)AppId羽氮,其他字段可繼續(xù)使用。
scope參數(shù)的值有兩個(gè)可選惫恼,一個(gè)是snsapi_base档押,另一個(gè)是snsapi_userinfo。
關(guān)于網(wǎng)頁(yè)授權(quán)的兩種scope的區(qū)別說(shuō)明

1.1.1祈纯、以snsapi_base為scope發(fā)起的網(wǎng)頁(yè)授權(quán)令宿,是用來(lái)獲取進(jìn)入頁(yè)面的用戶的openid的,并且是靜默授權(quán)并自動(dòng)跳轉(zhuǎn)到回調(diào)頁(yè)的腕窥。用戶感知的就是直接進(jìn)入了回調(diào)頁(yè)(往往是業(yè)務(wù)頁(yè)面)

1.1.2粒没、以snsapi_userinfo為scope發(fā)起的網(wǎng)頁(yè)授權(quán),是用來(lái)獲取用戶的基本信息的油昂。但這種授權(quán)需要用戶手動(dòng)同意革娄,并且由于用戶同意過(guò),所以無(wú)須關(guān)注冕碟,就可在授權(quán)后獲取該用戶的基本信息拦惋。
這里我們只是獲取用戶openid,無(wú)需用戶手動(dòng)同意安寺,所以用snsapi_base厕妖。

在頁(yè)面打開時(shí)判斷openid是否已獲取,未獲取時(shí)調(diào)用reload()方法挑庶。

initData(){
      let self = this
      if(self.getQueryParam("code")){
          let code = self.getQueryParam("code") //getQueryParam()方法在下方
        API.request({  //api.js 文件在下方言秸。
            url:"自己的后臺(tái)接口",
            type:'請(qǐng)求方式',  //get  post
            data:{
              code:code //頁(yè)面通過(guò)reload()方法獲取到的code 重定向后參數(shù)是拼接在頁(yè)面鏈接上的 需要自己獲取 。
            },
            success:res=>{
              if(res.errcode === 200 && res.data != undefined){
                self.$data.openID = res.data
              }else{
                self.reload();
              }
            }
        })
      }else{
        self.reload()
      }
 }
    getQueryParam(variable){
       var query = window.location.search.substring(1);
       var vars = query.split("&");
       for (var i=0;i<vars.length;i++) {
            var pair = vars[i].split("=");
            if(pair[0] == variable){
               return pair[1];
            }
       }
       return(false);
    }

后臺(tái)通過(guò)前端傳的code參數(shù)迎捺,獲取到用戶openid后返回給前端保存举畸。
2.下單
用戶點(diǎn)擊頁(yè)面支付功能后,前端調(diào)用后臺(tái)接口生成預(yù)付單并返回?cái)?shù)據(jù)凳枝,前端解析詩(shī)句獲取各種參數(shù)然后入下:

pay(){
      let self = this
      API.request({
        url:"自己的下單接口",
        type:'POST',
        data:{
           //下單需要的參數(shù)
        },
        success:res=>{
          if(res.errcode === 200){
            let data = res.data
            //下面代碼調(diào)起微信支付
            WeixinJSBridge.invoke(
              'getBrandWCPayRequest', {
                "appId":data .appid,     //公眾號(hào)id     
                "timeStamp":data .timeStamp,         //時(shí)間戳抄沮,自1970年以來(lái)的秒數(shù)     
                "nonceStr":data .nonceStr, //隨機(jī)串     
                "package":data .package,     
                "signType":"MD5",         //微信簽名方式:通用參數(shù) 可不改 
                "paySign":data .paySign //微信簽名 
              },
              function(res){
                  if(res.err_msg == "get_brand_wcpay_request:ok" ){
                  // 使用以上方式判斷前端返回,微信團(tuán)隊(duì)鄭重提示:
                    //res.err_msg將在用戶支付成功后返回ok跋核,但并不保證它絕對(duì)可靠。
                    //支付成功  請(qǐng)求接口確認(rèn) 刷新頁(yè)面
                  }
            }); 
          }else {
            //失敗處理
          }
        }
      })
    }

前端代碼完成叛买。
后臺(tái)代碼:
1.獲取openid

   /**
     * 網(wǎng)頁(yè)支付 獲取openid
     *
     * @param code
     * @return
     */
    @PostMapping("getOpenID")
    private String getOpenID(@RequestParam("code") String code) {
        JSONObject accessToken = getAccessToken(code);
        return accessToken.getString("openid");
    }
    public static JSONObject getAccessToken(String code){
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="公眾號(hào)AppID"&secret="公眾號(hào)秘鑰"&code="+code+"&grant_type=authorization_code";
        String result = HttpUtils.httpGet(url);
        JSONObject data = com.alibaba.fastjson.JSON.parseObject(result);
        return data;
    }
/**
     * 發(fā)送get請(qǐng)求
     * @param url    路徑
     * @return
     */
    public static String httpGet(String url){
        //get請(qǐng)求返回結(jié)果
        String strResult = null;
        try {
            DefaultHttpClient client = new DefaultHttpClient();
            //發(fā)送get請(qǐng)求
            HttpGet request = new HttpGet(url);
            HttpResponse response = client.execute(request);

            /**請(qǐng)求發(fā)送成功砂代,并得到響應(yīng)**/
            if (response.getStatusLine().getStatusCode() == org.apache.http.HttpStatus.SC_OK) {
                /**讀取服務(wù)器返回過(guò)來(lái)的json字符串?dāng)?shù)據(jù)**/
                strResult = EntityUtils.toString(response.getEntity(),"UTF-8");
            } else {

            }
        } catch (IOException e) {

        }
        return strResult;
    }

獲取openid完成。

  1. 調(diào)用微信支付統(tǒng)一下單接口
    2.1 payUtils工具類
import org.apache.commons.codec.digest.DigestUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.json.JSONObject;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

public class PayUtil {

    public static String APP_ID = "";
    
    public static JSONObject wxPay(String appID, String openid, String bodys, String orderNos, String price, String notify_url) {
        JSONObject json = new JSONObject();
        try {
            //生成的隨機(jī)字符串
            String nonce_str = Utils.genNonceStr();
            //獲取本機(jī)的ip地址
            String spbill_create_ip = "127.0.0.1";

            Map<String, String> packageParams = new HashMap<String, String>();
            packageParams.put("appid", appID);
            packageParams.put("mch_id", WXPayUtil.MCH_ID);
            packageParams.put("nonce_str", nonce_str);
            packageParams.put("body", bodys);//商品名稱
            packageParams.put("out_trade_no", orderNos);//商戶訂單號(hào)
            packageParams.put("total_fee", price);
            packageParams.put("spbill_create_ip", spbill_create_ip);
            packageParams.put("notify_url", notify_url);
            packageParams.put("trade_type", "JSAPI");
            packageParams.put("openid", openid);

            // 除去數(shù)組中的空值和簽名參數(shù)
            packageParams = paraFilter(packageParams);
            String prestr = createLinkString(packageParams); // 把數(shù)組所有元素率挣,按照“參數(shù)=參數(shù)值”的模式用“&”字符拼接成字符串

            //MD5運(yùn)算生成簽名刻伊,這里是第一次簽名,用于調(diào)用統(tǒng)一下單接口
            String mysign = sign(prestr, WXPayUtil.API_KEY, "utf-8").toUpperCase();
//            System.out.println("=======================第一次簽名:" + mysign + "=====================");
            //拼接統(tǒng)一下單接口使用的xml數(shù)據(jù)椒功,要將上一步生成的簽名一起拼接進(jìn)去
            String xml = "<xml version='1.0' encoding='gbk'>" + "<appid>" + appID + "</appid>"
                    + "<body><![CDATA[" + bodys + "]]></body>"
                    + "<mch_id>" + WXPayUtil.MCH_ID + "</mch_id>"
                    + "<nonce_str>" + nonce_str + "</nonce_str>"
                    + "<notify_url>" + notify_url + "</notify_url>"
                    + "<openid>" + openid + "</openid>"
                    + "<out_trade_no>" + orderNos + "</out_trade_no>"
                    + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"
                    + "<total_fee>" + price + "</total_fee>"
                    + "<trade_type>" + "JSAPI" + "</trade_type>"
                    + "<sign>" + mysign + "</sign>"
                    + "</xml>";


//            System.out.println("調(diào)試模式_統(tǒng)一下單接口 請(qǐng)求XML數(shù)據(jù):" + xml);


            //調(diào)用統(tǒng)一下單接口捶箱,并接受返回的結(jié)果
            String result = httpRequest(pay_url, "POST", xml);

//            System.out.println("調(diào)試模式_統(tǒng)一下單接口 返回XML數(shù)據(jù):" + result);


// 將解析結(jié)果存儲(chǔ)在HashMap中
            Map map = doXMLParse(result);
//            System.out.println("map:"+map);

            String return_code = (String) map.get("return_code");//返回狀態(tài)碼


//返回給移動(dòng)端需要的參數(shù)
            Map<String, Object> response = new HashMap<String, Object>();
            if (return_code == "SUCCESS" || return_code.equals(return_code)) {
// 業(yè)務(wù)結(jié)果
                String prepay_id = (String) map.get("prepay_id");//返回的預(yù)付單信息
//                System.out.println("prepay_id:"+prepay_id);
                response.put("nonceStr", nonce_str);
                response.put("package", "prepay_id=" + prepay_id);
                Long timeStamp = System.currentTimeMillis() / 1000;
                response.put("timeStamp", timeStamp + "");//這邊要將返回的時(shí)間戳轉(zhuǎn)化成字符串,不然小程序端調(diào)用wx.requestPayment方法會(huì)報(bào)簽名錯(cuò)誤

                String stringSignTemp = "appId=" + appID + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id + "&signType=" + "MD5" + "&timeStamp=" + timeStamp;
                //再次簽名蛾茉,這個(gè)簽名用于小程序端調(diào)用wx.requesetPayment方法
                String paySign = sign(stringSignTemp, WXPayUtil.API_KEY, "utf-8").toUpperCase();
                System.out.print("=======================第二次簽名:" + paySign + "=====================");
                response.put("paySign", paySign);
                //更新訂單信息
                //業(yè)務(wù)邏輯代碼
            }
            response.put("appid", appID);
            json.put("errMsg", "OK");
            json.put("data", response);
        } catch (Exception e) {
            e.printStackTrace();
            json.put("errMsg", "Failed");
        }
        return json;
    }


    /**
     * 簽名字符串
     *
     * @param text          需要簽名的字符串
     * @param key           密鑰
     * @param input_charset 編碼格式
     * @return 簽名結(jié)果
     */

    public static String sign(String text, String key, String input_charset) {
        text = text + "&key=" + key;
        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
    }

    /**
     * 簽名字符串
     *
     * @param text          需要簽名的字符串
     * @param sign          簽名結(jié)果
     * @param key           密鑰
     * @param input_charset 編碼格式
     * @return 簽名結(jié)果
     */

    public static boolean verify(String text, String sign, String key, String input_charset) {
        text = text + key;
        String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
        if (mysign.equals(sign)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @param content
     * @param charset
     * @return
     * @throws UnsupportedEncodingException
     */

    public static byte[] getContentBytes(String content, String charset) {
        if (charset == null || "".equals(charset)) {
            return content.getBytes();
        }
        try {
            return content.getBytes(charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5簽名過(guò)程中出現(xiàn)錯(cuò)誤,指定的編碼集不對(duì),您目前指定的編碼集是:" + charset);
        }
    }

    /**
     * 生成6位或10位隨機(jī)數(shù) param codeLength(多少位)
     *
     * @return
     */

    public static String createCode(int codeLength) {
        String code = "";
        for (int i = 0; i < codeLength; i++) {
            code += (int) (Math.random() * 9);
        }
        return code;
    }

    @SuppressWarnings("unused")
    private static boolean isValidChar(char ch) {
        if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
            return true;
        if ((ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f))
            return true;// 簡(jiǎn)體中文漢字編碼
        return false;
    }

    /**
     * 除去數(shù)組中的空值和簽名參數(shù)
     *
     * @param sArray 簽名參數(shù)組
     * @return 去掉空值與簽名參數(shù)后的新簽名參數(shù)組
     */

    public static Map<String, String> paraFilter(Map<String, String> sArray) {
        Map<String, String> result = new HashMap<String, String>();
        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
                    || key.equalsIgnoreCase("sign_type")) {
                continue;
            }
            result.put(key, value);
        }
        return result;
    }

    /**
     * 把數(shù)組所有元素排序讼呢,并按照“參數(shù)=參數(shù)值”的模式用“&”字符拼接成字符串
     *
     * @param params 需要排序并參與字符拼接的參數(shù)組
     * @return 拼接后字符串
     */

    public static String createLinkString(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (i == keys.size() - 1) {// 拼接時(shí),不包括最后一個(gè)&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }

    /**
     * @param requestUrl    請(qǐng)求地址
     * @param requestMethod 請(qǐng)求方法
     * @param outputStr     參數(shù)
     */

    public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {
// 創(chuàng)建SSLContext
        StringBuffer buffer = null;
        try {
            URL url = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod(requestMethod);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.connect();
//往服務(wù)器端寫內(nèi)容
            if (null != outputStr) {
                OutputStream os = conn.getOutputStream();
                os.write(outputStr.getBytes("utf-8"));
                os.close();
            }
// 讀取服務(wù)器端返回的內(nèi)容
            InputStream is = conn.getInputStream();
            InputStreamReader isr = new InputStreamReader(is, "utf-8");
            BufferedReader br = new BufferedReader(isr);
            buffer = new StringBuffer();
            String line = null;
            while ((line = br.readLine()) != null) {
                buffer.append(line);
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return buffer.toString();
    }

    public static String urlEncodeUTF8(String source) {
        String result = source;
        try {
            result = java.net.URLEncoder.encode(source, "UTF-8");
        } catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 解析xml,返回第一級(jí)元素鍵值對(duì)谦炬。如果第一級(jí)元素有子節(jié)點(diǎn)悦屏,則此節(jié)點(diǎn)的值是子節(jié)點(diǎn)的xml數(shù)據(jù)。
     *
     * @param strxml
     * @return
     * @throws IOException
     */
    public static Map doXMLParse(String strxml) throws Exception {
        if (null == strxml || "".equals(strxml)) {
            return null;
        }

        Map m = new HashMap();
        InputStream in = String2Inputstream(strxml);
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while (it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if (children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }

            m.put(k, v);
        }

//關(guān)閉流
        in.close();

        return m;
    }

    /**
     * 獲取子結(jié)點(diǎn)的xml
     *
     * @param children
     * @return String
     */
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if (!children.isEmpty()) {
            Iterator it = children.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }

        return sb.toString();
    }

    public static InputStream String2Inputstream(String str) {
        return new ByteArrayInputStream(str.getBytes());
    }


    public static void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
//sb為微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
//        System.out.println("接收到的報(bào)文:" + notityXml);


        Map map = doXMLParse(notityXml);


        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
//驗(yàn)證簽名是否正確
            if (verify(createLinkString(map), (String) map.get("sign"), WXPayUtil.API_KEY, "utf-8")) {
/**此處添加自己的業(yè)務(wù)邏輯代碼start**/


/**此處添加自己的業(yè)務(wù)邏輯代碼end**/


//通知微信服務(wù)器已經(jīng)支付成功
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[報(bào)文為空]]></return_msg>" + "</xml> ";
        }
//        System.out.println(resXml);
//        System.out.println("微信支付回調(diào)數(shù)據(jù)結(jié)束");


        BufferedOutputStream out = new BufferedOutputStream(
                response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }
}

2.2 在接口中調(diào)用方式:

//微信支付  參數(shù)說(shuō)明
//APP_ID 必須是公眾號(hào)appid
//openid 下單用戶的openid 前端傳過(guò)來(lái)的
//str  商品簡(jiǎn)單描述
//out_trade_no  商戶系統(tǒng)內(nèi)部訂單號(hào)键思,要求32個(gè)字符內(nèi)础爬,只能是數(shù)字、大小寫字母_-|* 且在同一個(gè)商戶號(hào)下唯一
 //"1" 商品價(jià)格 這里的價(jià)格是*100后的價(jià)格 
//NOTIFY_URL 支付回調(diào)地址

            org.json.JSONObject objects = PayUtil .wxPay(APP_ID,openid, str, out_trade_no, "1", NOTIFY_URL);//
            System.out.println(objects);
            String errMsg = objects.getString("errMsg");
            if (errMsg.equals("OK")) {
                org.json.JSONObject data = objects.getJSONObject("data");
//                  System.out.println(data);
                Map<String, Object> map = new HashMap<>();
                map.put("timeStamp", data.getString("timeStamp"));
                map.put("package", data.getString("package"));
                map.put("paySign", data.getString("paySign"));
                map.put("appid", data.getString("appid"));
                map.put("nonceStr", data.getString("nonceStr"));
                return map;
             }

2.3 支付回調(diào)

/**
     * jsApi H5廣告微信支付回調(diào)
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "自定義name")
    private String 自定義name(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> return_data = new HashMap<String, String>();
        try {
            InputStream inStream = request.getInputStream();

            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            String resultxml = new String(outSteam.toByteArray(), "utf-8");
//        System.out.println("resultxml:-----------------");
//        System.out.println(resultxml);
//        System.out.println("---------------------------");
            Map<String, String> params = PayCommonUtil.doXMLParse(resultxml);
            outSteam.close();
            inStream.close();

            if (!PayCommonUtil.isTenpaySign(params)) {
                // 支付失敗
                System.out.println("===============信支付回調(diào)驗(yàn)簽失敗==============");
                return_data.put("return_code", "FAIL");
                return_data.put("return_msg", "return_code不正確");
                return StringUtil.GetMapToXML(return_data);
            } else {
                // ------------------------------
                // 處理業(yè)務(wù)開始
                // ------------------------------
                String total_fee = params.get("total_fee");

                double v = Double.valueOf(total_fee) / 100;

                String tradeNo = params.get("transaction_id");
                String out_trade_no = String.valueOf(Long.parseLong(params.get("out_trade_no").split("O")[0]));
              //處理業(yè)務(wù)邏輯
                    return_data.put("return_code", "SUCCESS");
                    return_data.put("return_msg", "OK");
                    return StringUtil.GetMapToXML(return_data);
                }

            }
        } catch (
                IOException e) {
            e.printStackTrace();
        } catch (
                JDOMException e) {
            e.printStackTrace();
        }
        return_data.put("return_code", "FAIL");
        return_data.put("return_msg", "out_trade_no不正確");
        return StringUtil.GetMapToXML(return_data);
    }

PayCommonUtil工具類

public class PayCommonUtil {

    //請(qǐng)求xml組裝
    public static String getRequestXml(SortedMap<String,Object> parameters){
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String key = (String)entry.getKey();
            String value = (String)entry.getValue();
            if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
                sb.append("<"+key+">"+"<![CDATA["+value+"]]></"+key+">");
            }else {
                sb.append("<"+key+">"+value+"</"+key+">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }


    /**
     * 驗(yàn)證回調(diào)簽名
     * @return
     */
    public static boolean isTenpaySign(Map<String, String> map) {
        String characterEncoding="utf-8";
        String charset = "utf-8";
        String signFromAPIResponse = map.get("sign");
        if (signFromAPIResponse == null || signFromAPIResponse.equals("")) {
            System.out.println("API返回的數(shù)據(jù)簽名數(shù)據(jù)不存在吼鳞,有可能被第三方篡改!!!");
            return false;
        }
//        System.out.println("服務(wù)器回包里面的簽名是:" + signFromAPIResponse);
        //過(guò)濾空 設(shè)置 TreeMap
        SortedMap<String,String> packageParams = new TreeMap();

        for (String parameter : map.keySet()) {
            String parameterValue = map.get(parameter);
            String v = "";
            if (null != parameterValue) {
                v = parameterValue.trim();
            }
            packageParams.put(parameter, v);
        }

        StringBuffer sb = new StringBuffer();
        Set es = packageParams.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(!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + API_KEY);

        //將API返回的數(shù)據(jù)根據(jù)用簽名算法進(jìn)行計(jì)算新的簽名看蚜,用來(lái)跟API返回的簽名進(jìn)行比較
        //算出簽名
        String resultSign = "";
        String tobesign = sb.toString();

        if (null == charset || "".equals(charset)) {
            resultSign = MD5Util.MD5Encode(tobesign, characterEncoding).toUpperCase();
        }else{
            try{
                resultSign = MD5Util.MD5Encode(tobesign, characterEncoding).toUpperCase();
            }catch (Exception e) {
                resultSign = MD5Util.MD5Encode(tobesign, characterEncoding).toUpperCase();
            }
        }
        String tenpaySign = ((String)packageParams.get("sign")).toUpperCase();
//        System.out.println("返回?cái)?shù)據(jù)-tenpaySign:"+tenpaySign);
//        System.out.println("resultSign:"+resultSign);
//        System.out.println(tenpaySign.equals(resultSign));
        return tenpaySign.equals(resultSign);
    }

    //請(qǐng)求方法
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        try {

            URL url = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 設(shè)置請(qǐng)求方式(GET/POST)
            conn.setRequestMethod(requestMethod);
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 當(dāng)outputStr不為null時(shí)向輸出流寫數(shù)據(jù)
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意編碼格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 從輸入流讀取返回內(nèi)容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 釋放資源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            System.out.println("連接超時(shí):{}"+ ce);
        } catch (Exception e) {
            System.out.println("https請(qǐng)求異常:{}"+ e);
        }
        return null;
    }

    //xml解析
    public static Map doXMLParse(String strxml) throws JDOMException, IOException {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");

        if(null == strxml || "".equals(strxml)) {
            return null;
        }

        Map m = new HashMap();

        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while(it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if(children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }

            m.put(k, v);
        }

        //關(guān)閉流
        in.close();

        return m;
    }

    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if(!children.isEmpty()) {
            Iterator it = children.iterator();
            while(it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if(!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }

        return sb.toString();
    }
    public static String GetMapToXML(Map<String,String> param){
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        for (Map.Entry<String,String> entry : param.entrySet()) {
            sb.append("<"+ entry.getKey() +">");
            sb.append(entry.getValue());
            sb.append("</"+ entry.getKey() +">");
        }
        sb.append("</xml>");
        return sb.toString();
    }

}

結(jié)束!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赔桌,一起剝皮案震驚了整個(gè)濱河市供炎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疾党,老刑警劉巖音诫,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異雪位,居然都是意外死亡竭钝,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門雹洗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)香罐,“玉大人,你說(shuō)我怎么就攤上這事时肿”用#” “怎么了?”我有些...
    開封第一講書人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵螃成,是天一觀的道長(zhǎng)旦签。 經(jīng)常有香客問(wèn)我啥容,道長(zhǎng),這世上最難降的妖魔是什么顷霹? 我笑而不...
    開封第一講書人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮击吱,結(jié)果婚禮上际度,老公的妹妹穿的比我還像新娘执赡。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開白布绍绘。 她就那樣靜靜地躺著,像睡著了一般泥技。 火紅的嫁衣襯著肌膚如雪贸宏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,729評(píng)論 1 289
  • 那天常摧,我揣著相機(jī)與錄音搅吁,去河邊找鬼。 笑死落午,一個(gè)胖子當(dāng)著我的面吹牛谎懦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溃斋,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼界拦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了梗劫?” 一聲冷哼從身側(cè)響起享甸,我...
    開封第一講書人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梳侨,沒(méi)想到半個(gè)月后蛉威,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡猫妙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年瓷翻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片割坠。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡齐帚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出彼哼,到底是詐尸還是另有隱情对妄,我是刑警寧澤,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布敢朱,位于F島的核電站剪菱,受9級(jí)特大地震影響摩瞎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜孝常,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一旗们、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧构灸,春花似錦上渴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至半开,卻和暖如春隔披,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寂拆。 一陣腳步聲響...
    開封第一講書人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工奢米, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人漓库。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓恃慧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親渺蒿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痢士,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348

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