微信小程序-微信支付

最近寫了一個微信小程序的後端,微信支付(Java版)。在這裏分享一下開發過程吧。javascript

在這裏插入圖片描述
首先咱們要先去了解微信小程序支付開發的過程。
前端

這裏說一下流程。java

  1. 微信小程序端獲取到code,由微信小程序前端傳code到後端,
  2. 後端接收到code去調用微信官方接口換取openid。
  3. 生成商戶訂單,即經過xml格式包含文檔中必填的參數去調用統一下單接口(附下圖),返回prepay_id.
  4. 固然微信小程序須要二次簽名,一樣經過必填參數封裝,返回給微信小程序端。(其中有不少坑,下文慢慢講解)

正文開始web

一、微信小程序前端獲取到code算法

//獲取code的方法
	wx.login({ 
    success: res => { 
        console.log("向後臺傳遞獲取用戶的信息的地址");
        console.log(res.code);
       // 發送 res.code 到後臺換取 openId
       //此處能夠請求後臺接口獲取openid
   }
})

2.後臺接收到code後,經過拼接字符串請求地址,返回openid(在後續附上工具類)spring

public static String getOpenId(String code) { 
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + 你的APP_ID +
                "&secret=" + 你的APP_SECRET + "&js_code=" + code + "&grant_type=authorization_code";
        HttpUtil httpUtil = new HttpUtil();
        try { 
            HttpResult httpResult = httpUtil.doGet(url, null, null);
            if (httpResult.getStatusCode() == 200) { 
                JsonParser jsonParser = new JsonParser();
                JsonObject obj = (JsonObject) jsonParser.parse(httpResult.getBody());
                System.out.println("getOpenId: " + obj.toString());
                if (obj.get("errcode") != null) { 
                    System.out.println("getOpenId returns errcode: " + obj.get("errcode"));
                    return "";
                } else { 
                    return obj.get("openid").toString();
                }
                //return httpResult.getBody();
            }
        } catch (Exception e) { 
            e.printStackTrace();
        }
        return "";
    }

3.其次是調用統一下單接口,(這一步也是不少人採坑的地方)官方詳細文檔數據庫

  1. 統一下單接口訪問的接口爲:https://api.mch.weixin.qq.com/pay/unifiedorder
  2. 統一下單接口必填參數爲:[共十個]appid(小程序ID),mch_id(商戶號),nonce_str(隨機字符串),sign(簽名),body(商品描述),out_trade_no(商戶訂單號),total_fee(標價金額),spbill_create_ip(終端ip),notify_url(回調地址),trade_type(交易類型)

**注意:**這裏的nonce_str必須與再次簽名的隨機字符串爲同一值。apache

我這裏是經過封裝一個實體類,對類進行賦值取值。 (固然,嫌麻煩的能夠直接所有寫在配置類中)json

public class PayInfo implements Serializable { 
    private String appid;//appid
    private String body;//商品描述
    private String mch_id;//商戶號
    //private String device_info; //設備號,小程序傳"WEB"
    private String nonce_str;//隨機字符串
    private String notify_url;//通知地址
    private String openid;//用戶標識
    private String out_trade_no;//商戶訂單號
    private String sign;//簽名
    private String sign_type;  //簽名類型
    private String spbill_create_ip;//終端ip
    //private String detail;//商品詳情
    //private String attach;附加數據
    private String time_expire;//交易結束時間
    private String time_start;//起始交易時間
    private int total_fee;//商戶金額
    private String trade_type; //交易類型,JSAPI
    //private String limit_pay; //指定支付方式,no_credit
    private String TimeStamp;
    private String repay_id;//這裏應該設置package,可是是關鍵字。
    private String key;

…省略get和set…小程序

這一步是 對實體類設置須要的值。(酌情修改參數,沒必要填的能夠註釋掉,上面寫了必填參數!) 注意:微信官方要求md5加密必須符合字母表順序,這一步在寫實體類的時候要注意(屬性名要按字母表寫)。

set和get方法不影響。

private PayInfo createPayInfo(String openId, String clientIP, String randomNonceStr) { 
        Date date = new Date();
        String timeStart = TimeUtils.getFormatTime(date, Constant.TIME_FORMAT);
        String timeExpire = TimeUtils.getFormatTime(TimeUtils.addDay(date, Constant.TIME_EXPIRE), Constant.TIME_FORMAT);

        String randomOrderId = CommonUtil.getRandomOrderId();

        PayInfo payInfo = new PayInfo();
        payInfo.setAppid(Constant.APP_ID);
        payInfo.setMch_id(Constant.MCH_ID);
        payInfo.setDevice_info("WEB");
        payInfo.setNonce_str(randomNonceStr);
        payInfo.setSign_type("MD5");  //默認即爲MD5
        payInfo.setBody("JSAPI支付測試");//這裏若是是中文須要進行轉碼,否則可能會報錯
        payInfo.setAttach("支付測試4luluteam");
        payInfo.setOut_trade_no(randomOrderId);
        payInfo.setTotal_fee(1);
        payInfo.setSpbill_create_ip(clientIP);
        payInfo.setTime_start(timeStart);
        payInfo.setTime_expire(timeExpire);
        payInfo.setNotify_url(Constant.URL_NOTIFY);
        payInfo.setTrade_type("JSAPI");
        payInfo.setLimit_pay("no_credit");
        payInfo.setOpenid(openId);

        return payInfo;

設置好參數,這一步是對字符串進行拼接。目的是md5加密!(酌情刪減)

private String getSign(PayInfo payInfo) throws Exception { 
        StringBuffer sb = new StringBuffer();
        sb.append("appid=" + payInfo.getAppid())
                .append("&attach=" + payInfo.getAttach())
                .append("&body=" + payInfo.getBody())
                .append("&device_info=" + payInfo.getDevice_info())
                .append("&limit_pay=" + payInfo.getLimit_pay())
                .append("&mch_id=" + payInfo.getMch_id())
                .append("&nonce_str=" + payInfo.getNonce_str())
                .append("&notify_url=" + payInfo.getNotify_url())
                .append("&openid=" + payInfo.getOpenid())
                .append("&out_trade_no=" + payInfo.getOut_trade_no())
                .append("&sign_type=" + payInfo.getSign_type())
                .append("&spbill_create_ip=" + payInfo.getSpbill_create_ip())
                .append("&time_expire=" + payInfo.getTime_expire())
                .append("&time_start=" + payInfo.getTime_start())
                .append("&total_fee=" + payInfo.getTotal_fee())
                .append("&trade_type=" + payInfo.getTrade_type())
                .append("&key=" + Constant.APP_KEY);

        log.error("排序後的拼接參數:" + sb.toString());

        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }

這裏進行統一下單。返回的是prepay_id這個值。 若是這裏報了簽名錯誤等問題。[解決方案]一、仔細檢查10個必填參數是否按順序拼接。二、檢查一下appid,mch_id等(或者更改一下key[微信端會抽風])

/** * 調用統一下單接口 * @param openId */
    private String unifiedOrder(String openId, String clientIP, String randomNonceStr) { 

        try { 

            String url = Constant.URL_UNIFIED_ORDER;

            PayInfo payInfo = createPayInfo(openId, clientIP, randomNonceStr);
            //這裏對payInfo對象的九個必須參數進行加密,獲得sign值。
            String md5 = getSign(payInfo);
            payInfo.setSign(md5);

            log.error("md5 value: " + md5);

            String xml = CommonUtil.payInfoToXML(payInfo);
            xml = xml.replace("__", "_").replace("<![CDATA[1]]>", "1");
            //xml = xml.replace("__", "_").replace("<![CDATA[", "").replace("]]>", "");
            log.error(xml);

            StringBuffer buffer = HttpUtil.httpsRequest(url, "POST", xml);
            log.error("unifiedOrder request return body: \n" + buffer.toString());
            Map<String, String> result = CommonUtil.parseXml(buffer.toString());


            String return_code = result.get("return_code");
            if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")) { 

                String return_msg = result.get("return_msg");
                if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) { 
                    //log.error("統一下單錯誤!");
                    return "";
                }

                String prepay_Id = result.get("prepay_id");
                return prepay_Id;

            } else { 
                return "";
            }

        } catch (Exception e) { 
            e.printStackTrace();
        }
        return "";
    }

輸出結果:

得不到prepay_id,極可能是sign出錯了。建議多核對幾遍。

在這裏插入圖片描述
咱們獲得prepay_id以後,將組合數據再次進行簽名。

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.company.service.GoodsOrderService;
import com.example.company.utils.HttpClientUtils;
import com.example.company.utils.Pay.*;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.lang3.StringUtils;
import org.jdom.JDOMException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public R prePay(String code, HttpServletRequest request) throws IllegalAccessException { 
        //調用靜態方法getOpenId
        String openId = getOpenId(code);//獲取到openid

        openId = openId.replace("\"", "").trim();

        //這裏獲取到prepayId
        String prepayId = unifiedOrder(openId, clientIP, randomNonceStr);

        //獲取客戶端ip
        String clientIP = CommonUtil.getClientIp(request);

        //System.out.println("prepayId: " + prepayId);
        //二次簽名加密封裝
        final long time = System.currentTimeMillis() / 1000;
        String timeStamp = String.valueOf(time);
        String paySign = "appId=" + Constant.APP_ID + "&nonceStr=" + randomNonceStr + "&package=prepay_id=" + prepayId
                + "&signType=MD5" + "&timeStamp=" + timeStamp + "&key="+Constant.APP_KEY;

        String sign = DigestUtils.md5DigestAsHex(paySign.getBytes(StandardCharsets.UTF_8)).toUpperCase();
        //System.out.println("sign===="+sign);

        //再次簽名

        Map map = new HashMap();
        //map.put("appId", Constant.APP_ID);//獲取appid
        map.put("nonceStr", randomNonceStr);//返回隨機字符串
        map.put("package", "prepay_id=" + prepayId);//返回prepayId
        map.put("paySign", sign);
        map.put("signType", "MD5");
        map.put("timeStamp", timeStamp);//獲取時間戳

        String content = null;

        try { 
            content = JSON.toJSONString(map);//以json字符串形式返還給調用者
            System.out.println("content" + content);
        } catch (Exception e) { 
            e.printStackTrace();
        }
        return R.ok().data("content", content);
    }

獲得的"content"的字符串值爲:
在這裏插入圖片描述

作到這裏,已經幾近成功了。還差最後一步,回調函數(當支付成功時,在數據庫中修改"已支付"成功字段。)

注意:一、回調地址必須是公網上的地址。(項目部署到服務器上纔可進行訪問)。 二、回調地址中不能添加任何參數。

public String notifyUrl(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException { 
        //System.out.println(request);
        System.out.println("微信支付回調");
        //用字節流來獲取數據。
        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");
        Map<String, String> params = PayCommonUtil.doXMLParse(resultxml);
        outSteam.close();
        inStream.close();
        /** for(Map.Entry<String,String> entry:params.entrySet()){ System.out.println(entry.getKey()+" ======[[]]====="+entry.getValue()); } */
        /** * 這裏獲得的params的字符串對。 * transaction_id ======[[]]=====4200000819202011192847521125 * nonce_str ======[[]]=====BBJIJ1vrDqxistqhFukLIjuHe7PP21DP * bank_type ======[[]]=====OTHERS * openid ======[[]]=====ozP-C4m-93TNpk0F40yvzJA12wa0 * sign ======[[]]=====F90FFB4B9DEA5F7846B28E93209C3A93 * fee_type ======[[]]=====CNY * mch_id ======[[]]=====顯示本身的商戶號 * cash_fee ======[[]]=====1 * out_trade_no ======[[]]=====20201119165722672 * appid ======[[]]=====顯示本身的appid * total_fee ======[[]]=====1 * trade_type ======[[]]=====JSAPI * result_code ======[[]]=====SUCCESS * time_end ======[[]]=====20201119165807 * is_subscribe ======[[]]=====N * return_code ======[[]]=====SUCCESS */

        Map<String, String> return_data = new HashMap<String, String>();
        if (!PayCommonUtil.isTenpaySign(params)) { 
            // 支付失敗
            return_data.put("return_code", "FAIL");
            return_data.put("return_msg", "return_code不正確");
            return StringUtil.GetMapToXML(return_data);
        } else { 
            System.out.println("===============付款成功==============");
            // ------------------------------
            // 處理業務開始
            // ------------------------------
            // 此到處理訂單狀態,結合本身的訂單數據完成訂單狀態的更新,修改訂單狀態等。
            // ------------------------------

            String out_trade_no = String.valueOf(Long.parseLong(params.get("out_trade_no").split("O")[0]));
            System.out.println("out_trade_no==="+out_trade_no);
            Date accountTime = DateUtil.stringtoDate(params.get("time_end"), "yyyyMMddHHmmss");
            System.out.println("accountTime==="+accountTime);
            String ordertime = DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss");
            System.out.println("ordertime==="+ordertime);
            String totalAmount = String.valueOf(v);
            System.out.println("totalAmount==="+totalAmount);
            String appId = params.get("appid");
            System.out.println("appId==="+appId);
            String tradeNo = params.get("transaction_id");
            System.out.println("tradeNo==="+tradeNo);

            return_data.put("return_code", "SUCCESS");
            return_data.put("return_msg", "OK");
            return StringUtil.GetMapToXML(return_data);
        }
    }

附上工具類。

public class Constant { 

    //public static final String DOMAIN = "https://i-test.com.cn";

    public static final String APP_ID = "你的id";//小程序ID

    public static final String APP_SECRET = "你的secret";

    public static final String APP_KEY = "商戶key";

    public static final String MCH_ID = "你的商戶號";  //商戶號

    public static final String URL_UNIFIED_ORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    public static final String URL_CHECK_ORDER = "https://api.mch.weixin.qq.com/pay/orderquery";

    public static final String URL_NOTIFY = "你的公網地址";//回調 地址

    public static final String TIME_FORMAT = "yyyyMMddHHmmss";

    public static final int TIME_EXPIRE = 2;  //單位是day

}

public class PayCommonUtil { 
   /** * 驗證回調簽名 * @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返回的數據簽名數據不存在,有可能被第三方篡改!!!");
            return false;
        }
        System.out.println("服務器回包裏面的簽名是:" + signFromAPIResponse);
        //過濾空 設置 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返回的數據根據用簽名算法進行計算新的簽名,用來跟API返回的簽名進行比較
        //算出簽名
        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();
        return tenpaySign.equals(resultSign);
    }
}

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import javax.servlet.http.HttpServletRequest;
import java.io.Writer;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.*;
public class CommonUtil { 

    public static String getRandomOrderId() { 
        // UUID.randomUUID().toString().replace("-","")
        Random random = new Random(System.currentTimeMillis());
        int value = random.nextInt();
        while (value < 0) { 
            value = random.nextInt();
        }
        return value + "";
    }

    private static XStream xstream = new XStream(new XppDriver() { 
        public HierarchicalStreamWriter createWriter(Writer out) { 
            return new PrettyPrintWriter(out) { 
                //增長CDATA標記
                boolean cdata = true;
                @SuppressWarnings("rawtypes")
                public void startNode(String name, Class clazz) { 
                    super.startNode(name, clazz);
                }
                protected void writeText(QuickWriter writer, String text) { 
                    if (cdata) { 
                        writer.write("<![CDATA[");
                        writer.write(text);
                        writer.write("]]>");
                    } else { 
                        writer.write(text);
                    }
                }
            };
        }
    });

    public static String payInfoToXML(PayInfo pi) { 
        xstream.alias("xml", pi.getClass());
        return xstream.toXML(pi);
    }

    @SuppressWarnings("unchecked")
    public static Map<String, String> parseXml(String xml) throws Exception { 
        Map<String, String> map = new HashMap<>();
        Document document = DocumentHelper.parseText(xml);
        Element root = document.getRootElement();
        List<Element> elementList = root.elements();
        for (Element e : elementList)
            map.put(e.getName(), e.getText());
        return map;
    }


    public static String getClientIp(HttpServletRequest request) { 
        String ip = request.getHeader("X-Forwarded-For");
        if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ 
            //屢次反向代理後會有多個ip值,第一個ip纔是真實ip
            int index = ip.indexOf(",");
            if(index != -1){ 
                return ip.substring(0,index);
            }else{ 
                return ip;
            }
        }
        ip = request.getHeader("X-Real-IP");
        if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ 
            return ip;
        }
        return request.getRemoteAddr();
    }


    /** * 對字符串md5加密 * * @param str * @return */
    public static String getMD5(String str) throws Exception { 
        try { 
            // 生成一個MD5加密計算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 計算md5函數
            md.update(str.getBytes());
            // digest()最後肯定返回md5 hash值,返回值爲8爲字符串。由於md5 hash值是16位的hex值,實際上就是8位的字符
            // BigInteger函數則將8位的字符串轉換成16位hex值,用字符串來表示;獲得字符串形式的hash值
            return new BigInteger(1, md.digest()).toString(16);
        } catch (Exception e) { 
            throw new Exception("MD5加密出現錯誤");
        }
    }

}

import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpUtil { 

	// User-Agent
	public static final String USERAGENT_FIREFOX = "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0";  
	public static final String USERAGENT_IE = "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko";  
	
	private CloseableHttpClient httpClient;

	private BasicCookieStore cookieStore;
	private HttpGet get;
	private HttpPost post;

    public static StringBuffer httpsRequest(String requestUrl, String requestMethod, String output) throws IOException { 
        URL url = new URL(requestUrl);
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setUseCaches(false);
        connection.setRequestMethod(requestMethod);
        if (null != output) { 
            OutputStream outputStream = connection.getOutputStream();
            outputStream.write(output.getBytes("UTF-8"));
            outputStream.close();
        }
        // 從輸入流讀取返回內容
        InputStream inputStream = connection.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;
        connection.disconnect();
        return buffer;
    }

	
	public HttpResult doGet(String url, Map<String, String> headers, Map<String, String> params) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, ClientProtocolException, IOException { 

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

		SSLContextBuilder builder = new SSLContextBuilder();
		builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
		cookieStore = new BasicCookieStore();
		CloseableHttpClient httpclient = HttpClients.custom().setDefaultCookieStore(cookieStore)
				.setSSLSocketFactory(sslsf).build();

		HttpResult result = null;
		try { 

			url = url + "?" + parseParams(params);
			HttpGet httpget = new HttpGet(url);
			httpget.setHeaders(parseHeader(headers));

			CloseableHttpResponse response = httpclient.execute(httpget);
			try { 
				HttpEntity entity = response.getEntity();

				if (entity != null) { 
					result = new HttpResult();
					result.setCookies(cookieStore.getCookies());
					result.setStatusCode(response.getStatusLine().getStatusCode());
					result.setHeaders(response.getAllHeaders());
					result.setBody(EntityUtils.toString(entity));
				}

			} finally { 
				response.close();
			}
		} finally { 
			httpclient.close();
		}

		return result;
		
	}

	public HttpResult doPost(String url, Map<String, String> headers, Map<String, String> postData, String encoding) throws Exception { 

		if (url == null|| url.equals("")) { 
			return null;
		}
		if (encoding == null|| encoding.equals("")) { 
			encoding = "utf-8";
		}
		
		SSLContextBuilder builder = new SSLContextBuilder();
		builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build());
		cookieStore = new BasicCookieStore();
		CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore)
				.setSSLSocketFactory(sslsf).build();

		post = new HttpPost(url);
		List<NameValuePair> list = new ArrayList<NameValuePair>();
		for (String tmp : postData.keySet()) { 
			list.add(new BasicNameValuePair(tmp, postData.get(tmp)));
		}
		post.setEntity(new UrlEncodedFormEntity(list, encoding));
		post.setHeaders(parseHeader(headers));

		CloseableHttpResponse response = httpClient.execute(post);
		HttpEntity entity = response.getEntity();

		HttpResult result = new HttpResult();
		result.setCookies(cookieStore.getCookies());
		result.setStatusCode(response.getStatusLine().getStatusCode());
		result.setHeaders(response.getAllHeaders());
		result.setBody(EntityUtils.toString(entity, encoding));

		close(entity, response);

		return result;
	}
}

在這裏作個小總結吧。

微信官方的文檔意思就是。

第一次簽名:appid,mch_id,nonce_str,body,out_trade_no,total_fee,spbill_create_ip,notify_url,trade_type

這九個參數進行md5加密,爲sign,而後九個參數+sign以xml的格式發送請求給微信統一下單API返回的xml格式中有數據。

第二次簽名:appId,nonceStr,randomNonceStr,package,signType,timeStamp,key[七個參數]進行拼接簽名。

String paySign = 「appId=」 + Constant.APP_ID + 「&nonceStr=」 +
randomNonceStr + 「&package=prepay_id=」 + prepayId + 「&signType=MD5」 +
「&timeStamp=」 + timeStamp + 「&key=」+Constant.APP_KEY;

而後paySign拼接以後進行md5加密。

最後返回

("nonceStr", randomNonceStr);//返回隨機字符串<br>
("package", "prepay_id=" + prepayId);//返回prepayId<br>
("paySign", sign);<br>
("signType", "MD5");<br>
("timeStamp", timeStamp);//獲取時間戳<br>

結束

好了。我這裏是只作了微信小程序的支付及回調。

相關文章
相關標籤/搜索