1. 程式人生 > >微信小程式+java後臺實現支付(java操作)

微信小程式+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 後臺設定引數等並

程式超級大坑之40029invalid code 程式超級大坑之40029invalid 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