微信小程式+java後臺實現支付(java操作)
支付,在微信小程式上面稱為當一個使用者使用該小程式,當進入到支付環節,我們需要呼叫微信支付介面過程,進行一系列的操作,並記錄下來。
微信小程式與java介面實現支付操作,大致思路如下:
1.微信小程式呼叫Java後臺方法獲取引數,
2.java 後臺設定引數等並且傳遞引數返回給微信小程式,
3.微信小程式支付成功,
4.呼叫設定的回撥地址(訂單存入資料庫),
5.最後呼叫微信小程式的success方法。
對應程式碼如下:
1.微信小程式呼叫支付
//得到openid(微信使用者唯一的openid) //該步驟忽略。。。 //得到價錢(自定義) String price = httpRequest.getParameter("price"); int fee = 0; if (null != price) { fee = Integer.parseInt(price.toString()); } //得到商品的ID(自定義) String goodsid=httpRequest.getParameter("goodsid"); //訂單標題(自定義) String title = httpRequest.getParameter("title"); //時間戳 String times = System.currentTimeMillis() + ""; //訂單編號(自定義 這裡以時間戳+隨機數) Random random = new Random(); String did = times+random.nextInt(1000); SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>(); packageParams.put("appid",MapUtils.getString(configProperties, "appId"));//微信小程式ID packageParams.put("mch_id", MapUtils.getString(configProperties, "mch_id"));//商戶ID packageParams.put("nonce_str", times);//隨機字串(32位以內) 這裡使用時間戳 packageParams.put("body", title);//支付主體名稱 自定義 packageParams.put("out_trade_no", did+goodsid);//編號 自定義以隨機數+商品ID packageParams.put("total_fee", PayUtil.getMoney(price));//價格 自定義 //packageParams.put("spbill_create_ip", remoteAddr); packageParams.put("notify_url", "https://xxx.xx.xx.xx/xxxxx/buy.do");//支付返回地址要外網訪問的到, localhost不行,呼叫下面buy方法。(訂單存入資料庫) packageParams.put("trade_type", "JSAPI");//這個api有,固定的 packageParams.put("openid", openid);//使用者的openid 可以要 可以不要 //獲取sign(第一次簽名) String sign = PayUtil.createSign("UTF-8", packageParams, MapUtils.getString(configProperties, "mah_password"));//最後這個是自己在微信商戶設定的32位金鑰 /*String mapStr = PayUtil.createLinkString(packageParams); String key = MapUtils.getString(configProperties, "mah_password"); //MD5生成運算簽名 String sign = PayUtil.sign(mapStr,key,"utf-8").toUpperCase();*/ packageParams.put("sign", sign); System.out.println(sign); //轉成XML String requestXML = PayUtil.getRequestXml(packageParams); System.out.println(requestXML); //得到含有prepay_id的XML String resXml = HttpUtils.postData("https://api.mch.weixin.qq.com/pay/unifiedorder", requestXML); System.out.println(resXml); //解析XML存入Map Map map2 = null; try { map2 = XmlUtil.doXMLParse(resXml); } catch (Exception e) { e.printStackTrace(); } System.out.println(map2); String return_code = (String) map2.get("return_code"); //得到prepay_id 進行二次簽名 SortedMap<Object, Object> packageP = new TreeMap<Object, Object>(); try{ if(return_code.equals("SUCCESS")){ //獲取資料 //List<PayInfo> payInfoList = payService.selectPayInfoByOpenId(openid); //如果等於空,說明為第一次支付 /*if(CollectionUtils.isEmpty(payInfoList)){ PayInfo payInfo = new PayInfo(); payInfo.setPayId(did+goodsid); //設定openid payInfo.setOpenId(openid); //設定金額 payInfo.setAmount(fee); //設定說明 payInfo.setTitle(title); //設定支付狀態 payInfo.setPayStatus("0"); //插入資料 int count = payService.insertPayInfo(payInfo); //判斷 if(count==1){ log.info("新增支付資訊成功"); } }else{ //判斷是否為第一條 if(payInfoList.size() == 1){ PayInfo payInfo = payInfoList.get(0); //更新該條的金額 payInfo.setAmount(fee+payInfo.getAmount()); //更新資料 int count = payService.updateByPayInfo(payInfo); //判斷 if (count==1){ log.info("修改支付資訊成功"); } } }*/ PayInfo payInfo = new PayInfo(); payInfo.setPayId(did+goodsid); //設定openid payInfo.setOpenId(openid); //設定金額 payInfo.setAmount(fee); //設定說明 payInfo.setTitle(title); //設定支付狀態 payInfo.setPayStatus("0"); //插入資料 int count = payService.insertPayInfo(payInfo); //判斷 if(count==1){ log.info("新增支付資訊成功"); } String prepay_id = (String) map2.get("prepay_id"); //packageP = new TreeMap<Object, Object>(); packageP.put("appId", MapUtils.getString(configProperties, "appId"));//!!!注意,這裡是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 payStr = PayUtil.createLinkString(packageP); String paySign = PayUtil.sign(payStr,key,"utf-8").toUpperCase();*/ String paySign = PayUtil.createSign("UTF-8", packageP, MapUtils.getString(configProperties, "mah_password")); packageP.put("paySign", paySign); packageP.put("success", true); }else{ packageP.put("success",false); } }catch (Exception e){ e.printStackTrace(); log.info("介面異常"); } //將package 返回給小程式 return packageP;
2.微信小程式支付成功後的回撥(notify_url 寫的地址)
log.info("進入buy方法"); BufferedReader br = new BufferedReader(new InputStreamReader(httpRequest.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 = ""; Map map = XmlUtil.doXMLParse(notityXml); System.out.println("map = " + map); String returnCode = (String) map.get("return_code"); try{ if("SUCCESS".equals(returnCode)){ //判斷是否處理過 //進行簽名驗證,看是否是從微信傳送過來的,防止資金被盜 SortedMap stringStringMap = PayUtil.paraFilter(map); String signMy = PayUtil.createSign("utf-8", stringStringMap, MapUtils.getString(configProperties, "mah_password")); System.out.println("signMy = " + signMy); System.out.println("flag = " + map.get("sign")); if(signMy.equals(map.get("sign"))){ String out_trade_no=(String) map.get("out_trade_no"); /* * 存入資料庫的邏輯 */ 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[報文為空]]></return_msg>" + "</xml> "; } BufferedOutputStream out = new BufferedOutputStream(httpResponse.getOutputStream()); out.write(resXml.getBytes()); //告訴微信伺服器,我收到了,不要再回調action方法了 out.flush(); out.close(); }}catch (Exception e){ e.printStackTrace(); }
PayUtil工具類:
/** * 是否簽名正確,規則是:按引數名稱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 * 編碼格式 * 請求引數 * @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; } /** * 把陣列所有元素排序,並按照“引數=引數值”的模式用“&”字元拼接成字串 * @param params 需要排序並參與字元拼接的引數組 * @return 拼接後字串 */ public static String createLinkString(Map<Object, Object> params) { List<String> keys = new ArrayList<String>(); Collections.sort(keys); String prestr = ""; for (int i = 0; i < keys.size(); i++) { String key = keys.get(i); Object value = params.get(key); if (i == keys.size() - 1) {// 拼接時,不包括最後一個&字元 prestr = prestr + key + "=" + value; } else { prestr = prestr + key + "=" + value + "&"; } } return prestr; } /** * @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 + ">" + v + "</" + k + ">"); } else { sb.append("<" + k + ">" + v + "</" + k + ">"); } } sb.append("</xml>"); return sb.toString(); } /** * 驗證簽名,判斷是否是從微信發過來 * 驗證方法:接收微信伺服器回撥我們url的時候傳遞的xml中的引數 然後再次加密,看是否與傳遞過來的sign簽名相同 * @param map * @return */ public static boolean verifyWeixinNotify(Map<Object, Object> map,String key) { //根據微信服務端傳來的各項引數 進行再一次加密後 與傳過來的 sign 簽名對比 String mapStr = createLinkString(map); String signOwn = PayUtil.sign(mapStr, key, "utf-8").toUpperCase(); //根據微信端引數進行加密的簽名 String signWx = (String) map.get("sign"); //微信端傳過來的簽名 if(signOwn.equals(signWx)){ //如果兩個簽名一致,驗證成功 return true; } return false; } /** * 簽名字串 * @param text 需要簽名的字串 * @param sign 簽名結果 * @param key 金鑰 * @param input_charset 編碼格式 * @return 簽名結果 */ public static boolean verify(String text, String sign, String key, String input_charset) { text = text +"&key="+ key; String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset)); System.out.println("mysign = " + mysign); if (mysign.equals(sign)) { return true; } else { return false; } } /** * 元轉換成分 * @param amount * @return */ public static String getMoney(String amount) { if(amount==null){ return ""; } // 金額轉化為分為單位 String currency = amount.replaceAll("\\$|\\¥|\\,", ""); //處理包含, ¥ 或者$的金額 int index = currency.indexOf("."); int length = currency.length(); Long amLong = 0l; if(index == -1){ amLong = Long.valueOf(currency+"00"); }else if(length - index >= 3){ amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", "")); }else if(length - index == 2){ amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0); }else{ amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00"); } return amLong.toString(); } /** * 獲取隨機字串 (採用擷取8位當前日期數 + 4位隨機整數) * @return */ public static String getNonceStr() { //獲得當前日期 Date now = new Date(); SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss"); String currTime = outFormat.format(now); //擷取8位 String strTime = currTime.substring(8, currTime.length()); //得到4位隨機整數 int num = 1; double random = Math.random(); if (random < 0.1) { random = random + 0.1; } for (int i = 0; i < 4; i++) { num = num * 10; } num = (int)random * num; return strTime + num; } /** * MD5 加密,轉為指定型別 * @param text * @param key * @param input_charset * @return */ public static String sign(String text, String key, String input_charset) { text = text + key; return DigestUtils.md5Hex(getContentBytes(text, input_charset)); } 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簽名過程中出現錯誤,指定的編碼集不對,您目前指定的編碼集是:" + charset); } } /** * 除去陣列中的空值和簽名引數 * @param sArray 簽名引數組 * @return 去掉空值與簽名引數後的新簽名引數組 */ public static SortedMap<Object, Object> paraFilter(Map<String, String> sArray) { SortedMap<Object, Object> result = new TreeMap<Object, Object>(); 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; }
支付就可以實現了,如果大家有什麼問題,可以隨時留言。。。
覺得棒的話,趕緊打賞小編吧!
相關推薦
微信小程式+java後臺實現支付(java操作)
支付,在微信小程式上面稱為當一個使用者使用該小程式,當進入到支付環節,我們需要呼叫微信支付介面過程,進行一系列的操作,並記錄下來。 微信小程式與java介面實現支付操作,大致思路如下: 1.微信小程式呼叫Java後臺方法獲取引數, 2.java 後臺設定引數等並
微信小程式超級大坑之40029(invalid code) 微信小程式超級大坑之40029(invalid code)
微信小程式超級大坑之40029(invalid code) 在小程式新建的時候就應該輸入你正式的AppID,如果使用修改的AppID,則無法使用。 jscode2session會返回{"errcode":40029,"errmsg":"i
微信小程式之封裝HTTP請求(升級版)
// 該函式怎麼寫,需要跟後端人員協商返回的格式 function getErrorMsgByErrorNo(error_no) { let error_msg; switch (err
微信小程式教學第三章(含視訊):小程式中級實戰教程:列表-靜態頁面製作
§ 列表 - 開發準備 開始前請把 ch3-1 分支中的 code/ 目錄匯入微信開發工具 這一章主要會教大家如何用小程式製作一個可以無限載入的列表。希望大家能通過這個例子掌握製作各種列表的原理。 無限列表載入的原理
關於微信小程式中圖示的引用(基於iconfont)
步驟如下: iconfont圖示程式碼下載 在該網站中尋找我們需要的圖示,加入購物車(注意是加入購物車哦。如圖) 【加入購物車】 【檢視購物車,點選下載程式碼】 【下載後的檔案,解壓】 關注解壓檔案 【iconfont.ttf】和【
微信小程式:教師評分系統(試題頁)
一、實現試題左右滑動功能試卷的試題頁採用滑塊檢視容器(swiper)可以更方便檢視試題。從 1.4.0 開始,change事件返回detail中包含一個source欄位,表示導致變更的原因,可能值如下:autoplay 自動播放導致swiper變化;touch 使用者划動引起
微信小程式開發之formId使用(模板訊息)
基於微信小程式的模板訊息 下發條件:使用者本人在微信體系內與頁面有互動行為後觸發 1. 使用說明 1.1 獲取模板id 頁面的 <form/> 元件,屬性 report-submit 為 true 時,可以宣告為需發模板訊息,此
微信小程式WXML頁面常用語法(講解+示例)
![](http://image.ideal-20.cn/weixin-mini/19-01-02-000.png) # (一) WXML 是什麼 官方說明:WXML(WeiXin Markup Language)是框架設計的一套標籤語言,結合基礎元件、事件系統,可以構建出頁面的結構 在前面我們就已經提
微信小程式+java後臺實現登入(java操作)
登入,在微信小程式上面稱為當一個使用者使用該小程式,進入到小程式中,我們拿到該使用者的資訊,進行一系列的操作,並記錄下來。 微信小程式與java介面實現登入操作,大致思路如下: 1.微信小程式端通過呼叫對應的api,將對應的變數傳入後臺(code、iv、encr
微信小程式 c#後臺支付結果回撥
public partial class NativeNotifyPage : System.Web.UI.Page { public static string wxJsApiParam { get; set; } //前段顯示 public string r
微信小程式 scroll-view 實現錨點跳轉
在微信小程式中,使用scroll-view實現長頁面的標記跳轉,官方文件中沒有例子演示,錨點標記主要是使用<scroll-view>的scroll-into-view屬性。 實現錨點跳轉主要以下幾點: 1,最外層容器使用滾動檢視 2,賦值滾動到檢視,如:<s
微信小程式lianc++後臺
貼上微信小程式傳送http請求程式碼: onsend: function(){ wx.request({ url: 'http://127.0.0.1:1000', //c++後臺ip、埠 data: { x: '1' ,
微信小程式:Animation實現圖片旋轉動畫
最近小程式中有一個圖片旋轉的需求,最初是想著通過切換多張圖片達到旋轉的效果,後來發現微信小程式帶有動畫api,然後就改由image+Animation來實現。 ###首先在wxml中定義image <image class="bth_image2" mode="aspec
微信小程式 scroll-view實現錨點滑動
轉載,原文: 微信小程式 scroll-view實現錨點滑動的示例 https://www.jb51.net/article/129897.htm 選擇scroll-view(可滾動檢視區域)元件來實現錨點效果。 具體實現 具體API就不贅述了,可以
微信小程式評論功能實現原始碼,複製貼上
wxml: 傳送 js: var ComContent = ‘’ var CommentList = ‘[]’ var app = getApp() Page({ /** * */ data: { CommentList: [{}], bindContent: null, Co
【微信小程式】c# 實現獲取openid、session_key 服務端
c#寫一個獲取微信小程式 openid和session_key 的方法。。 1,微信小程式端 // 登入 wx.login({ success: res => { // 傳送 res.code 到後臺換取 openId, sessionKey,
微信小程式和後臺API通訊
1、微信小程式不能直接訪問後臺的介面。 2、通過內網穿透實現,暴漏到公網。 3、這裡使用的工具是 ngrok.com 使用ngrok進行內網穿透 1、開啟https://dashboard.ngrok.com,註冊賬號登陸,download 下載適合自己電腦的。
微信小程式,圖片上傳在java後端接收不到圖片的問題
在使用小程式的圖片上傳時,發現一直接收不到圖片,最後找到問題是Spring-mvc.xml配置檔案對圖片進行了預處理,所以導致沒有接收到。將配置檔案 <bean id="multipartResolver" class="or
Slog69_實現一個帶引數的雲函式GET!(微信小程式之雲開發-全棧時代2)
ArthurSlog SLog-69 Year·1 Guangzhou·China Sep 11th 2018 禍兮福之所倚 福兮禍之所伏 開發環境MacOS(High Sierra 10.13.5) 需要的資訊和資訊源: 前言 騰訊推出“雲開發”概
(五)微信小程式-文章列表-實現及在全域性樣式表新增頁面預設字型樣式
文章列表 每篇文章包含文章標題、文章頭圖、文章概要、評論數和閱讀數,基本上使用view, image, text 這三個元件就可以完成 先將準備好的圖片放在根目錄images檔案相應的路徑下,沒有建立,不過多解釋 我們在前序博文微信輪播圖實現專案下繼續操作操作 在post.wxm