1. 程式人生 > >微信小程式專案總結-記賬小程式(包括後端)

微信小程式專案總結-記賬小程式(包括後端)

一、小程式部分

這是理財系統的前端,江蘇海洋大學微信小程式比賽,最後獲得了一等獎
GitHub:https://github.com/GeorgeLeoo/finance

1. 專案描述

(1). 此專案為記賬小程式
(2). 包括賬單、圖表、搜尋、使用者等多個子模組
(3). 使用微信小程式技術 
(4). 採用模組化、元件化、工程化等模式開發

2. 專案功能介面

在 1.0.2版本中刪除了扇形圖

3. 專案目錄

    * pages:頁面
    * components:元件
    * utils:工具類  
        |-- util.js:工具類 
        |-- wxcharts.js:圖表外掛
    * images:資源圖片
    * config:配置檔案
    * filter:過濾器
    * http:網路請求
        |-- http.js:對 wx.request 的封裝
        |-- api.js:對網路請求介面的封裝    

4. 請求封裝

一開始使用 wx.request 對資料進行網路請求,可寫完後,發現太過冗餘,也太麻煩,故對其做了封裝。
通過建立一個函式返回 Promise 物件,就可以遮蔽公共的部分

// http/http.js
/**
 * 對微信普通網路請求封裝
 * @param url   請求地址
 * @param data  請求的引數
 * @param method   請求的方法型別 
 * @param headers   頭部資訊,在這裡主要是 token 認證功能
 * @returns {Promise<unknown>} 返回請求的 Promise 物件
 */
function http({url, data, method, headers = {}}) {
    return new Promise((resolve, reject) => {
        wx.request({
            url,
            method,
            data,
            header: {
                Authorization: headers.token,
                expiresIn: headers.expiresIn
            },
            success: (result) => {
                const res = result.data;
                if (res.code === 0) {
                    resolve(res.data);
                } else if (res.code === 1) {
                    reject(res.msg);
                }
                // 隱藏 loading
                wx.hideLoading();
            },
            fail: (err) => {
                console.error('server error', err);
            }
        });
    })
}

/**
 * 對檔案上傳介面封裝
 * @param url   請求地址
 * @param fileOptions   檔案配置項
 * @param data  請求傳送的資料
 * @param headers   頭部資訊,在這裡主要是 token 認證功能
 * @returns {Promise<unknown>}  返回請求的 Promise 物件
 */
function uploadFile({url, fileOptions, data, headers = {}}) {
    return new Promise(((resolve, reject) => {
        wx.uploadFile({
            url: url,
            filePath: fileOptions.filePath,
            name: fileOptions.name || 'file',
            header: {
                Authorization: headers.token,
                expiresIn: headers.expiresIn
            },
            formData: data,
            success: (res) => {
                console.log(res.data);
                if (JSON.parse(res.data).code === 0) {
                    resolve(res.data);
                } else if (res.code === 1) {
                    reject(res.msg);
                }
            },
            fail: (err) => {
                console.error('server error', err);
            }
        })
    }))
}

module.exports = {
    http,
    uploadFile
};

5. 遇到的問題

(1). 在更新賬單資料後,如何更新賬單介面的資料?
        這個問題我的解決方案是,在 globalData 中新增一個全部變數 isRefreshBills,預設為 false,
     當更新賬單資料成功後,將 isRefreshBills 修改為 true,同時返回到賬單介面,在賬單介面的
     onShow()方法中,判斷 isRefreshBills 是否為 true,若為 true 則重新請求資料,同時將 isRefreshBills 
     設為 false,否則不請求。這樣就避免了沒有更新資料的情況下多次請求資料。
        對這個解法,還有一種更加節流的方法,就是更新後不去請求,而是對原來的獲取到的資料進行個別刪除。比如當
     更新資料成功後,獲取一個被更新的這條資料的id,然後在賬單頁面的 onShow() 方法中,遍歷找到這個 id 對應的
     資料,並刪除這條資料也能達到資料更新的效果
     
(2). 在進行類別新增的時候,自定義的類別會出現雙倍?
        由於我有一分部初始資料是存在 globalData 中的,每次從伺服器獲取自定義類別時,都會對其進行拼接,
     在拼接的時候修改了原來的 globalData 中的值,所以每次新增後都會請求一次自定義資料,進行拼接。
     解決方案:禁止更新 globalData 中的資料
     
(3). 返回哪個頁面問題?
        在賬單頁面可以進去修改賬單的頁面,在搜尋頁面也可以進入修改賬單賬單的頁面,他們用的是同一個元件,
     那麼如何保證在賬單頁面進入修改賬單頁面後返回到賬單頁面,在搜尋頁面進入修改賬單頁面後返回到搜尋頁面。
     首先在路由跳轉的時候添加當前路由資訊,然後在修改賬單頁面中接受這個路由資訊,最後通過這個路由資訊返回到原來的路由
     

6. 總結

    這個專案是我5月份參加學校微信小程式的專案,兩個禮拜倉促的做了這麼一個專案,前後端都有,最後榮獲一等獎。
    在之前比賽用的版本中其實有很多的 bug 以及卡頓現象居多,故這兩天我有對這個專案進行了一定的維護,發現原來的程式碼實在
    慘不忍睹,現在經過升級,頁面卡頓現象減少,若後期再想維護,也相對於之前的版本好維護多了,但是還有很多可以維護的空間。
    其實我並不對這個專案很滿意,比如之前我沒做分頁載入, 現在想加個分頁載入的功能,我發現並不是一下子就能搞定的,
    因為我的資料結構不是很合理,因為後端返回的資料和前端要顯示的資料格式是不一致,故前端要重新定義資料結構,
    所以對分頁來說就有一定的困難。在我對專案進行維護後,程式碼比以前更簡潔,可讀性相對於之前的版本來說要更加好。

二、伺服器部分

1.簡述

這個專案是微信小程式記賬 app 的後端程式碼,使用技術:MongoDB+Express。
GitHub:https://github.com/GeorgeLeoo/finance-server

這個專案的目錄是這樣的

  • config: 配置檔案
  • routes: 路由配置
  • utils: 工具類
  • db: 操作資料庫的程式碼
  • controller: 控制是當前地址否要 token 驗證
  • service: 如何呼叫操作資料庫函式(我也不知道為什麼要寫controller,service,感覺這兩個寫一個就可以了)

2.遇到的問題

(1). token 驗證問題?

關於 token 驗證問題我使用了 jsonwebtoken 外掛,故先用 npm 安裝這個外掛。
token 驗證流程大概如下圖:

使用這個外掛: 定義兩個方法,一個用來生成 token,另一個用來驗證 token。


 /**
  * 生成token
  * @param {object} content  對某個內容生成 token
  */
 const access_token=function (content) {
     let secret = 'jizhangxitongfinancegeorgeleeo';  // 祕鑰
     let expiresIn = Math.round((new Date().getTime()/1000)) + 3600; // 過期時間
     let token = jwt.sign(content, secret, { expiresIn });
     return {
         token,
         expiresIn
     };
 }
 /**
  * 驗證token
  * @param {string} token token值
  */
 const check_token= function (token) {
     let secret = 'jizhangxitongfinancegeorgeleeo';  // 祕鑰,根生成的 token 要一致
     return new Promise((resolve, reject) => {
         jwt.verify(token, secret, (err, decode) => {
             if (err) {
                 //時間失效或偽造 token 或 token 不存在
                 reject({
                     status: 10010,
                     error: 'invalid_token'
                 });
             } else {
                 resolve();
             }
         });
     })
 }

在controller.js 中,去判斷 token 驗證成功與否

function billController(method, options, req, res) {
    // 驗證 token
    utils.check_token(req.headers.authorization, res).then(() => {
        // token驗證成功,呼叫操作資料庫的方法
        billService[method](options).then((data) => {
            res.json(data);
        }).catch((err) => {
            res.json(err)
        });
    }).catch((err) => {
        // token 驗證失敗
        res.json(err)
    })
}

(2). 檔案上傳問題?

在這個專案中,有使用檔案上傳的功能,express 預設是帶這個功能的,所以就必須使用 npm
安裝 express-fileupload 這個外掛,然後再 app.js 中引入並註冊這個外掛

var fileUpload = require('express-fileupload');
app.use(fileUpload());

當前端傳送檔案時,後端從 req.files['name']獲取 file 物件,然後通過 file.mv()方法進行檔案儲存

    file.mv(fileSavePath, function (e) {
        if (e) {
            // 失敗時
        } else {
            // 成功時
        }
    });

比如我的專案中,上傳圖片程式碼抽取出來就是

    // 小程式程式碼
        wx.uploadFile({
            url: 'http://localhost:3000/users/avatar',
            filePath: 'XXXXXXX',
            name: 'avatar',
            header: {
                Authorization: headers.token,
                expiresIn: headers.expiresIn
            },
            formData: data,
            success: (res) => {},
            fail: (err) => {}
        });

    // 伺服器程式碼
        let file = req.files.avatar
        file.mv('upload/a.png', function (e) {
            if (e) {
                // 失敗時
            } else {
                // 成功時
            }
        });

(3). 關於前端讀取upload中圖片的問題

本來想用伺服器的 ip 來讀取專案中 upload 中的圖片,但是發現並不能讀取,或顯示404,故最後將 upload 檔案放在了專案的外邊,
然後對這個 upload 檔案單獨開了一個服務,把他當做圖片伺服器來使用。

3. 總結

當初選用 Express + MongoDB 的唯一原因就是開發快,因為基本上每天都滿課,所以快速開發是我的需要。
在這個專案中其實還有很多可以優化的地方,還有一定的冗餘,比如在操作資料的時候,所有的查詢成功或失敗的函式
都可以存放到一個公共類裡面,而不是每一對應的檔案裡都有一個這個方法。

Github:
小程式:https://github.com/GeorgeLeoo/finance
伺服器:https://github.com/GeorgeLeoo/finance-ser