全端網頁開發:老爸的私房錢專案

Node.js記帳本網頁應用

Hazel
Jun 6, 2021
專案登入後首頁示意圖

專案已使用Heroku上架展示:老爸的私房錢

專案程式碼請見:GitHub

記帳應用程式會需要建立最基本的CRUD功能,並且會運用到數字運算及日期時間的處理,很適合新手工程師展現最基本的程式能力。

技術運用:

在老爸的私房錢記帳網頁應用程式中,從前端、後端及資料庫使用了許多工具。

  1. 專案使用JavaScript撰寫,運用Node.js架設伺服器,同時讓JS語言能被電腦讀懂,使JS能在後端進行操作。
  2. 網頁框架選用搭配Node.js最為流行的Express.js框架。並使用handlebars作為處理網頁頁面的樣板引擎。Handlebars雖然算是較舊的工具,但因為語法撰寫上與HTML5相似,對於新手來說,學習上較易上手及運用。
  3. 為了快速排版及美化前端網頁呈現,套用了前端開發經常使用的Bootstrap 5,同時也載入fontawesome適當使用icon提升視覺體驗。切板主要採用Grid網格系統搭配flex,並使用部分position: fix。Bootstrap 5也幫助了RWD(響應式網頁設計)的快速建立。不足部分,另外匯入CSS檔案做調整。
  4. 在後端資料庫部分,使用非關聯式文件資料庫MongoDB,為使用者頗多且開源討論及整體生態系發展完善的非關聯式資料管理系統。搭配使用提供給Node.js環境使用的ODM Mongoose,讓操作資料庫更為輕鬆,不需再花大筆時間研究資料庫本身的語言。
  5. 最後使用Heroku的雲端服務及MongoDB Atlas提供的遠端資料庫,實現專案網頁上架。

在註冊、登入及表單驗證的部分:

  1. 註冊時,使用bcrypt對密碼進行加鹽雜湊,使密碼難以透過彩虹表窮舉破解,以保護使用者資料的安全。
  2. 因為HTTP的無狀態機制,瀏覽器不會記得是誰登入,所以需要為登入的使用者帶上認證狀態,才能辨識是誰成功登入、是誰沒註冊的人。本專案使用express-session儲存認證狀態。
  3. 運用passport.js進行使用者認證,通過session認證狀態判斷是否為同一位使用者及驗證帳號密碼是否一致,控制是否可以登入成功。並在登入成功時,提供一個已認證訊號,幫助控制登入者才能看到的畫面呈現。
  4. 使用passport-facebook的facebook認證策略,實現可以經由已註冊的facebook帳戶進行使用者註冊登入。
  5. 表單驗證除HTML input type 及 required外,後端使用passport及express-validator對傳進來的資料進行驗證,符合要求才會存進資料庫。
  6. 使用connect-flash在資料驗證失敗、註冊登入登出成功時,能顯示對應的提示訊息,幫助使用者體驗。

在日期呈現部分,使用moment.js協助時間日期格式的轉換。

https://momentjs.com/

花費較多時間研究的困難點:

如何進行資料庫內資料的日期時間篩選?

老爸的私房錢最一開始是以字串形式儲存日期資料,然後取出資料對字串進行切分編輯後,直接比對字串,算是對學了JavaScript一段時間的人來說,不需要太多思考就能上手達成目標的一個方式。

然而,在工作坊時,助教有提到當資料越來越多時,進行字串比對,就明顯地較耗系統效能,是比較沒效率的方法。於是,就來嘗試將日期以 type: Date,而不是 type: String 的形式存進資料庫看看。原先的程式碼就會產生2個問題:

  1. 從資料庫取出日期資料後,它是以ISO date的格式存在,如何將它轉換成我想要的呈現格式,再丟到handlebars渲染出來?
  2. MongoDB資料庫是如何搜索指定的日期時間資料的?

第1個問題:剛好在工作坊後,有同學在slack貼了自己從string轉date後怎麼處理的分享,後續有同學提到使用moment.js處理日期時間格式,於是就直接收下moment.js來研究如何使用了!

花了一些時間看了moment.js的document,目前的解法是直接把回來的date資料丟進moment裡,讓它變成moment時間物件,就能接續使用moment.js提供的相關語法來格式自己想要的呈現方式了!

建立一個handlebars helper function轉換日期格式

至於第2個問題,其實做法蠻多的,但較為直觀搜尋某期間資料的方式是運用find()跟$gte和$lt,$gte用於搜尋給予的時間點之後的時間,而反之$lt用於搜尋給予的時間點之前的時間,同時使用就能搜尋指定期間的資料。我在快速搜尋「今天」、「昨天」、「這個月」、「上個月」記帳資料的快捷按鈕部分使用了這個方式!

如何同時根據「類別」、「年份」、「月份」篩選符合的資料?

然而,上述搜尋指定期間的方式,若是還要同時篩選「類別」或將「年」、「月」分開指定就會變得很不好用。那要如何對資料庫內的資料進行多重條件的操作或搜索?查詢到的語法是使用aggregation(),被稱為聚合的方式。

目前是使用if else條件式,區分3個條件的排列組合,搭配async/await,等待資料庫帶入aggregation()後,搜尋到符合條件的資料!不過,目前aggregation()給的條件有點多,覺得還能在思考是否有更好的解決方式!

繼續進修的面向

覺得現在因為要全面地完成一項全端開發作品,所以一口氣接觸了許多工具,但是每項工具都只懂它目前在作品裡有用到的部分,而沒有在深入一些研究每項工具還能怎麼用,於是就因為不知道工具可以做到,而想不到更好搭配的解法。

目前覺得可以更加去熟悉,express-validator怎麼去設每一個驗證條件,讓後端驗證更加完善。在時間處理部分,其實也還不是很熟練,對於moment.js是怎麼做到的及還能做什麼,懂全面一點,對之後寫程式也會很有幫助。特別是在時差部分該如何處理這點,是存在目前專案裡的小bug,也還有待研究如何解決!

感覺就是補不完的知識坑,不過第一次完成較為完整的全端作品,真的有升了很多級的感覺,繼續努力讓coding和運算思維就是自己生活的一部分!

專案成品快速展示

專案gif demo

--

--

Hazel

Web & Software Developer 🇹🇼 Taiwanese Explorer @MyLifeAdventure ICS Student @CamosunCollege