1. 程式人生 > >[微信] 開發微信小程式程式碼實戰

[微信] 開發微信小程式程式碼實戰

開發微信小程式流程 接入微信小程式 > 程式碼開發 > 提交稽核和釋出

接入

接入是指在微信平臺註冊和相關身份資訊認證

1:微信公眾平臺(https://mp.weixin.qq.com/) 註冊小程式,獲取唯一標識AppId ,和相關身份資訊認證

2:微信商戶平臺(https://pay.weixin.qq.com/) 註冊,獲取商戶資訊,支付場景用到

開發準備

  •  IDE:官方提供的微信開發者工具,方便可以直接使用微信提供的各種API,解決自己電腦開發環境需要指定ip,提供平臺認證繁瑣流程
  • 後臺API: 安全起見,相關的登入和統一下單支付交由後臺後臺介面實現, 小程式傳送後臺請求需要再頭部傳入token,進行省份資訊確認

程式碼開發

  小程式程式碼結構圖

------img 圖片資源相關

------pages

.------- 模組程式碼實現

------utils

      http.js 微信請求包裝類

      wx.js登入包裝類

------app.js 主入口,

------app.json 主入口配置

------app.wxss 樣式

app.js,裡面存放全域性常量引數,其他模組可以直接通過getApp() 來獲取下面資訊

//app.jsApp({ onLaunch: function () { //呼叫API從本地快取中獲取資料 var logs = wx.getStorageSync
('logs') || []
logs.unshift(Date.now()); wx.setStorageSync('logs', logs); }, config: { baseUrl: "********", key: "**********", appid: "**********" }})

app.json 置頂小程式路由跳轉(pages) ,基本資訊(window), 底部導航選單(tabBar)

{ "pages":[ "pages/index/index", "pages/romance/romance", "pages/release/release"
,
], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor":"#fea213", "navigationBarTitleText":"第一個小程式", "navigationBarTextStyle":"#fff" }, "tabBar":{ "color":"#dddddd", "selectedColor":"#3cc51f", "borderStyle":"white", "backgroundColor":"#ffffff", "list":[{ "pagePath":"pages/index/index", "iconPath":"img/home.png", "selectedIconPath":"img/home1.png", "text":"首頁" }, { "pagePath":"pages/romance/romance", "iconPath":"img/manager.png", "selectedIconPath":"img/manager1.png", "text":"個人中心" } ] } }

http.js 封裝rest服務包裝類,其他模組方便直接呼叫,不用寫繁瑣程式碼

classHttp { app; constructor() { this.app =getApp(); } get(url,callback) { var instance =this; wx.request({ url: instance.app.config.baseUrl +url, data: {}, method: 'GET', header: { 'token':encodeURI(wx.getStorageSync("token")), 'content-type':'application/json' }, success: function (res) { if (res.data.errorCode =='user_not_login') { wx.clearStorageSync(); } if (callback)callback(res); }, fail: function (res) { console.log(res); } }) } post(url,data,callback) { var instance =this; wx.request({ url: instance.app.config.baseUrl +url, data: data, method: 'POST', header: { 'token':encodeURI(wx.getStorageSync("token")), 'content-type':'application/json' }, success: function (res) { if (res.data.errorCode =='user_not_login') { wx.clearStorageSync(); } if (callback)callback(res); }, fail: function (res) { console.log(res); } }); } } module.exports =Http;

wx.js 用來實現微信登入,獲取使用者基本資訊 ,呼叫後臺介面 url: app.config.baseUrl + "user/wxlogin",,取得關鍵的openId, 

class WxService { app; constructor() { this.app =getApp(); } login(app,callback) { var page =this; wx.login({ success: function (re) { if (re.code) { wx.getUserInfo({ success: function (res) { wx.setStorageSync('userInfo',res.userInfo); var data = { 'username':re.code, 'userSaveBean': {'username':'','password':'','name':res.userInfo.nickName,'birth':newDate().getTime,'address':res.userInfo.city,'mobile':13111111111,'headimg':res.userInfo.avatarUrl } } wx.request({ url: app.config.baseUrl +"user/wxlogin", data: data, method: 'POST', header: { 'content-type':'application/json' }, success: function (res) { var yxNum =res.data.responseBody.username; wx.setStorageSync('yxNum',yxNum); wx.setStorageSync('openId',res.data.responseBody.openid); var token =page.pwd(res.data.responseBody.openid,app.config.code,app.config.key); wx.setStorageSync('token',token); if (callback) callback(); }, fail: function (res) { console.log(res); } }); } }); } else { console.log('獲取使用者登入態失敗!' +res.errMsg) } } }) } } module.exports =WxService;

程式碼模組實現官網文件有大量詳細說明,比如html的編寫,元件,樣式,和各種api的使用

就不做過多描述,這裡說下支付

支付分兩步 : 統一下單 > 發起字元

通過統一下單介面,獲取微信返回的prepay_id ,再把prepay_id和其他相關資訊提供支付介面,支付

var preOrderUrl ="order/prepay?amount=1&articleId=" +aid +"&totalFee=" +total_fee +"&openid=" +openid; http.get(preOrderUrl,function (res) {//呼叫後臺統一下單介面,獲取prepay_id if (res.data.errorCode) { wx.hideLoading(); wx.showModal({ title: '失敗!', content: res.data.errorMsg.substring(0,res.data.errorMsg), showCancel: false }) return; } var paymentTS ="" +newDate().getTime(); var paymentNS ="" +newDate().getTime(); var prepayId =res.data.responseBody.prepay_id; var paymentPack ='prepay_id=' +res.data.responseBody.prepay_id; var orderId =res.data.responseBody.orderId; var strPaymentSign ="appId=" +appid +"&nonceStr=" +paymentNS +"&package=" +paymentPack +"&signType=MD5&timeStamp=" +paymentTS +"&key=" +key; var paySign =ma5Helper.toMd5(strPaymentSign).toUpperCase(); wx.requestPayment(//呼叫微信支付介面,付款 { timeStamp: paymentTS, nonceStr: paymentNS, package: paymentPack, signType: 'MD5', paySign: paySign, success: function (res) { //提交訂單到伺服器,儲存資料 var orderUrl =app.config.baseUrl +"order"; var orderData = {flag:true,orderId:orderId,prepayId:prepayId,msg:"" }; http.post("order",orderData,function (res) { wx.hideLoading(); if (res.data.errorCode) { wx.showModal({ title: '訂單提交失敗!', content: res.data.errorMsg.substring(0,res.data.errorMsg.indexOf('[')), showCancel: false }) } else { //支付成功 wx.showToast({ title: '支付成功', icon: 'success', duration: 3000, success: function () { wx.switchTab({ url: '../romance/romance', }) } }) } }); }, fail: function (res) { }, complete: function (res) { } }) }

統一下單

@GetMapping("/prepay")
public ResponseBean createOrderTemp(HttpServletRequest request, @ModelAttribute OrderTempSaveBean saveBean){
    saveBean.setSpbill_create_ip(okhttpService.getIpAddress(request));
return success(orderTempService.createOrderTemp(userFromToken(request),saveBean));
}

/**
 * 統一下單
 * @param user
* @param saveBean
* @return
*/
@Transactional
public Map createOrderTemp(User user,OrderTempSaveBean saveBean) {
    String orderNumber= (new Random().nextInt(100))+""+DateTime.now().toString(DateUtils.pattern.defualt_2.getContent())+user.getId();
if(saveBean.getTransType() == null)
       throw new BusinessException(ErrorCode.invalid_request,"編碼未設定");
OrderTempWithBLOBs orderTemp=new OrderTempWithBLOBs();
orderTemp.setFlag(true);
orderTemp.setStatus(OrderStatus.onCreate.name());
saveBean.setOpenid(user.getOpenid());
saveBean.setNonceStr(orderNumber);
saveBean.setOutTradeNo(orderNumber);
saveBean.setSpbill_create_ip(saveBean.getSpbill_create_ip() == null ? "1.1.1.1": saveBean.getSpbill_create_ip());
if(saveBean.getTotalFee() == null && saveBean.getTotalFee() <=0)
        throw new BusinessException(ErrorCode.invalid_request,"交易金額不對");
if(saveBean.getTransType().equals(TransType.C004)){

       if(saveBean.getAmount() == null && saveBean.getAmount() <=0)
           throw new BusinessException(ErrorCode.invalid_request,"數量不對");
Article article = articleMapper.selectByPrimaryKey(saveBean.getArticleId());
if(article ==null)
           throw new BusinessException(ErrorCode.article_not_found,"未找到");
if(new DateTime(article.getEndTime()).compareTo(new DateTime()) <0)
           throw  new BusinessException(ErrorCode.invalid_request,"已經結束") ;
saveBean.setBody("標題-"+article.getThemeTitle());
}else if (saveBean.getTransType().equals(TransType.C001)){
        saveBean.setAmount(1);
saveBean.setArticleId(-9999);
saveBean.setBody("浪漫之旅-充值");
}else{
        throw  new BusinessException(ErrorCode.invalid_request,"無效請求") ;
}

    Map unifiedorderMap=null;
try {
        unifiedorderMap= mWxPayService.createOrderTemp(saveBean);
logger.info("=============> createOrderTemp success : "+JSON.toJSONString(unifiedorderMap));
if(!"SUCCESS".equals(unifiedorderMap.get("return_code"))){
            throw new BusinessException(ErrorCode.invalid_request,unifiedorderMap.get("return_msg").toString());
}
        orderTemp.setPrepayId(String.valueOf(unifiedorderMap.get("prepay_id")));
}catch (BusinessException e){
        orderTemp.setFlag(false);
throw new BusinessException(e.getErrorCode(),e.getMessage());
}catch (Exception e){
        orderTemp.setFlag(false);
orderTemp.setMsg(e.getMessage());
e.printStackTrace();
logger.info("=============> createOrderTemp Exception : "+e.getMessage());
throw new BusinessException(ErrorCode.sys_error,"下單失敗了!");
}finally {
        orderTemp.setCreateTime(new Timestamp(System.currentTimeMillis()));
orderTemp.setParam(JSONObject.toJSONString(saveBean));
orderTemp.setCreateBy(user.getNickname() ==null ? "":user.getNickname());
orderTemp.setUserId(user.getId());
orderTemp.setOutTradeNo(orderNumber);
orderTemp.setAmount(saveBean.getAmount());
orderTemp.setArticleId(saveBean.getArticleId());
orderTemp.setBody(saveBean.getBody());
orderTemp.setPrice(saveBean.getTotalFee());
orderTemp.setSpbillCreateIp(saveBean.getSpbill_create_ip());
orderTemp.setMsg(JSONObject.toJSONString(unifiedorderMap));
orderTempMapper.insert(orderTemp);
unifiedorderMap.put("orderId",orderTemp.getId());
}

    return unifiedorderMap;
}

mWxPayService.createOrderTemp(saveBean) 實現
public Map createOrderTemp(OrderTempSaveBean saveBean) throws Exception {
    Map reqData = WxPayConfig.genUnifiedorder();
reqData.put("body", saveBean.getBody());
reqData.put("nonce_str", saveBean.getNonceStr());
reqData.put("out_trade_no", saveBean.getOutTradeNo());
reqData.put("total_fee",saveBean.getTotalFee().toString());
reqData.put("spbill_create_ip", saveBean.getSpbill_create_ip());
reqData.put("openid",saveBean.getOpenid());
reqData.put("sign", WXPayUtil.generateSignature(reqData, Const.key, SignType.MD5));String reqXml = WXPayUtil.mapToXml(reqData);
String response = okhttpService.post(Const.UNIFIEDORDER_URL_SUFFIX, reqXml);
return  WXPayUtil.xmlToMap(response);
}

WXPayUtil.generateSignature(reqData, Const.key, SignType.MD5))實現
public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
    Set<String> keySet = data.keySet();
String[] keyArray = keySet.toArray(new String[keySet.size()]);
Arrays.sort(keyArray);
StringBuilder sb = new StringBuilder();
for (String k : keyArray) {
        if (k.equals(Const.FIELD_SIGN)) {
            continue;
}
        if (data.get(k).trim().length() > 0) // 引數值為空,則不參與簽名
sb.append(k).append("=").append(data.get(k).trim()).append("&");
}
    sb.append("key=").append(key);
if (SignType.MD5.equals(signType)) {
        return MD5(sb.toString()).toUpperCase();
}
    else if (SignType.HMACSHA256.equals(signType)) {
        return HMACSHA256(sb.toString(), key);
}
    else {
        throw new Exception(String.format("Invalid sign_type: %s", signType));
}
}

WXPayUtil.mapToXml(reqData) 實現
/**
 * 將Map轉換為XML格式的字串
 *
 * @param data Map型別資料
 * @return XML格式的字串
 * @throws Exception
*/
public static String mapToXml(Map<String, String> data) 
            
           

相關推薦

[] 發微程式程式碼實戰

開發微信小程式流程 接入微信小程式 > 程式碼開發 > 提交稽核和釋出 接入 接入是指在微信平臺註冊和相關身份資訊認證 1:微信公眾平臺(https://mp.weixin.qq.com/) 註冊小程式,獲取唯一標識AppId ,和相關身份資訊認證 2:微信商

使用mpvue發微程式——原生程式、mpvue、wepy對比

mpvue是什麼?為什麼使用它? 目前小程式開發主要有三種形式:原生、wepy、mpvue,其中wepy是騰訊的開源專案;mpvue是美團開源的一個開發小程式的框架,全稱mini program vue(基於vue.js的小程式),vue開發者使用了這個框架後,開發小程式的效率將得到

Thinkphp 發微程式第二天檔案程式碼架構

    下載安裝工具後有個demo檔案,仔細分析檔案程式碼架構,瞭解程式碼才能更好的進行開發。 1,index資料夾     .json 字尾的 JSON 配置檔案     .wxml 字尾的 WXML 模板檔案     .wxss 字尾的 WXSS 樣式檔案     .

電商程式流量暴增 如何發微電商程式

2018年初,伴隨著微信月活躍使用者量達到10億,微信小程式的流量池正在不斷擴大。這也意味著,中國切實進入了無線網際網路的下半場—微信網際網路年代!微信小程式被視為社交電商生態框架的重要佈局,將重新定義電商行業。2017年微信生態電商營業額高達1萬億元,而電商小

發微程式進行支付步驟

最近開發微信小程式進入到支付階段,一直以來從事App開發,所以支付流程還是熟記於心的。但是微信小程式的支付就有點奇怪了,應用的建立是在公眾號裡,但是文件的介紹卻在公眾號中無法找到直接入口,甚是不解,而且小程式的師傅到底是屬於公眾號支付範疇還是app支付範疇也成疑問。下面

C#發微門戶及應用(47) - 整合Web API、後臺管理及前端程序的應用方案

post 裏的 www. 一個數據庫 展開 動態 建立 http 文本 在微信開發中,我一直強調需要建立一個比較統一的Web API接口體系,以便實現數據的集中化,這樣我們在常規的Web業務系統,Winform業務系統、微信應用、微信小程序、APP等方面,都可以直接調用基於

一步一步發微程式

   小程式的開發與傳統的web前端開發極其相似,想必各位技術宅們關心的是如何去開發一個小程式,這裡我簡單介紹一下如何簡單上手開發小程式。 第一步:安裝         首先下載微信開

程式程式碼上傳,稽核釋出程式

1.開啟微信開發者工具 管理員掃碼 -> 填寫好小程式的專案目錄、AppID(必須是客戶已註冊好的AppID)、專案名稱 2.在app.js中修改id(客戶登入後臺管理系統的id),app.json中修改頁面導航欄標題navigationBarTitleText

Java發微程式(三)用程式給使用者推送服務訊息

第三篇 用小程式給使用者推送服務訊息 1.小程式登入獲取,小程式的openId和unionId。 2.獲取並解密小程式的加密資訊包括使用者和手機資訊。 3.用小程式給使用者推送服務訊息。 4.給繫結小程式而且又關注微信公眾號的使用者推送公眾號訊息。 小程式訊息推送機制有

Java發微程式(二)獲取並解密程式使用者和手機資訊

第二篇 獲取並解密小程式的加密資訊包括使用者和手機資訊。 如果對其他的資訊幹興趣,還可以點選以下的連線 1.小程式登入獲取,小程式的openId和unionId。 2.獲取並解密小程式的加密資訊包括使用者和手機資訊。 3.用小程式給使用者推送服務訊息。​​​​​​​ 4.給繫結小

Java發微程式(一)登入並獲取程式的openId和unionId

第一篇 小程式登入獲取,小程式的openId和unionId。 最近公司做了一個微信的小程式應用,做了一些技術研究也踩了不少坑,不過最終結果不錯小程式順利上線。 在這裡做一個開發筆記,主要記錄以下幾個方面,分別用四篇文章來記錄: 1.小程式登入獲取,小程式的openId和unionId。

使用Mpvue發微程式——音樂程式專案原始碼分享

前言: 最近小組有個微信小程式分享的環節,於是在業餘時間使用mpvue框架寫了個音樂小程式,時間有限,專案暫時只是demo級別,之後有時間會繼續完善。 原始碼地址 github連結:https://github.com/XieTongXue/mpvue-music 專案簡

發微公眾號技巧(授權跳轉)

出發微信公眾號 先pick一個小技巧 開發過公眾號的朋友們知道流程,在使用者點選登入後,會在url上返回code...等值,這時候要取code值傳給後端同學,然後跳轉到我們的主頁面,大多數的朋友都是這種流程 window.location.href = 'url' // 但是呢,這樣會有

發微程式-目錄解析(二)

文件:https://developers.weixin.qq.com/miniprogram/dev/quickstart/basic/file.html#js-互動邏輯 普通快速模板 開發目錄 ├── app.js ├── app.json ├── app.wxss ├── pag

發微程式-安裝(一)

先註冊 https://mp.weixin.qq.com/wxopen/waregister?action=step1 下載小程式 https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html?t=181012

發微程式簡易教程

開發微信小程式簡易教程 開發小程式的第一步,你需要擁有一個小程式帳號,通過這個帳號你就可以管理你的小程式。 跟隨這個教程,開始你的小程式之旅吧! 申請帳號 點選 https://mp.weixin.qq.com/wxopen/waregister?action=step1 根據指引填

mpvue發微程式的全域性變數問題-Vuex

如果你以前使用過原生的小程式開發,現在要使用mpvue框架的話,你應該也會遇到以下的問題: 1. 怎麼存放可全域性訪問的變數? 2. 頁面跳轉的時候,怎麼傳遞引數到下一個頁面比較好? 3. 頁面返回上一頁的時候,怎麼傳遞當前頁的資料到上一頁? 4. 多個頁面間需要同步資料,怎麼做比較

程式程式碼最大限制2M的解決方案

瞭解小程式有最大程式碼量限制之前需要先了解微信小程式的本質:前端近幾年都處於技術爆炸時期, react 最早的是facebook開源的開發框架----react,支援移動網頁和原生app的開發(react native),提倡一次學習,全渠道開發。目的是讓產品研發更聚焦更敏捷,它有三個重要特

java發微公眾號(二)--測試號申請、與java程式碼初步互動

一、申請測試號 個人不能夠免費申請服務號,訂閱號有很多限制,介面許可權出來基本的幾乎沒有,如圖, 在微信公眾平臺,檢視介面許可權 那麼怎麼使用服務號的介面許可權呢?微信推出了測試號,交給大家使用,開通的步驟是: 1.在微信平臺頁面,在服務號中,點選開發者文件 2

程式程式碼結構簡介

在建立一個小程式工程之後,會顯示如下圖 project.config.json:微信開發者工具的配置資訊 app.js:幫助我們去註冊一個微信小程式的應用 app.json:微信小程式的一個全域性配置 app.wxss:設定微信小程式全域性的一些樣式 pages:存放的