天天看點

code換取微信openid_微信小程式登入+支付(背景Java)Demo實戰(環境搭建+源碼)...♪ 點選上方綠标 收聽微信小程式-登入+支付

點選上方[全棧開發者社群]→右上角[...]→[設為星标⭐]

code換取微信openid_微信小程式登入+支付(背景Java)Demo實戰(環境搭建+源碼)...♪ 點選上方綠标 收聽微信小程式-登入+支付

♪ 點選上方綠标 收聽微信小程式-登入+支付

介紹一個可運作的微信小程式登入+支付的demo。接觸了小程式簡易教程的,想必都知道我們必然有自己的背景應用伺服器,來處理我們自己的業務邏輯、請求微信服務完成一定的功能。在此,我們的背景采用java環境,本文将首先介紹環境搭建的過程,随後介紹登入+支付的流程及代碼。

一、背景web服務環境搭建

1. 安裝jdk、tomcat,ICP備案的域名準備。 

Linux安裝jdk:https://blog.csdn.net/zhang918784312/article/details/79751283

Linux 安裝tomcat:https://www.cnblogs.com/EasonJim/p/7202844.html

經過icp備案的域名,請自行準備。 

2.配置https,由于小程式請求url必須是https,故而必須配置支援https請求。本人采用的是在阿裡雲購買的域名,故而采用的證書也是阿裡雲生成的ssl證書,可參考如下兩篇博文進行配置。當然,你也可以通過别的方式生成證書,更或者通過nginx作反向代理到你的伺服器。 

https://blog.csdn.net/qq_28189091/article/details/75078164 

https://blog.csdn.net/z_xuewen/article/details/78176509 

同時,務必将您的小程式域名綁定在小程式後端。登入小程式背景,【設定】-【開發設定】-【伺服器域名】

3. 部署web服務 

如上兩步完成後,請務必确認通過你的域名(https://...)可以展示tomcat的預設頁之後,開始部署我們的web服務。在此,就簡單粗暴的在webapps下建立小程式的根目錄,我命名為wechatserver,在此目錄下,建立WEB-INFO,下面的目錄結構如下: 

code換取微信openid_微信小程式登入+支付(背景Java)Demo實戰(環境搭建+源碼)...♪ 點選上方綠标 收聽微信小程式-登入+支付

classes存放自己寫的類的classes檔案,lib存放我們項目依賴的jar包,logs用于存放我們的日志輸出,web.xml是我們這個項目的配置。 demo中,我們隻有一個servlet接收小程式前端請求,web.xml中增加配置如下:

<servlet>        <servlet-name>WechatServletservlet-name>        <servlet-class>com.icbc.servlet.WechatServletservlet-class>    servlet>    <servlet-mapping>        <servlet-name>WechatServletservlet-name>        <url-pattern>/servlet/WechatServleturl-pattern>    servlet-mapping>
           

4. log4j 應用 在開發調試中,我們免不了需要通過列印日志進行調試,是以在此增加了日志的使用。web.xml中增加配置:

<context-param>      <param-name>log4jConfigLocationparam-name>      <param-value>classes/log4j.propertiesparam-value>  context-param>  
           

在classes增加檔案,log4j.properties,内容如下:

log4j.rootLogger = INFO,toConsole,D,Elog4j.appender.toConsole=org.apache.log4j.ConsoleAppender log4j.appender.toConsole.Target=System.out  log4j.appender.toConsole.layout=org.apache.log4j.PatternLayout log4j.appender.toConsole.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] [%p] %m%nlog4j.appender.D = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.D.file = 你的目錄/common.loglog4j.appender.D.Append = truelog4j.appender.D.Threshold = info log4j.appender.D.layout = org.apache.log4j.PatternLayoutlog4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%nlog4j.appender.D.DatePattern='.'yyyy-MM-dd'.log'log4j.appender.E = org.apache.log4j.DailyRollingFileAppenderlog4j.appender.E.file = 你的目錄/error.log log4j.appender.E.Append = truelog4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayoutlog4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%nlog4j.appender.D.DatePattern='.'yyyy-MM-dd'.log'
           

log4j 在java中的引用、使用: public static Logger logger = Logger.getLogger(WechatServlet.class); logger.info(“列印資訊”);

二、微信小程式登入+支付

1. 小程式前端目錄準備

基于微信小程式工具生成的預設hello world程式,pages下先建立目錄order,随後在order目錄生成一個新的page,命名為order,結構如下圖: 

code換取微信openid_微信小程式登入+支付(背景Java)Demo實戰(環境搭建+源碼)...♪ 點選上方綠标 收聽微信小程式-登入+支付

在index中增加按鈕,進入order。 index.wxml

<view>    <navigator class="index-intro__btn btn btn-danger btn-md" url="/pages/order/order">進入商城navigator>  view>
           

order.xml中描述商品資訊,增加支付按鈕,order.js 支付事件處理。

2. 登入+支付 code

流程大概分為幾步: 

1)登入,擷取code(一個code隻能用一次) 

2)通過code擷取openid(通過請求伺服器,由伺服器請求微信擷取并傳回小程式)。微信登入+擷取openid接口。

3)小程式請求伺服器進行預下單,上送商品詳情、金額、openid。 

4)伺服器端接收請求,根據請求訂單資料、生成第三方訂單号,調用微信的統一下單接口。 

5)伺服器收到預下單資訊後,簽名并組裝支付資料,傳回給小程式。所需資料見:小程式支付接口 

6)小程式前端發起支付,并支付完成 

7)伺服器收到回調。

2.1 登入,擷取code。

onLoad: function (options) {    // 登入    wx.login({      success: function (res) {        // 發送 res.code 到背景換取 openId, sessionKey, unionId        var that = this;        if (res.code) {          console.log('擷取使用者登入态success!' + res.code)          app.globalData.code = res.code        } else {          console.log('擷取使用者登入态失敗!' + res.errMsg)        }      }    })    },
           

2.2 通過code 擷取openid(前端)

getOpenId:function(that, code){    console.log(code);    let operFlag = "getOpenid";    console.log(operFlag);    wx.request({      url: 'https://xxx/wechatserver/servlet/WechatServlet',      data: {        code:code,        operFlag:operFlag      },      header: { 'content-type': 'application/json' },      success: function (res) {        console.log(res);         var openid = res.data.openid;        console.log(openid);        that.paypay(that, openid); //預下單并支付      },      fail: function (res) {        console.log(res.data.errmsg);        console.log(res.data.errcode);      },      complete:function(res){      }    })  },
           

2.2 伺服器端servlet(複寫HttpServlet的doGet doPost函數)doPost的代碼片段:

//擷取操作類型,根據類型執行不同操作        String operFlag = request.getParameter("operFlag");        logger.info("operFlag=" + operFlag);        String results = "";        if("getOpenid".equals(operFlag)){            String code = request.getParameter("code");            logger.info("code=" + code);            String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid                     + "&secret=" + secretKey + "&js_code=" + code + "&grant_type=authorization_code";            logger.info("url=" + url);            results = sendGetReq(url);//發送http請求    }        logger.info("results = " + results);        response.setContentType("application/json;charset=UTF-8");        response.setHeader("catch-control", "no-catch");        PrintWriter out = response.getWriter();        out.write(results);        out.flush();        out.close();
           

2.3 前端上送訂單資訊、openid請求預下單(在此,為友善,訂單資訊直接寫死在伺服器端了),若成功,則根據伺服器端傳回資料發起支付。

paypay: function (that, openid) {    let operFlag = 'pay';    wx.request({      url: 'https://xxx/wechatserver/servlet/WechatServlet',      data: {        openid: openid,        operFlag: operFlag      },      header: { 'content-type': 'application/json' },      success: function (res) {        console.log(res);        wx.requestPayment({          'timeStamp': res.data.timeStamp,          'nonceStr': res.data.nonceStr,          'package': res.data.package,          'signType': 'MD5',          'paySign': res.data.sign,          'success': function (res) {            if (res.errMsg == "requestPayment:ok") {              wx.showToast({                title: '支付成功'              })            }          },          'fail': function (res) {          }        })      },      fail: function (res) {        console.log(res.data.errmsg);        console.log(res.data.errcode);      },      complete: function (res) {      }    })  },
           

2.4 伺服器端預下單,2.5并簽名傳回支付請求資料。

if("pay".equals(operFlag)){            String openid = request.getParameter("openid");            logger.info("openid = " + openid);            String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";            String reqStr = getReqStr(openid); //組裝預下單的請求資料            logger.info("reqStr=" + reqStr);            results = sendPost(url,reqStr);//發送post資料到微信預下單            logger.info("prepay from weixin: \n " + results);            Map<String,String> return_data = null;            try {                return_data = WXPayUtil.xmlToMap(results);//微信的一個工具類            } catch (Exception e) {                // TODO Auto-generated catch block                e.printStackTrace();                logger.error(e.getMessage());            }            String return_code = return_data.get("return_code");            logger.info("return_code=" + return_code);            if("SUCCESS".equals(return_code)){                String prepay_id = return_data.get("prepay_id");                results = conPayParam(prepay_id); //組裝傳回資料            }else{                results ="{\"return_code\":\"fail\"}";            }        }
           

三、實戰中遇到的問題

預下單和支付請求中,簽名的密鑰使用的是商戶密鑰,但是用code擷取openid是使用小程式對應的secret key,這個可以在小程式的背景看到。

微信小程式前端發起post請求到伺服器端時,伺服器端收不到請求參數。原因是:微信API接口wx.request中: 

a) 對于 GET 方法的資料,會将資料轉換成 query string(encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)…) 

b1) 對于 POST 方法且 header[‘content-type’] 為 application/json 的資料,會對資料進行 JSON 序列化 

b2) 對于 POST 方法且 header[‘content-type’] 為 application/x-www-form-urlencoded 的資料,會将資料轉換成 query string (encodeURIComponent(k)=encodeURIComponent(v)&encodeURIComponent(k)=encodeURIComponent(v)…)

是以,如果post請求,為省去伺服器端反序列化的操作時,可使用header[‘content-type’] 為 application/x-www-form-urlencoded 的資料。 

3. 如果部署了servlet後,tomcat重新開機後,需要等幾分鐘才能生效(原因是我的機器記憶體比較小,而tomcat又很占用記憶體資源),待熟悉tomcat 調優。

留言打卡第16天,早日脫單

code換取微信openid_微信小程式登入+支付(背景Java)Demo實戰(環境搭建+源碼)...♪ 點選上方綠标 收聽微信小程式-登入+支付

覺得本文對你有幫助?請分享給更多人

關注「全棧開發者社群」加星标,提升全棧技能

本公衆号會不定期給大家發福利,包括送書、學習資源等,敬請期待吧!

如果感覺推送内容不錯,不妨右下角點個在看轉發朋友圈或收藏,感謝支援。

好文章,我在看❤️

繼續閱讀