兩小時快速構建微信小程序

小程序在2017年1月上線之初,被社會極力吹捧,刻意去將其製造爲一個「風口」,透支其價值。可是在以後一個月裏,石破天驚迅速歸爲沉寂。媒體又開始過分消費小程序,大談其雞肋之處。css

我的認爲小程序的一個分水嶺是在12月28日。微信升級到6.6.1版本,將小程序入口移植主界面,下拉主界面便可選擇進入,而且支持新類目「小遊戲」。小程序逐漸升溫,在整個微信生態中扮演愈來愈重要的角色。時至今日,小程序的風潮如日中天,優秀的小程序很容易獲得融資。這到底是是另外一輪泡沫,仍是小程序自己真正已經進入了成熟期?我我的更相信後者。html

我我的作過兩款小程序,對小程序有必定認識,但理解仍是比較淺的。今天就僅從如何快速搭建一個小程序談起,揭開小程序的一絲神祕面紗。前端

概述

  • 小程序是先後端分離的。
  • 前端使用的是微信自定義的一套規範wxml+wxss+json+js,我認爲本質仍是html+css+js
  • 後臺能夠選用任何你熟悉的語言:Java,Python,PHP,Ruby等等,在這篇文章裏我選用PythonFlask框架+Gunicorn+Nginx來快速搭建。
  • 數據庫我選擇MySQL,nosql數據庫我選擇Redis。固然,你的小程序能夠很輕量級,甚至不須要使用到數據庫。小程序一大思想「用完即走」。
  • 後臺須要跑在一臺本身的服務器上,同時你也須要一個已備案的https域名來進行映射。

附註

如今市面上也有一些第三方快速生成小程序的工具,和之前那些快速生成網站的是同一門生意。我我的並不推薦去使用那些,由於那些小程序幾乎千篇一概,沒法結合你本身的創意,沒法定製你須要提供的服務,並且一定存在一些收費。python

固然,這些平臺既然存在,那麼一定是市場需求,假如確實適合你,能爲你帶來一些效益,不妨一試。mysql

今天,咱們是以學習者的角度去構建小程序。nginx

準備工做

  1. 一臺雲服務器,能夠上各大雲提供商平臺租用,我使用的是學生低配,¥10/月。
  2. 我在服務器上使用的操做系統爲ubuntu
  3. 購買一個域名,並經過備案。域名價格在1-10000000不等,我使用的是某com域名,¥50/年。
  4. 在微信公衆平臺註冊一個帳號並下載小程序開發工具。詳細說明
  5. httphttps。如今不少SSL證書能夠免費申請,下面會詳細說下如何配置。

目標

咱們的目標是實現一個簡單的小程序,可以實現先後端對接。web

從http到https

  1. 首先擁有一個已備案域名,並已經解析到你的服務器上了。
  2. 若是你在阿里/騰訊雲租用了服務器,能夠申請免費的SSL證書。找到相應入口並申請就能夠了。審覈通常很快,個人在一小時之內。
  3. 審覈經過後下載頒發的證書,先保存在本地。以後經過ftp傳到服務器的相應路徑。
  4. 在服務器上安裝Nginx
  5. 首先測試你的Nginx服務是否能正常運行,配置完打開本身的域名能顯示nginx的歡迎頁時即爲成功配置。
  6. 而後將你的證書經過ftp上傳到服務器的任意路徑下(建議和Nginx在同一路徑下)
  7. 打開Nginx的配置文件,如圖配置(證書路徑填寫本身的)
  8. 重啓服務,瀏覽器經過https訪問,能正常顯示頁面即爲配置成功。
    image

前端

如今,打開你的小程序開發工具,並使用你的APPID新建一個項目。(我這裏沒有多餘的APPID,因此先使用測試環境) sql

能夠先勾選「創建普通快速啓動模板」來生成一個官方測試demo,以下圖: 數據庫

讓咱們來觀察一下目錄結構。app.js,app.json,app.wxss分別對應全局的方法,全局配置參數和全局樣式。而在具體包下的index.js,index.wxml,index.wxss則對應相應的元素。json

如今讓咱們來寫一點簡單的頁面的代碼。

<!-- index.wxml -->
<view class="main-card">
 <view class="main-card-item" id="toast" wx:if="{{news_flag}}">
    <view class="card-item-hd" >
      <image class="card-item-icon" src="/images/index/toast.png"></image>
      <text class="card-item-name">大事兒</text>
    </view>
    <view class='toast'>
     Hello,歡迎觀看此教程,但願對你有幫助。
    </view>
  </view>
</view>
複製代碼
/* index.wxss */

page {
  background-color: #f8f8f8;
}

.main-card {
  padding-bottom: 100rpx;
}
.main-card-item{
  display: flex;
  flex-direction: column;
  background: #fff;
  border-top: 1rpx solid #F6F6EF;
  border-bottom: 1rpx solid #F6F6EF;
  margin-bottom: 20rpx;
  background-repeat: no-repeat;
  background-size: 100% auto;
  background-position: bottom center;
  overflow: hidden;
  margin-left: 12rpx;
  margin-right: 12rpx;
   border-radius: 15rpx;
}

.card-item-hd{
  display: flex;
  align-items: center;
  height: 75rpx;
  border-bottom: 1rpx solid #e5e5e5;
  margin-left: 30rpx;
}
.card-item-icon{
  width: 40rpx;
  height: 40rpx;
  margin-right: 10rpx;
}
.card-item-name{
  letter-spacing: 1px;
  font-size: 25rpx;
}
.toast{
  
  letter-spacing:3rpx;
  line-height: 50rpx;
  font-size: 28rpx;
  margin-left: 20rpx;
  margin-top: 20rpx;
  margin-bottom: 40rpx; 
  
}
複製代碼

此時,一個簡單的頁面已經生成了,讓咱們來看看效果。

很簡單,可是能夠看出來「大事兒」裏的內容是寫死的,此時咱們須要後端來提供數據。

###服務器環境

在編寫後端以前,咱們先把服務器的環境部署一下。

安裝:

  1. 安裝了Python環境 apt-get install python-dev
  2. 安裝Flask pip install flask
  3. 安裝UWSGI pip install uwsgi
  4. 安裝了Nginx apt-get install nginx
  5. 安裝了Gunicorn pip install gunicorn

準備

首先在你的/var/www/目錄下建立一個測試目錄,好比/var/www# mkdir test

而後使用chmod更改此目錄的權限chmod 777 /var/www/test

這裏講一下chmod規則,由於這裏是測試用例,因此爲了方便,直接使用777。

Nginx

Ubuntu下的Nginx的目錄結構大體以下:

  1. 全部的配置文件都在/etc/nginx下,每一個虛擬主機已經安排在了/etc/nginx/sites-available目錄下
  2. 啓動程序文件在/usr/sbin/nginx
  3. 日誌文件放在了/var/log/nginx中,分別是access.logerror.log
  4. /etc/init.d/下建立了啓動腳本nginx
  5. 默認的虛擬主機的目錄設置在了/usr/share/nginx/www

啓動服務:/etc/init.d/nginx start,重啓服務:/etc/init.d/nginx restart

如今,咱們須要進入到Nginx的配置中,改動配置文件。vim /etc/nginx/site-avalidable/default

更改配置文件後重啓服務/etc/init.d/nginx restart,或者service nginx restart

Gunicorn

Gunicorn 綠色獨角獸 是一個Python WSGI UNIX的HTTP服務器。這是一個pre-fork worker的模型,從Ruby的獨角獸(Unicorn )項目移植。該Gunicorn服務器大體與各類Web框架兼容,只需很是簡單的執行,輕量級的資源消耗,以及至關迅速。

此時須要在「準備」步驟中建立的測試目錄下放入咱們的測試運行項目,我選擇的FTP工具是:xftp。我傳入了一個簡單的用來測試的Python文件wsgi.py,使用命令/var/www/myflask# vim wsgi.py預覽。

wsgi.py

此時在測試目錄下鍵入命令gunicorn -w 4 -b 127.0.0.1:8000 wsgi:app運行。

開始運行

此時,訪問服務器,能夠看到「Hello World」已經能夠正常顯示了。

hello world

關於Flask

後端咱們採用PythonFlask框架+Gunicorn+Nginx來快速搭建。首先須要一些Python的基礎知識,相信你們在菜鳥學Python學了這麼久,這徹底不是問題。如今,讓咱們瞭解一下Flask如何使用。

一位使用多種語言開發複雜程序而且擁有十多年經驗的軟件工程師,曾經用 PHP, Ruby, Smalltalk 甚至 C++ 寫過 web 應用,他認爲,在全部這些中,Python/Flask 組合是最爲自由的一種。

在使用了Flask以後,我也不得不認可,它確實很便捷快速。固然也會有必定的缺點,這是後話。

迴歸正題。

得到對象

from flask import Flask

app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello World'

if __name__ == '__main__':
    app.run() 
複製代碼

這是一個最簡單的Demo。

執行流程爲:從flask模塊獲取對象app,經過路由,執行方法,返回內容。

此時在瀏覽器訪問(默認端口5000):127.0.0.1:5000/ ,能夠看到國際慣例Helloworld的界面。

hello world

路由

  • 惟一URL:
@app.route('/hello')
@app.route('/hello/')
#這兩種須要區分
#
@app.route('/hello/')
#在使用這種尾部帶斜線的url時,假如用戶沒有輸入尾部/,也將訪問到正確的頁面
#
@app.route('/hello')
#在使用這種尾部不帶斜線的url時,假如用戶在尾部輸入了/,將返回404
複製代碼

這個規則彷佛有點拗口,但其實也不能理解。優勢是:

  1. 使得用戶在遺忘尾斜線時,容許關聯的 URL 接任工做,與 Apache 和其它的服務器的行爲並沒有二異
  2. 保證了 URL 的惟一,有助於避免搜索引擎索引同一個頁面兩次。

若是實在記不清,最好的方法是破罐子破摔:統一不帶尾部「/」

  • 構造URL中的動態部分
@app.route('/var/<name>')
def var(name):
    return 'hello'+' '+name
複製代碼

這點就不贅述了,能夠看一下演示效果:

hello ji

模板渲染

大部分時候,在用戶訪問了一個URL的時候,咱們都須要給他/她返回一個界面,咱們固然不會用Python自己去渲染HTML,爲此,Flask 配備了Jinja2 模板引擎。

看完如下代碼示例,相信你就能理解。

首先,咱們建立「templates」文件夾用於保存模板。

Flask 會在 templates 文件夾裏尋找模板。因此,若是你的應用是個模塊,這個文件夾應該與模塊同級;若是它是一個包,那麼這個文件夾做爲包的子目錄:

#狀況 1: 模塊:
/application.py
/templates
    /hello.html

#狀況 2: 包:
/application
    /__init__.py
    /templates
        /hello.html
複製代碼
  1. 不含參數示例 在程序執行:
@app.route('/redi/')
def redi():
    return render_template('hello.html')
複製代碼

hello.html:
hello

  1. 再看另外一個例子,加入動態參數:
@app.route('/redi2/<name>')
def redi2(name):
    return render_template('hello2.html',name=name)
複製代碼

hello2.html

hello ji

GET和POST

請求方式不止這個兩種,可是最經常使用的是這兩種,若是對這兩種不熟悉,能夠先去查一下HTTP方法的資料,這裏只演示在flask中的用法。

@app.route('/met',methods=['GET','POST'])
def met():
    if request.method=='GET':
        return '這是get方法'
    if request.method=='POST':
        return '這是post方法'
複製代碼

打開Postman這款軟件(Web神器),模擬發送HTTP請求。

get

post

請求對象

下面我來模擬一個簡單的登陸操做。

首先是控制器:

@app.route('/login',methods=['POST','GET'])
def login():
    error=None
    if request.method=='POST':
        print (request.form['username']+' '+request.form['password'])
        if func.login_func.valid_login(request.form['username'],
                    request.form['password']):
            return func.login_func.login_success(request.form['username'])
        else:
            error='Invalid username/password'
            return render_template('login_error.html',error=error)
複製代碼

能夠看到執行流程:

  1. 得到請求
  2. 判斷請求類型
  3. 得到登錄數據
  4. valid_login()方法驗證登錄 4.1 若登錄成功,執行login_success()方法 4.2 若登陸失敗,添加失敗信息,返回失敗模板

下面是上述用到的兩個方法:

def valid_login(username,password):
    if username=='admin' and password=='admin':
        return True
複製代碼
def login_success(username):
    return render_template('login_success.html',username=username)
複製代碼

下面使用Postman來模擬請求,看看能不能返回設想的結果。

success

failure

這是一些簡單的Flask操做,好了,咱們如今對web有了必定的瞭解了。如今開始編寫咱們的代碼。

###後端 萬事俱備,只欠東風。 首先咱們來寫兩個路由,一個用於更新通知,一個用於獲取通知。

@app.route("/updateToast",methods=['POST'])
@allow_cross_domain
def update_toast():
    data=db_util.update_toast(request.form['toastUpdateInfo'])
    return jsonify(data)

@app.route("/getToast",methods=['GET'])
@allow_cross_domain
def get_toast():
    data = db_util.get_toast_info()
    return jsonify(data)

複製代碼

而後寫一個工具類,用於直接操做數據庫(這種設計並不規範,只是爲了快速演示)

#db_util.py
def get_toast_info():
    db = pymysql.Connect(
        host='xxx',
        port=3306,
        user='xxx',
        passwd='xxx',
        db='xxx',
        charset='utf8'
    )
    cursor = db.cursor()
    sql = "select content from guohe_lite_toast order by id desc limit 1 "
    try:
        cursor.execute(sql)
        result = cursor.fetchone()
        return response_info.success('小程序通知查詢成功', result)
    except:
        return response_info.error('2', '小程序通知查詢失敗', result)
        # 關閉數據庫鏈接
    finally:
        db.close()
def update_toast(toast_update_info):
    db = pymysql.Connect(
        host='xxx',
        port=3306,
        user='xxxx',
        passwd='xxx',
        db='xxxx',
        charset='utf8'
    )
    cursor = db.cursor()
    sql = "insert into guohe_lite_toast(content,update_time) values(%s,%s) "
    try:
        dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        cursor.execute(sql,(toast_update_info,dt))
        db.commit()
        return response_info.success('通知更新成功', toast_update_info)
    except:
        db.rollback()
        return response_info.error("2",'更新失敗', toast_update_info)
    finally:
        db.close()
複製代碼

如今,讓咱們使用postman來測試一下接口。

首先更新一下通知:

而後看能不能成功獲取:

這一切都生效了,數據接口已經準備就緒。

數據渲染

那麼,如今如何在小程序端獲取數據並顯示呢?咱們去簡要讀下小程序的官方文檔

請注意,小程序是純異步方式來發送請求的。

依葫蘆畫瓢,咱們來模仿一下:

#index.js
wx.request({

      url: 'https://example.com/getToast',
      method: 'GET',
      header: {
        'content-type': 'application/x-www-form-urlencoded' // 默認值
      },
      success: function (res) {
        var message = res.data.info[0]
        console.log(message)
        that.setData({
          toast: message
        })
      }

    })
複製代碼

咱們將獲取的數據已經保存在"toast"這個變量中了,再去讀文檔,看看小程序是如何進行數據綁定的。而後咱們將以前寫死的文本換成"{{toast}}",這時再刷新,能夠看到,數據已經顯示了。

<!-- index.wxml -->
<view class="main-card">
 <view class="main-card-item" id="toast" wx:if="{{news_flag}}">
    <view class="card-item-hd" >
      <image class="card-item-icon" src="/images/index/toast.png"></image>
      <text class="card-item-name">大事兒</text>
    </view>
    <view class='toast'>
    {{toast}}
    </view>
  </view>
</view>
複製代碼

此時,一套完整的流程已經結束,雖然實現了一個微小的功能,但麻雀雖小,五臟俱全。接下來,就是去進一步學習,去如何改造以及豐富咱們的項目了。

好比稍微努力一下:

掃一掃,關注公衆號
相關文章
相關標籤/搜索