java微信小程序調用支付接口

簡介:微信小程序支付這里的坑還是有的,所以提醒各位在編寫的一定要注意?。。?/p>

1.首先呢,你需要準備**openid,appid**,還有申請微信支付后要設置一個**32位的密鑰**,需要先生成一個**sign**,得到**prepay_id**,然后再得到一個**paySign**,總之就是很墨跡,下面獻上我的controller


//微信下單支付

@ResponseBody

@RequestMapping("doOrder")

public void doOrder(HttpServletRequest request, HttpServletResponse response) throws IOException, JDOMException {

request.setCharacterEncoding("UTF-8");

response.setCharacterEncoding("UTF-8");

//得到openid

String openid = request.getParameter("openid");

int fee = 0;

//得到小程序傳過來的價格,注意這里的價格必須為整數,1代表1分,所以傳過來的值必須*100;

if (null != request.getParameter("price")) {

fee = Integer.parseInt(request.getParameter("price").toString());

}

System.out.println(request.getParameter("price"));

System.out.println(fee);

//訂單編號

String did = request.getParameter("did");

//訂單標題

String title = request.getParameter("title");

//時間戳

String times = System.currentTimeMillis() + "";

SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();

packageParams.put("appid", "wxa**********2e2");

packageParams.put("mch_id", "1486425722");

packageParams.put("nonce_str", times);//時間戳

packageParams.put("body", title);//支付主體

packageParams.put("out_trade_no", did);//編號

packageParams.put("total_fee", fee);//價格

// packageParams.put("spbill_create_ip", getIp2(request));這里之前加了ip,但是總是獲取sign失敗,原因不明,之后就注釋掉了

packageParams.put("notify_url", base+"/notify");//支付回調接口,用于支付成功后處理業務邏輯,小程序端支付success不能保證100%回調成功,建議采用后端異步回調處理方式,回調方法在最后

packageParams.put("trade_type", "JSAPI");//這個api有,固定的

packageParams.put("openid", openid);//openid

//獲取sign

String sign = PayCommonUtil.createSign("UTF-8", packageParams, "x********************************4");//最后這個是自己設置的32位密鑰

packageParams.put("sign", sign);

//轉成XML

String requestXML = PayCommonUtil.getRequestXml(packageParams);

System.out.println(requestXML);

//得到含有prepay_id的XML

String resXml = HttpUtil.postData("https://api.mch.weixin.qq.com/pay/unifiedorder", requestXML);

System.out.println(resXml);

//解析XML存入Map

Map map = XMLUtil.doXMLParse(resXml);

System.out.println(map);

// String return_code = (String) map.get("return_code");

//得到prepay_id

String prepay_id = (String) map.get("prepay_id");

SortedMap<Object, Object> packageP = new TreeMap<Object, Object>();

packageP.put("appId", "wxa**********2e2");//?。。∽⒁?,這里是appId,上面是appid,真懷疑寫這個東西的人。。。

packageP.put("nonceStr", times);//時間戳

packageP.put("package", "prepay_id=" + prepay_id);//必須把package寫成 "prepay_id="+prepay_id這種形式

packageP.put("signType", "MD5");//paySign加密

packageP.put("timeStamp", (System.currentTimeMillis() / 1000) + "");

//得到paySign

String paySign = PayCommonUtil.createSign("UTF-8", packageP, "x********************************4");

packageP.put("paySign", paySign);

//將packageP數據返回給小程序

Gson gson = new Gson();

String json = gson.toJson(packageP);

PrintWriter pw = response.getWriter();

System.out.println(json);

pw.write(json);

pw.close();

}

```

2.下面是需要用到的工具類

(1).生成sign以及得到sign后生成XML工具類PayCommonUtil


public class PayCommonUtil {

/**

? ? * 是否簽名正確,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。

? ? * @return boolean

? ? */?

? ? public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {?

? ? ? ? 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);?


? ? ? ? //算出摘要?

? ? ? ? String mysign = MD5.MD5Encode(sb.toString(), characterEncoding).toLowerCase();?

? ? ? ? String tenpaySign = ((String)packageParams.get("sign")).toLowerCase();?


? ? ? ? //System.out.println(tenpaySign + "? ? " + mysign);?

? ? ? ? return tenpaySign.equals(mysign);?

? ? }?


? ? /**

? ? * @author

? ? * @Description:sign簽名

? ? * @param characterEncoding

? ? *? ? ? ? ? ? 編碼格式

? ? * @param parameters

? ? *? ? ? ? ? ? 請求參數

? ? * @return

? ? */?

? ? public static String createSign(String characterEncoding, SortedMap<Object, Object> packageParams, String API_KEY) {?

? ? ? ? StringBuffer sb = new StringBuffer();?

? ? ? ? Set es = packageParams.entrySet();?

? ? ? ? Iterator it = es.iterator();?

? ? ? ? while (it.hasNext()) {?

? ? ? ? ? ? Map.Entry entry = (Map.Entry) it.next();?

? ? ? ? ? ? String k = entry.getKey().toString();?

? ? ? ? ? ? String v = entry.getValue().toString();?

? ? ? ? ? ? if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {?

? ? ? ? ? ? ? ? sb.append(k + "=" + v + "&");?

? ? ? ? ? ? }?

? ? ? ? }?

? ? ? ? sb.append("key=" + API_KEY);?

? ? ? ? String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();?

? ? ? ? return sign;?

? ? }?


? ? /**

? ? * @author

? ? * @Description:將請求參數轉換為xml格式的string

? ? * @param parameters

? ? *? ? ? ? ? ? 請求參數

? ? * @return

? ? */?

? ? public static String getRequestXml(SortedMap<Object, 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 k = entry.getKey().toString();?

? ? ? ? ? ? String v = entry.getValue().toString();?

? ? ? ? ? ? if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {?

? ? ? ? ? ? ? ? sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");?

? ? ? ? ? ? } else {?

? ? ? ? ? ? ? ? sb.append("<" + k + ">" + v + "</" + k + ">");?

? ? ? ? ? ? }?

? ? ? ? }?

? ? ? ? sb.append("</xml>");?

? ? ? ? return sb.toString();?

? ? }?


? ? /**

? ? * 取出一個指定長度大小的隨機正整數.

? ? *?

? ? * @param length

? ? *? ? ? ? ? ? int 設定所取出隨機數的長度。length小于11

? ? * @return int 返回生成的隨機數。

? ? */?

? ? public static int buildRandom(int length) {?

? ? ? ? int num = 1;?

? ? ? ? double random = Math.random();?

? ? ? ? if (random < 0.1) {?

? ? ? ? ? ? random = random + 0.1;?

? ? ? ? }?

? ? ? ? for (int i = 0; i < length; i++) {?

? ? ? ? ? ? num = num * 10;?

? ? ? ? }?

? ? ? ? return (int) ((random * num));?

? ? }?


? ? /**

? ? * 獲取當前時間 yyyyMMddHHmmss

? ? *?

? ? * @return String

? ? */?

? ? public static String getCurrTime() {?

? ? ? ? Date now = new Date();?

? ? ? ? SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");?

? ? ? ? String s = outFormat.format(now);?

? ? ? ? return s;?

? ? }?

}

```

(2).訪問官方接口得到含有prepay_id的XML工具類HttpUtil


public class HttpUtil {

//private static final Log logger = Logs.get();?

? ? private final static int CONNECT_TIMEOUT = 5000; // in milliseconds?

? ? private final static String DEFAULT_ENCODING = "UTF-8";?


? ? public static String postData(String urlStr, String data){?

? ? ? ? return postData(urlStr, data, null);?

? ? }?


? ? public static String postData(String urlStr, String data, String contentType){?

? ? ? ? BufferedReader reader = null;?

? ? ? ? try {?

? ? ? ? ? ? URL url = new URL(urlStr);?

? ? ? ? ? ? URLConnection conn = url.openConnection();?

? ? ? ? ? ? conn.setDoOutput(true);?

? ? ? ? ? ? conn.setConnectTimeout(CONNECT_TIMEOUT);?

? ? ? ? ? ? conn.setReadTimeout(CONNECT_TIMEOUT);?

? ? ? ? ? ? if(contentType != null)?

? ? ? ? ? ? ? ? conn.setRequestProperty("content-type", contentType);?

? ? ? ? ? ? OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), DEFAULT_ENCODING);?

? ? ? ? ? ? if(data == null)?

? ? ? ? ? ? ? ? data = "";?

? ? ? ? ? ? writer.write(data);?

? ? ? ? ? ? writer.flush();?

? ? ? ? ? ? writer.close();? ?


? ? ? ? ? ? reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), DEFAULT_ENCODING));?

? ? ? ? ? ? StringBuilder sb = new StringBuilder();?

? ? ? ? ? ? String line = null;?

? ? ? ? ? ? while ((line = reader.readLine()) != null) {?

? ? ? ? ? ? ? ? sb.append(line);?

? ? ? ? ? ? ? ? sb.append("\r\n");?

? ? ? ? ? ? }?

? ? ? ? ? ? return sb.toString();?

? ? ? ? } catch (IOException e) {?

? ? ? ? ? ? //logger.error("Error connecting to " + urlStr + ": " + e.getMessage());?

? ? ? ? } finally {?

? ? ? ? ? ? try {?

? ? ? ? ? ? ? ? if (reader != null)?

? ? ? ? ? ? ? ? ? ? reader.close();?

? ? ? ? ? ? } catch (IOException e) {?

? ? ? ? ? ? }?

? ? ? ? }?

? ? ? ? return null;?

? ? }?

}

```

(3).解析XML工具類


public class XMLUtil {

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 = XMLUtil.getChildrenText(children);?

? ? ? ? ? ? }?


? ? ? ? ? ? m.put(k, v);?

? ? ? ? }?


? ? ? ? //關閉流?

? ? ? ? in.close();?


? ? ? ? return m;?

? ? }?


? ? /**

? ? * 獲取子結點的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(XMLUtil.getChildrenText(list));?

? ? ? ? ? ? ? ? }?

? ? ? ? ? ? ? ? sb.append(value);?

? ? ? ? ? ? ? ? sb.append("</" + name + ">");?

? ? ? ? ? ? }?

? ? ? ? }?


? ? ? ? return sb.toString();?

? ? }?

}

```

(4).MD5加密工具類


public class MD5 {

private static String byteArrayToHexString(byte b[]) {

? ? ? ? StringBuffer resultSb = new StringBuffer();

? ? ? ? for (int i = 0; i < b.length; i++)

? ? ? ? ? ? resultSb.append(byteToHexString(b[i]));

? ? ? ? return resultSb.toString();

? ? }

? ? private static String byteToHexString(byte b) {

? ? ? ? int n = b;

? ? ? ? if (n < 0)

? ? ? ? ? ? n += 256;

? ? ? ? int d1 = n / 16;

? ? ? ? int d2 = n % 16;

? ? ? ? return hexDigits[d1] + hexDigits[d2];

? ? }

? ? public static String MD5Encode(String origin, String charsetname) {

? ? ? ? String resultString = null;

? ? ? ? try {

? ? ? ? ? ? resultString = new String(origin);

? ? ? ? ? ? MessageDigest md = MessageDigest.getInstance("MD5");

? ? ? ? ? ? if (charsetname == null || "".equals(charsetname))

? ? ? ? ? ? ? ? resultString = byteArrayToHexString(md.digest(resultString

? ? ? ? ? ? ? ? ? ? ? ? .getBytes()));

? ? ? ? ? ? else

? ? ? ? ? ? ? ? resultString = byteArrayToHexString(md.digest(resultString

? ? ? ? ? ? ? ? ? ? ? ? .getBytes(charsetname)));

? ? ? ? } catch (Exception exception) {

? ? ? ? }

? ? ? ? return resultString;

? ? }


? ? private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",

? ? ? ? "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

}

```

3.小程序支付函數


gopay: function () {

? ? var that = this

? ? wx.request({

? ? ? url: app.baseurl + 'doOrder',

? ? ? data: {

? ? ? ? 'openid': wx.getStorageSync('openids'),

? ? ? ? 'title': that.data.title,

? ? ? ? 'did': that.data.did,

? ? ? ? 'price': that.data.price*100

? ? ? },

? ? ? method: 'POST',

? ? ? header: {

? ? ? ? "content-type": 'application/x-www-form-urlencoded'

? ? ? },

? ? ? success: function (res) {

? ? ? ? console.log(res.data)

? ? ? ? console.log(res.data.timeStamp)

? ? ? ? console.log(res.data.nonceStr)

? ? ? ? console.log(res.data.package)

? ? ? ? console.log(res.data.paySign)

? ? ? ? wx.requestPayment({

? ? ? ? ? timeStamp: res.data.timeStamp,

? ? ? ? ? nonceStr: res.data.nonceStr,

? ? ? ? ? package: res.data.package,

? ? ? ? ? signType: res.data.signType,

? ? ? ? ? paySign: res.data.paySign,

? ? ? ? ? success: function (res) {

? ? ? ? ? console.log('支付調用成功',res)

? ? ? ? ? },

? ? ? ? ? fail: function (res) {

? ? ? ? ? ? console.log(res)

? ? ? ? ? }

? ? ? ? })

? ? ? }

? ? })

? }

```

4、支付成功回調


/**

? ? * 此函數會被執行多次,如果支付狀態已經修改為已支付,則下次再調的時候判斷是否已經支付,如果已經支付了,則什么也執行

? ? * @param request

? ? * @param response

? ? * @return

? ? * @throws IOException

? ? * @throws JDOMException

? ? */

? ? @RequestMapping(value = "notify")

? ? @ResponseBody

? ? public String notify(HttpServletRequest request, HttpServletResponse response) throws IOException {

? ? String resXml = "";

? ? ? ? System.out.println("微信支付回調");

//resultxml中含用戶訂單號等信息,解析后用于處理訂單

? ? ? ? Map<String, String> params = PayCommonUtil.doXMLParse(resultxml);

? ? ? ? if (!PayCommonUtil.isTenpaySign(params)) {

? ? ? ? ? ? // 支付失敗

? ? ? ? ? ? resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"

? ? ? ? ? ? ? ? ? ? + "<return_msg><![CDATA[報文為空]]></return_msg>" + "</xml> ";

? ? ? ? } else {

? ? ? ? ? ? System.out.println("==========付款成功==========");

? ? ? ? ? ? // ------------------------------

? ? ? ? ? ? // 處理業務開始

? ? ? ? ? ? // ------------------------------

? ? ? ? ? ? // 此處處理訂單狀態,結合自己的訂單數據完成訂單狀態的更新

? ? ? ? ? ? // ------------------------------

//通知微信.異步確認成功.必寫.不然會一直通知后臺.八次之后就認為交易失敗了

resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"

? ? ? ? ? ? ? ? ? ? + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";

? ? ? ? }

? ? ? ? BufferedOutputStream out = new BufferedOutputStream(

? ? ? ? ? ? ? ? response.getOutputStream());

? ? ? ? out.write(resXml.getBytes());

? ? ? ? out.flush();

? ? ? ? out.close();

? ? }

```

結束啦,小程序支付的java后臺就這些。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。