微信小程式-微信支付
阿新 • • 發佈:2020-11-21
最近寫了一個微信小程式的後端,微信支付(Java版)。
在這裡分享一下開發過程吧。
首先我們要先去了解微信小程式支付開發的過程。
這裡說一下流程。
微信小程式端獲取到code,由微信小程式前端傳code到後端,
後端接收到code去呼叫微信官方介面換取openid。
生成商戶訂單,即通過xml格式包含文件中必填的引數去呼叫統一下單介面(附下圖),返回prepay_id.
當然微信小程式需要二次簽名,同樣通過必填引數封裝,返回給微信小程式端。(其中有很多坑,下文慢慢講解)
正文開始
- 微信小程式前端獲取到code
//獲取code的方法 wx.login({ success: res => { console.log("向後臺傳遞獲取使用者的資訊的地址"); console.log(res.code); // 傳送 res.code 到後臺換取 openId //此處可以請求後臺介面獲取openid } })
2.後臺接收到code後,通過拼接字串請求地址,返回openid
(在後續附上工具類)
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.其次是呼叫統一下單介面,(這一步也是很多人採坑的地方)官方詳細文件
統一下單介面訪問的介面為:https://api.mch.weixin.qq.com/pay/unifiedorder
統一下單介面必填引數為:[共十個] appid(小程式ID),mch_id(商戶號),nonce_str(隨機字串),sign(簽名),body(商品描述),out_trade_no(商戶訂單號),total_fee(標價金額),spbill_create_ip(終端ip),notify_url(回撥地址),trade_type(交易型別)
注意:這裡的nonce_str必須與再次簽名的隨機字串為同一值。
我這裡是通過封裝一個實體類,對類進行賦值取值。 (當然,嫌麻煩的可以直接全部寫在配置類中)
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("¬ify_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這個值。 如果這裡報了簽名錯誤等問題。[解決方案]1、仔細檢查10個必填引數是否按順序拼接。2、檢查一下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"的字串值為:
做到這裡,已經幾近成功了。還差最後一步,回撥函式(當支付成功時,在資料庫中修改"已支付"成功欄位。)
注意
:1、回撥地址必須是公網上的地址。(專案部署到伺服器上才可進行訪問)。 2、回撥地址中不能新增任何引數。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 ======[[]]=====1323436201
* cash_fee ======[[]]=====1
* out_trade_no ======[[]]=====20201119165722672
* appid ======[[]]=====wxa26695086d4d5d59
* 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>
結束
第二次簽名:
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>
結束
好了。我這裡是只做了微信小程式的支付及回撥。
部落格中的程式碼有刪改,
若是有欠缺,可以留言或者私信我。
感謝各位讀者!