天天看點

小程式雲開發:菜鳥也能全棧做産品

我想獨立實作一個全棧産品為什麼這麼難

日常生活中,我們會使用很多軟體産品。在使用這些産品的時候,我們看得見的東西稱為“前端界面”如一個輸入框、一個按鈕,點選按鈕之後發生的一切看不見的東西稱為“後端服務”。與之對應的創造者分别稱為“前端程式員”、“後端程式員”,然而,一個完整産品的開發不僅僅是隻有前端和後端,還有設計師,架構師,運維等。有沒有可能這些所有的事情都一個人幹呢?有可能,事實上如今就有很多的“全棧工程師”,他們身兼數職,是多面手。能獨立完成一個産品的方方面面。這種人固然十分了得,他們通常具有多年的經驗,涉獵廣泛,是老手,也是高手,當有一個産品想法的時候,他們可以用自己的全面專業技能,盡情的發揮去實作自己的想法。是以,從某種意義上講“全棧也是一種自由”,你可以自由的實作你的想法,這簡直太美妙了!

然而,很多時候當我們有一個産品想法的時候,我們往往發現,前端寫完了,後端怎麼搞?資料庫怎麼搞?域名怎麼搞?域名還要備案?應用部署怎麼搞?我的買什麼樣的伺服器啊?靜态資源 CDN 怎麼搞?檔案上傳伺服器怎麼搞?萬一通路使用者多了能撐住嗎?等等……問題很多,導緻你的一個個想法,都隻是在腦海中昙花一現,從來都無法将她們實作,或者說你激情飽滿的實作了其中自己最擅長的一部分,當碰到其他難題的時候就止步了。于是仰天長嘯:我就想獨立做一個完整的産品為什麼這麼難?年輕人,這一切都不怪你……

破局:小程式雲開發

為什麼使用小程式雲開發來破局?

為啥是用“小程式雲開發”來破局?首先,我們的目的是全棧實作一個産品。全棧可以有多種技術方案,你可用任何你能會的技能來達到全棧的目的。你可以開發安卓,IOS,或者 PC 站,然而小程式是最實際的!為啥?手機上能做的事情為啥要用 PC 版?OK,既然手機版比較好,那能不能再簡單一點?能,就是小程式,不需要開發IOS,安卓兩個版本。可以快速産出,快速試錯。

其次,前面說到了,全棧實作一個産品并不容易,對很多人來說甚至是巨難!選擇了小程式已經是比較劃算的方案。而再內建雲開發,全棧立馬就有了。這就是為什麼選擇“小程式雲開發”來破局。

小程式雲開發是什麼?

小程式雲開發是什麼?官方文檔是這麼說的:開發者可以使用雲開發開發微信小程式、小遊戲,無需搭建伺服器,即可使用雲端能力。雲開發為開發者提供完整的原生雲端支援和微信服務支援,弱化後端和運維概念,無需搭建伺服器,使用平台提供的 API 進行核心業務開發,即可實作快速上線和疊代,同時這一能力,同開發者已經使用的雲服務互相相容,并不互斥。

看完上面的描述,也許你仍然無法非常清楚的知道什麼是“小程式雲開發”,沒關系,你隻需要注意加粗的部分,大概知道它“無需搭建伺服器”,從傳統觀念将,這個似乎“毀三觀”咋可能沒伺服器啊?是的,可以沒有傳統意義上的伺服器,這種模式是 serveless 的。

那麼,小程式雲開發提供了哪些東西來破局呢?且看下面的表格:

能 力 作 用 說 明
雲函數 無需自建伺服器 在雲端運作的代碼,微信私有協定天然鑒權,開發者隻需編寫自身業務邏輯代碼
資料庫 無需自建資料庫 一個既可在小程式前端操作,也能在雲函數中讀寫的 JSON 資料庫
存儲 無需自建存儲和 CDN 在小程式前端直接上傳/下載下傳雲端檔案,在雲開發控制台可視化管理
雲調用 原生微信服務內建 基于雲函數免鑒權使用小程式開放接口的能力,包括服務端調用、擷取開放資料等能力

上面的表格中提到了“雲開發”中的一些能力:“雲函數”,“資料庫”,“存儲”,“雲調用”,我們可以将這些詞帶入你曾經開發過的應用,看看它們分别代表了哪些部分。對于程式員來說,如果有疑問的話,沒有什麼是一個 helloword 解決不了的。

實戰:獨立開發一個簡易的零售小程式

哆嗦再多,不如實戰。下面我們就來使用小程式雲開發實作一個簡單的零售小程式。

項目構思

既然是一個零售小程式,那麼我們可以思考一下零售小程式的大緻業務流程,以及粗略的梳理一下,其功能點。現根據自己的想法,大緻畫一下草圖,如果沒有靈感可以參考一下别的 APP 是如何設計的。

我根據自己的想法設計之後是這樣的:

功能子產品:首頁,商品清單頁,購物車,确認訂單,個人中心,個人訂單,管你子產品(商品添加,分類添加)其中商品需要上傳圖檔。

梳理完功能之後,我們對于要實作的東西已經有個初步的概念了。接下來,我們需要大概畫一下頁面設計、及功能流轉。初次設計可能沒有太多經驗,沒關系,開始做就行了,做着做着就會想法越來越多,然後優化的越來越好。。我也是經過了多番修改調整,最終找到了一些思路。我的(拙劣)設計如下,圖檔如果看不清楚可複制圖檔連結在新視窗打開檢視:

小程式雲開發:菜鳥也能全棧做産品

說明,以上圖檔是根據成品(我真的開發了一個雲小程式并上線使用了)截圖的,而實際我再設計的時候也是經過幾番修改才最終定成這樣。

同時,補充說明一下,這裡前端頁面使用的是 vant-weapp控件,非常好用。推薦!如果你和我一樣是一個純後端程式員,建議使用 vant-weapp 來作為 ui,非常友善。否則自己寫頁面樣式的話可能就做不出來了。全棧不是那麼好幹的啊。選擇自己能駕馭的,能實作最終功能,就是一個合格的全棧。

建立小程式雲開發項目

我們先下載下傳微信小程式開發工具,下載下傳位址在這裡,安裝好了之後,建立項目,界面如下,APPID 需要你自己去注冊一個。然後注意,選擇“小程式雲開發”,如下圖所示:

小程式雲開發:菜鳥也能全棧做産品

建立好了之後,項目目錄如下,先看 1 标注的地方:

小程式雲開發:菜鳥也能全棧做産品

如果你曾經有過小程式的開發經驗,那麼

miniprogram

檔案夾下面的結構你肯定熟悉了,

miniprogram

下面的子目錄分别是小程式對應的元件、圖檔、頁面、樣式以及

app.js

,

app.json

sitemap.json

,其中

components

下面的

vant-weapp

就是上面提到的 ui 元件。

最後一個比較重要的檔案夾就是

cloudfunctions

,這個目錄是用來存放“雲函數的”,雲函數就是我們的後端。每一個雲函數提供一個服務。一個個的雲函數組成了我們整體的後端服務。雲函數可以看做是 FaaS(function as a service)。途中,2 标記的位置的“雲開發”按鈕,我們點進去,就可以看到“雲開發的控制台”,如下圖所示:

小程式雲開發:菜鳥也能全棧做産品

如果上圖看不清楚,可以複制連結到新的浏覽器視窗檢視,如圖,小程式雲開發預設的免費套餐有一定的額度可供使用。首頁便是使用統計。然後我們能看到,有“資料庫”,“存儲”,“雲函數”。

這裡的“資料庫”其實就是類似于一個 MongoDB,你可以點進去建立一個個的 collection(即:關系型資料庫中的table);這裡的“存儲”其實就是“檔案夾”,我們可以通過微信提供的 api把圖檔上傳到“存儲”中;這裡的“雲函數”就是我們需要實作的後端業務邏輯,他就是一個個的函數(函數由我們自己寫好後上傳)。一般開發過程中我們在開發者工具中的

cloudfunctions

目錄下建立雲函數(比方說是:user-add)開發完成之後在雲函數目錄點選右鍵——上傳即可。然後就可以在小程式的代碼中調用這個

user-add

雲函數。

雲開發之——3 分鐘實作檔案上傳

注意:在開始雲開發之前,我們現在 小程式代碼的 app.js 中加入

wx.cloud.init

,如下:

App({
  onLaunch: function () {
    if (!wx.cloud) {
      console.error('請使用 2.2.3 或以上的基礎庫以使用雲能力')
    } else {
      wx.cloud.init({
        // env 參數說明:
        //   env 參數決定接下來小程式發起的雲開發調用(wx.cloud.xxx)會預設請求到哪個雲環境的資源
        //   此處請填入環境 ID, 環境 ID 可打開雲控制台檢視
        //   如不填則使用預設環境(第一個建立的環境)
        env: 'your-env-id',
        traceUser: true,
      })
    }
    this.globalData = {}
  }
})
           

上面的圖中,我們已經看到了“商品添加”頁面的效果,它需要我們輸入商品名稱、價格、并上傳圖檔,然後儲存。傳統架構中,上傳圖檔需要前端頁面擺一個控件,然後後端提供一個 api用來接收前端傳來的檔案,通常來說這個後端 api 接收到圖檔之後,會将圖檔檔案儲存到自己的檔案伺服器或者是阿裡雲存儲、或者是七牛雲存儲之類的。然後傳回給你一個檔案連結位址。非常麻煩,然而,小程式雲開發上傳檔案超級簡單,上代碼:

頁面代碼:
<van-notice-bar
  scrollable="false"
  text="釋出商品"
/>
  <van-field
    value="{{ productName }}"
    required
    clearable
    label="商品名稱"
    placeholder="請輸入商品名稱"
    bind:change="inputName"
  />
    <van-field
    value="{{ productPrice }}"
    required
    clearable
    label="價格"
    icon="question-o"
     bind:click-icon="onClickPhoneIcon"
    placeholder="請輸入價格"
    error-message="{{phoneerr}}"
    border="{{ false }}"
    bind:change="inputPrice"
  />

<van-action-sheet
  required
  show="{{ showSelect }}"
  actions="{{ actions }}"
  close-on-click-overlay="true"
  bind:close="toggleSelect"
  bind:select="onSelect" cancel-text="取消"
/>
  <van-field
    value="{{ productCategory }}"
    center
    readonly
    label="商品分類"
    border="{{ false }}"
    use-button-slot
  >
    <van-button slot="button" size="small" plain type="primary"  
     bind:click="toggleSelect">選擇分類</van-button>
  </van-field>
  
  <van-button class="rightside" type="default" bind:click="uploadImage" >上傳商品圖檔</van-button>
  <view class="imagePreview">
    <image src="{{productImg}}" />
  </view>
 <van-submit-bar
  price="{{ totalShow }}"
  button-text="送出"
  bind:submit="onSubmit"
  tip="{{ false }}"
 >
 </van-submit-bar> 
<van-toast id="van-toast" />
<van-dialog id="van-dialog" />
           

這裡有個控件,綁定了

uploadImage

方法,其代碼為:

uploadImage:function(){
    let that = this;
    wx.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success(res) {
        wx.showLoading({
          title: '上傳中...',
        })
        const tempFilePath = res.tempFilePaths[0]
        const name = Math.random() * 1000000;
        const cloudPath = name + tempFilePath.match(/\.[^.]+?$/)[0]
        wx.cloud.uploadFile({
          cloudPath:cloudPath,//雲存儲圖檔名字
          filePath: tempFilePath,//臨時路徑
          success: res => {
            let fileID = res.fileID;
            that.setData({
              productImg: res.fileID,
            });
            wx.showToast({
              title: '圖檔上傳成功',
            })
          },
          fail: e =>{
            wx.showToast({
              title: '上傳失敗',
            })
          },
          complete:()=>{
            wx.hideLoading();
          }
        });
      }
    })
  }
           

這裡,

wx.chooseImage

用于調起手機選擇圖檔(相冊/相機拍照),然後

wx.cloud.uploadFile

用于上傳圖檔到上面說到的雲開發能力之一的“存儲”中。上傳圖檔成功之後傳回一個檔案 ID,類似:

cloud://release-0kj63.7265-release-0kj63-1300431985/100477.13363146288.jpg	
           

這個連結可以直接在小程式頁面展示:

<image src="cloud://release-0kj63.7265-release-0kj63-1300431985/100477.13363146288.jpg	" />
           

也可以通過微信 api,裝換成 http 形式的圖檔連結。

雲開發之——操作資料庫,1 分鐘寫完儲存商品到資料庫的代碼

上面我們實作了商品圖檔上傳,但是,商品圖檔并沒有儲存到資料庫。正常錄入商品的時候,我們會填好商品名稱,價格等,然後上傳圖檔,最終點選“儲存”按鈕,将商品儲存到資料庫。傳統模式下,前端仍然是需要調用一個後端接口,通過 post 送出資料,最終由後端服務(比如 java 服務)将資料儲存到資料庫。小程式雲開發使得操作資料庫十分簡單,首先我們在雲開發控制台建立“商品表”,即一個

collection

,取名為:

products

。然後我們就可以儲存資料到資料庫了,代碼如下:

onSubmit:function(){
    // 校驗代碼,略
    let product = {};
    product.imgId = this.data.productImg;
    product.name= this.data.productName;
    product.categoryId = this.data.productCategoryId;
    product.price = this.data.productPrice;
    // 其他指派,略
    const db = wx.cloud.database();
    db.collection('products').add({
     data: product,
     success(res) {
       wx.showToast({
         title: '儲存成功',
       })
     }
   });
  }
           

以上就實作了資料入庫,就這點代碼,超簡單,1 分鐘寫完,誠不欺我。其中這裡的

products

就是我們的“商品表”,之前說過,類似 MongoDB 資料庫,這裡操作的是

db.collection

,這和 MongoDB 的文法差不多。

雲開發之——使用雲函數完成後端業務邏輯,訂單建立

小程式雲開發提供了幾大能力:“資料庫”,“存儲”,“雲函數”,前兩項我們已經有所體會了。下面我們能建立一個雲函數來實作訂單建立。這裡說明,雲函數其實就是 一段JavaScript 代碼,上傳至雲伺服器之後,最終也是運作在 nodejs 環境的,隻是這一切,我們不需要關心。我們隻需要關心我們這個雲函數提供的功能是什麼就可以了。

建立雲函數很簡單,直接在開發工具中右鍵“建立Node.js 雲函數”。然後以建立訂單為例,假設我們建立一個雲函數名為

c-order-add

,建立好了之後,目錄是這樣:

小程式雲開發:菜鳥也能全棧做産品

雲函數的主要代碼在 index.js 中,其完整代碼是這樣:

// 雲函數入口檔案
const cloud = require('wx-server-sdk')
cloud.init({
  env: 'release-xxx'// your-env-id
})
const db = cloud.database()

// 雲函數入口函數
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext();
  console.log("雲函數 c-order-add : ")  
  // 這裡是一些邏輯處理...
  
  return await db.collection('uorder').add({
    data: {
      openid: event.userInfo.openId,
      address: event.address,
      userName: event.userName,
      phone: event.phone,
      shoppingInfo: event.shoppingInfo,
      totlePrice: event.totlePrice,
      shoppingStr: event.shoppingStr,
      remark:event.remark,
      createTime: now,
      // ...
    }
  });
}
           

這個雲函數寫好之後,需要上傳到伺服器,直接在雲函數目錄點選右鍵,然後點選“上傳并部署”即可,這就相當于部署好了後端服務。前端小程式頁面調用的寫法是這樣的:

let orderData={};
orderData.userName = this.data.userName;
orderData.phone = this.data.phone;
orderData.address = this.data.address;
// ....
wx.cloud.callFunction({
      // 雲函數名稱
      name: 'c-order-add',
      // 傳給雲函數的參數
      data: orderData,
      complete: res => {
        Dialog.alert({
          title: '送出成功',
          message: '您的訂單成功,即将配送,請保持手機通暢。'
        }).then(() => {
          // ....
          wx.redirectTo({
            url: '../uorder/uorder'
          });
        });
      }
})
           

這裡,向程式前端,通過

wx.cloud.callFunction

完成了對雲函數的調用,也可以了解為對後端服務的調用。至此我們我們介紹完了,小程式雲開發的功能。雖然,我隻貼出了少量的代碼,即儲存商品,和送出訂單。由于時間和篇幅有限,我不可能把整個完整的程式代碼貼出來。但是你可以參照這個用法示例,将剩下的業務邏輯補充完整,最終完成“項目構思”一節中展示的成品截圖效果。

小程式稽核的一點經驗

我開發的小程式稽核在送出稽核的時候遭遇了兩次退回,第一次是因為:“小程式具備電商性質,個人小程式号不支援”。是以,我隻好申請了一個企業小程式号,使用的是超市的營業執照。服務類目的選擇也被打回了一次,最後選擇了食品還送出了食品經營許可證。第二次打回是因為:“使用者體驗問題”。其實就是“授權索取”的問題,微信不讓打開首頁就“要求授權”,同時不能強制使用者接受授權,得提供拒絕授權也能使用部分功能。

上面兩條解決之後,更新新了好幾版,都沒有出現過被拒的情況。并且,有次我是夜晚 10 左右提價的稽核,結果10 點多就提示稽核通過,當時沒看具體時間,就是接盆水泡了個腳的時間稽核通過了。是以,我推斷小程式稽核初次稽核會比較嚴,之後如果改動不大應該直接機審就過了。

總結及對比

這裡我們可以對小程式雲開發和傳統模式做一個對比:

對比條目 傳統模式 雲開發
是否需要後端服務 需要 (如一個java應用部署在 Tomcat 中) 不需要 隻需要“雲函數”
是否需要域名 需要 (還得在微信背景的把域名加入安全域名) 不需要
是否需要購買伺服器 需要 (你得部署後端 Java 應用,還得安裝資料庫)

不需要

開通雲開發之後免費套餐夠用

不夠的話購買套餐按調用量計費

是否需要懂運維

需要

(你得會折騰伺服器,資料庫之類的

還得配置好相關的使用者,端口,啟動服務)

圖檔上傳及 CDN 麻煩 簡單
擷取微信 openID 超級簡單,雲函數中直接擷取
···

就對比這麼多吧,總之,我非常喜歡小程式雲開發,小程式真的可以讓你輕松幹全棧。或者咱們别動不動就提“全棧”,姑且說,小程式雲開發可以讓你更簡單、更快速、更便宜的實作你的産品落地。我自己開發的雲小程式上線之後,使用了一兩個月,沒出現任何問題。我也不用操心伺服器什麼的。是以,我已經給身邊很多人安利了小程式雲開發了。這裡我就不貼出我的小程式碼了,因為已經正式給我同學的超市使用了,是以不友善讓别人去産生測試資料。如果你感興趣想看的話,可以聯系我。郵件[email protected]

Docker & k8s 系列一:快速上手docker

Docker & k8s 系列二:本機k8s環境搭建

Docker & k8s 系列三:在k8s中部署單個服務執行個體

小程式雲開發:菜鳥也能全棧做産品

感謝您的閱讀,歡迎您評論交流。PS:部落格園已停更,後續請通過郵件或者公衆号聯系