《後現代全棧系統的設計與應用》


從當年的畢業論文(2019/5/13)中找點靈感。。。






目 錄


1 緒論 1

1.1 選題目的 1

1.2 研究內容 1

2 系統需求分析 1

2.1 功能性分析 1

2.2 非功能性需求 2

3 開發環境以及相關技術 3

3.1 前端框架 3

3.2 後端框架 4

3.3 全棧設計模式 4

3.4 開發環境和工具 5

3.4.1 vscode 5

3.4.2 chrome 5

3.4.3 mongodb compass 5

3.4.4 github desktop 5

4 系統設計 6

4.1業務邏輯與界面 7

4.1.1 GUI設計 7

4.1.2 用戶權限劃分 7

4.1.3 MVC設計 8

4.1.4 編輯器功能 8

4.1.5 數據庫功能 8

4.2 統計 11

4.2.1 表格變形 11

4.2.2 雷達圖 12

4.2.3 Excel導出 12

4.2 編輯與設置 12

4.2.1 對象增刪改查 12

4.2.2 賬戶設置 14

4.2.3 登錄登出 14

4.4 管理員 15

4.4.1 日誌訪問 15

4.4.2 遠程調試 15

4.4.3 用戶註冊 15

5 系統實現 15

5.1 前端 16

5.1.1 表格交互模塊 16

5.1.2 schema封裝模塊 17

5.1.3 異步封裝模塊 18

5.1.4 前端自動化腳本 18

5.1.5 渲染循環模塊 19

5.1.6 UI佈局模塊 19

5.1.7 表格變形配置模塊 20

5.1.8 雷達圖模塊 21

5.2 後端 22

5.2.1 目錄設計模塊 22

5.2.2 入口設計模塊 24

5.2.3 增刪改查模塊 25

5.2.4 頁面跳轉模塊 25

5.2.5 遠程調試模塊 26

5.2.6 數據庫備份模塊 28

5.2.7 數據過濾模塊 28

5.2.8 會話控制模塊 28

5.2.9 日誌模塊 29

5.3 數據庫 29

5.3.1 索引模塊 29

5.3.2 模型層模塊 29

5.3.3 數據驗證模塊 30

6 測試 30

6.1 功能性測試(用戶數據驗證) 30

6.2 安全性測試 31

6.2.1 請求未知資源(404) 31

6.2.2 權限測試 32

7 總結與展望 32

參考文獻 33

致謝 34








基於web的項目資源分配系統


 


摘要:本系統旨在設計一款基於MVC的web系統,以產品經理和項目經理爲目標用戶,針對EXCEL表格統計軟件的不足,提出一套輕量級、易操作的解決方案,搭建了一個存儲在雲端的項目資源管理網站。系統圍繞企業中人與項目這兩個資源該如何搭配這個主題,提供了項目資源的編輯與統計服務等定製的項目管理功能,能夠讓管理人員在網頁上管理員工與項目之間的工時安排,編輯、統計每個項目對每個部門的資源需求以及每個部門給每個項目提供的人力資源數等具體功能。本系統以material design爲UI主題,以SPA應用程序爲設計模式,以函數式編程爲代碼風格,實現一個高可用,易擴展的網站。

關鍵詞:Web;Material Design;MVC;項目管理資源分配








1緒論

1.1 選題目的

目前,很多中小型企業有着“上雲”的趨勢,很多公司將內部的內容管理系統的建設任務外包給軟件公司,本次設計的目標是以產品經理和項目經理爲目標用戶,搭建一個存儲在雲端的項目資源管理網站,提供高效的項目資源分配分析服務。Windows上提供的管理軟件比如office,Outlook都不夠靈活,無法滿足日益增長的需求,尤其是Excel統計工具在某些場景下異常臃腫,本系統主要就是針對表格統計軟件的不足,提出一套輕量級,易操作的解決方案。

本次選題的意義在於實現雲端系統給企業管理帶來批量增刪改查的功能,並且開放源碼推廣給其他用戶,同時還要保證系統在保持高可擴展的同時是否能做到高內聚低耦合。

1.2 研究內容

目前很多企業管理者感受到Windows上提供的管理軟件比如office,Outlook都有不夠靈活,無法多人同時編輯的缺陷,無法滿足日益增長的需求,尤其是傳統的Excel統計工具更是異常臃腫,本系統主要就是針對表格統計軟件的不足,提出一套自己的解決方案,能夠輕鬆的擴充功能並且向下兼容[1]

以產品經理和項目經理爲目標用戶,設計開發一款項目資源管理網站。要求給出合理的需求分析、詳盡的總體設計方案以及詳細設計說明,編程實現基於web的項目資源分配系統,具有云端數據存儲、在線編輯資源、監控項目資源、數據統計分析及圖表繪製等功能,軟件最終要完成測試。

2系統需求分析

本系統以產品經理和項目經理爲目標用戶,設計開發一款項目資源管理網站。要求給出合理的需求分析、詳盡的總體設計方案以及詳細設計說明,編程實現基於web的項目資源分配系統,具有云端數據存儲、在線編輯資源、監控項目資源、數據統計分析及圖表繪製等功能,軟件最終要完成測試。要求系統界面美觀大方,操作模式友好,用戶體驗優良。

2.1 功能性分析

如今,所有的桌面軟件都有一種“上瀏覽器端”的趨勢,比如許多開發工具IDE現在都出現了相應的ODE(online IDE),很多繪圖製表的工具也從傳統的app變成在線使用的工具,當然還有各種web管理系統,都上web了。在這個趨勢的背後,Web平臺的發展起到了至關重要的作用:web平臺由瀏覽器和HTTP(s)組成,在20多年的發展過程中衍生出了許多分支,其中nodejs和webassembly是2個里程碑式的技術。其中nodejs將web技術拓展到了服務器端,webassembly則讓所有客戶端的app上web成爲可能。

本次的項目管理系統需要的功能主要是方便項目經理或部門經理規劃公司某地區內所有的項目和人力資源,以及如何將人力資源(以時間爲單位)合理的分配到不同的項目上。基礎功能之上還有一些進階的功能需求如統計的功能,包括排序、過濾、索引、製圖,還有UI上的“隱含“要求比如動畫、遮罩層、彈窗、字體。除此之外,網站還要解決excel“無法多人同時編輯”的缺陷,即要求可以多人同時登錄,同時修改數據庫。

從用戶的角度,可以畫出一個用戶需求圖:

2.1 用戶需求圖

圖2.1中,用戶希望能夠直觀,方便的編輯項目對部門的需求,以及部門對項目的實際分配,最好是在熟悉的表格中進行操作,然後需要能生成一個統計圖,最後可以將這個表格備份到本機。

2.2 非功能性需求

web平臺能做的事情越來越多,也越來越強大,本系統的關鍵來自於,如何合理的利用web平臺,將傳統企業基於Excel的管理模式搬移至web上面,滿足用戶對性能的需求。

衆所周知,許多傳統制造業,尤其是外企的工作站一直採用微軟公司的“全套服務”,即Windows企業版,Outlook郵件,Skype for business通訊工具,Office辦公四件套,甚至IE瀏覽器。

從用戶的角度,很多企業管理者感受到Windows上提供的管理軟件比如office,Outlook都有不夠靈活,無法多人同時編輯的缺陷,無法滿足日益增長的需求,尤其是傳統的Excel統計工具更是異常臃腫

讓用戶瀏覽網頁理論上要比使用傳統的excel快,因爲以前通常是打開一個體積龐大的excel文件,一次讀取所有的數據,但網站則是讀取自己需要的一部分數據,網絡帶寬和前端渲染上都會好很多。因爲是通過網絡傳輸數據,用戶還要求保證數據安全性,保證傳輸中數據的加密和認證。

除此之外,還要求系統頁面美觀,交互性強。

3 開發環境以及相關技術

系統前端基於現代瀏覽器,以Chrome60+爲準,後端是nodejs服務器,開發語言都是JavaScript,數據庫使用超越關係型的mongodb。

3.1 前端框架

首先考慮到整個UI風格,系統更傾向於使用目前比較流行的material design風格,所以UI框架採用Google的MDC(material design component)。MDC是一個輕量級的UI框架,提供了用戶友好的圖標,動畫,尤其是動畫可以帶來很好的操作暗示[3],如圖3.1所示。

3.1 material design提供的各種UI元素

除此之外還需要一個表格驅動引擎Ag-grid,這是一個重量級的網格插件,可以在表格的基礎上提供豐富的操作,表格的主題也支持material,如圖3.2所示。Ag-grid並不是由社區維護,而是一家公司,版本更新的力度很足,issue反饋率也非常高,所以Ag-gird非常可靠。

爲了方便用戶更好的編輯數據,尤其是具體的json對象比如人的姓名部門等屬性,本系統引入了一個json-editor插件來渲染編輯器,並將他製作成一個異步模塊以方便調用。

最後,爲了能夠生成統計圖,使用Chart.js來渲染雷達圖或者柱狀圖。

3.2 ag-grid的material主題的大致風格

3.2 後端框架

Web容器採用最流行的express。express是一個非常精簡但是強大的web容器,在node的異步光環下完美實現了路由,session,中間件,靜態文件,模板引擎等核心功能,同時安全性也做得非常好。express還是nodejs基金會的成員,某種意義上,express可以和node標準庫相提並論

數據庫採用了和nodejs搭配極佳的mongodb,後者支持易擴展的數據結構[4],後者是一個存儲類json對象的一種超越關係型的數據庫,但和SQL類似,mongo也支持關係代數和集合論,也擁有索引和過濾器,創新的地方在於它可以儲存嵌套的數據結構,爲此還專門設計了一個叫做BSON的二進制協議格式,用於底層的存儲和傳輸。Mongodb非常適合數據結構複雜的企業級管理系統,也就是本系統。

此外還用到了一些小插件,比如用於打包備份的壓縮模塊archiver,用於給密碼進行sha1加密的crypto模塊,以及標準庫的https模塊(提供ssl認證服務[5])。

3.3 全棧設計模式

前端並沒有使用經典的mvvm框架,同時ag-grid提供的狀態欄和context菜單內置了數據綁定的功能,所以前端間接性的使用了MVVM設計模式。

後端仍然是經典的MVC設計模式,結合express嚴格分離了數據層,業務邏輯層以及顯示層[6]

中間http的設計,選擇業界最流行的restful api[2]設計模式。Rest嚴格意義上並不是設計模式,而是一個http的使用教程,旨在讓開發者更好的使用http。

3.4 開發環境和工具

3.3 開發者工具

3.4.1 vscode

Vscode是微軟公司基於electron製作的IDE(集成開發環境),特點是輕量級但功能強大,插件系統非常豐富,同時還支持git,debug等有用的功能。本系統所有的前後端代碼都在vscode上完成。

3.4.2 chrome

調試前端代碼基本上在Chrome內置的devtool(開發者工具)中進行。前端開發者都知道,devtool是開發高性能頁面的必備,它內置了html元素查看器,調試終端,資源管理器,網絡工具,性能監視器,以及一堆開發者常用的工具。甚至Chrome還可以調試node程序[7],但本次只用它來測試前端的代碼。

3.4.3 mongodb compass

Compass是mongodb官方推出的一款可視化客戶端,界面友好,反應快捷,也是基於electron製作而成。Compass不僅可以作爲開發工具,還可以作爲項目上線後網站管理員的數據庫管理工具。

3.4.4 github desktop

Github desktop是GitHub的可視化客戶端工具,工具集成了所有的git命令和GitHub專有的功能,在本項目的開發過程中,它起到了本機與雲端同步代碼,保存歷史版本記錄的功能。

4 系統設計

根據之前的需求分析,本系統的基本功能是讓用戶(項目經理)維護每一個項目對不同部門的需求量,這裏的需求量主要指的是人頭數或者更準確的說是時間數,還有一個是與之相對應的數值:實際花費值,即部門內每個人每季度在項目X上貢獻的時間(單位天)的總和。

前者的需求量通常由項目經理來填寫,後者實際值部門經理來維護每個人所花費的時間,即資源數,最後將項目對部門資源的需求量和實際值進行對比,並繪製成雷達圖的形式觀察是否滿足需求。

根據用戶需求圖2.1,制定一個詳細的系統功能圖,其中將用戶需要的主要功能分類爲“編輯與設置”與“統計”,“管理員”屬於管理員用戶需要的功能,“業務邏輯與界面”屬於系統層面的一些功能。

圖4.1 系統功能圖

圖4.1中,“統計”的目的旨在幫助用戶更好的分析數據,利用表格和圖表這2種表達方式合理的表現用戶所需要的“資源數據”,“編輯”則從增刪改的角度幫助用戶更好的對業務邏輯上的數據進行操作,原則是儘可能的滿足大衆用戶操作表格的習慣,“其他”則包含了其他一些很重要但用戶默認的功能,比如登錄註冊登出機制,還有方便管理員維護的功能包括查看日誌,遠程調試。

4.1業務邏輯與界面

4.1.1 GUI設計

雖然傳統的管理系統有一套標準的UI模板來構建整個頁面,基本是灰白藍主題,框架式的頁面佈局,但是本次系統希望引入material design的元素,讓界面更美觀,動畫效果更明顯,色彩更鮮明,給企業用戶帶來煥然一新的感覺,所以本系統設計UI上要額外花費一些精力,考慮添加一些遮罩層,動畫,摺疊與收縮等UI元素。

首先利用MDC框架搭起一個大的框架,包括標題欄,側邊欄,主體,然後在主體中嵌入aggrid框架提供的表格,表格在主體中可以自由滾動,變形,除此之外還需要一些懸浮在頁面最上方的元素包括彈窗,提示框,對話框。

GUI設計需要使用到的模塊包括schema封裝模塊,渲染循環模塊,UI佈局模塊。

4.1.2 用戶權限劃分

考慮到許多應用場景,本系統劃分了4種級別用戶(正常情況下只使用其中2種),分別是:inactive user,common user,super user,root user,如表4.1所示。


4.1  4種用戶權限說明

權限等級

權限名稱

權限範圍

標識符

說明

4

Root

全部

_root

管理員用戶,擁有所有權限

3

Super

所有地區(全公司)

無_common

Boss/總監級別(大部分用戶)

2

Common

本地區

_common

小的部門領導

1

Inactive

自身

無_pwd

普通員工

表中root user指的是管理員用戶,也就是網站的運維人員,在接手開發者的使用文檔後,擁有遠程debug,數據庫備份,添加/刪除部門和項目分類等權限。Super user則是大多數部門經理/產品經理的權限,可以添加/刪除員工和項目,增刪查改員工數據,項目需求等。Common user適用於一些特定的場景,這個場景中一些用戶權限有限,不能查看其他用戶所在的地區的信息,即只能在自己所管轄的範圍內進行增刪查改。Inactive user指的是那些非經理級別的普通員工,也就是出現在表格當中被當做資源分配的員工。

不同用戶通過表中“標識符”一列的數據庫字段來區分。

和用戶權限劃分有關的模塊主要是數據過濾模塊。

4.1.3 MVC設計

MVC是web後端設計的經典模式,MVC分別代表數據模型層,前端表現層,業務邏輯層。這三層在應用上分別對應着數據庫,前端,後端,但都是在後端代碼中連接在一起,這表示,雖然三層分工明確,但一定通過其中的業務邏輯層(controller)將剩下2層聯繫起來。本系統自然也遵循了MVC的原則:將mongodb的連接庫封裝而成的讀寫模塊作爲模型層掛載在全局對象上,將前端靜態文件目錄的檢索接口放在路由器最前端的位置作爲顯示層,將所有的路由模塊以http方法分類放在路由器的核心位置作爲邏輯層。

 

4.2 MVC之間的關係

和MVC設計有關的模塊包括模型層模塊,頁面跳轉模塊。

4.1.4 編輯器功能

本系統的編輯器包括用戶登錄框和更新對象的框,都使用對話框加上json-editor來設計。從用戶打開編輯器開始,到用戶點擊提交按鈕這個過程封裝成一個promise。

和編輯器功能相關的模塊包括異步封裝模塊,UI佈局模塊,表格交互模塊。

4.1.5 數據庫功能

Mongodb是nosql數據庫,nosql不是“非關係型”的意思,而是“不止關係型(not only)”,也就是說mongodb包含關係型[8]的表格結構,在類型上比傳統sql數據庫多了2種,分別是列表和字典(對象),本項目總共建立了4張表(mongo中叫做集合),外加sessions表是由session模塊自動創建的,4個表都是管理員來維護。

4.3:E-R圖(屬性參考下面的表格)

4.33個主要對象中,person和project的關係(工作)就是某人在某項目上花費的時間(spent time),這個關係屬性選擇存放在person集合中以節省空間。膩歪一個關係屬性是demand,代表項目對部門的時間需求,存儲在department集合中。圖中還能看到2個一對多的包含關係(belong)。

1) person集合

表4.2:person集合的結構

序號

字段

類型

說明

索引

驗證

1

_id

String

人名

正則表達式

2

_about

String

備註信息


長度限制

3

_root

Boolean

是否有root權限



4

_common

Boolean

是否是普通用戶



5

_role

String

所屬部門

正則表達式

6

_pwd

String

密碼(sha1加密)



7

_owner

String

該用戶的創建人



8

_capacity

Number

該用戶的“餘額”




[project]

Object

關於某個項目的信息,多個字段




……


同上一個字段




Person集合是存放所有員工,以及領導的集合,用戶的登錄,增刪改查都會對這張表進行讀寫。除了前8個字段外,如果需要建立某個人和某個項目之間的聯繫,即通過實際分配的時間數,備註,當前狀態來表示一個人在某個項目上的數據,這時候就可以通過一個以項目名(_id)爲key的字段插在person對象之上,value是一個新的json對象,其中包括spent,comment,status等字段。

爲了不和前面幾個特殊字段名衝突,項目名首字符不允許是“_”。

2) project集合

表4.3:project集合的結構

序號

字段

類型

說明

索引

驗證

1

_id

String

項目名

正則表達式

2

_about

String

備註信息


長度限制

3

_owner

String

該項目的創建人



4

_type

String

所屬分類

正則表達式

5

_sub_type

String

所屬子分類




Project集合存放了所有的項目。其中_type字段和_sub_type字段是爲了某些地區用戶服務,他們希望對項目進行二級分類,以方便管理,但這個特性並不常用。和person集合一樣,利用_id作爲項目名,類型索引_type作爲批量操作的入口點。_owner是一個記錄字段,記錄上次修改這個項目的人,其餘的2個字段都是描述字段。


3 department集合

表4.4:department集合的結構

序號

字段

類型

說明

索引

驗證

1

_id

String

部門名

正則表達式


[project]

number

關於某個項目的信息,多個字段


整形數,大小限制


……






Department集合是一個只爲存儲項目對部門的公共需求(總需求)而存在的集合。這個集合比較簡單,除了_id作爲部門名,剩下若干個字段分別對應一個項目:鍵爲項目名,值爲部門被這個項目所要求的時間(數字類型)

4 log集合




表4.5:log集合的結構

序號

字段

類型

說明

索引

驗證

1

_id

Number

Log創建的時間


2

Method

string枚舉

http方法,get、post、put、delete


枚舉類型

3

Ip

String

用戶的ip地址


Ipv4、ipv6格式驗證

4

User

String

用戶的_id



5

Person

String

某操作所涉及的person的_id



6

Department

String

某操作所涉及的department的_id



7

Project

String

某操作所涉及的project的_id



8

About

String

備註信息


長度限制


Log集合是一個輔助集合,記錄某一個用戶操作所產生的影響,也就是日誌。這樣有利於系統出現異常時的錯誤定位和責任追蹤,查看日誌也是網站管理員所必須的習慣。除了更新員工的分配時間這種高頻操作外,其餘所有的增刪改操作都會計入log集合。關於如何實現在接下來的“系統實現一章”講解。

和數據庫功能有關的模塊包括索引模塊,模型層模塊,數據驗證模塊。

4.2 統計

4.2.1 表格變形

表格變形指的是在數據層面不變的情況下,對view層面的表現形式進行變換[9],從而達到更好的數據展示效果。在context menu中直接提供了6種批量的變形操作。

1.Collapse All。將所有的索引子表摺疊起來,只展現索引列表,這個操作和Expand All同樣可以通過一個個點擊表格中的箭頭號來實現。

2.Expand All。是上面Collapse All的逆操作,即展開所有的索引子表。

3.Autosize All Columns。,根據當前可視窗口的內容自動調整每一列的寬度。

4.Reset Columns。重置表格到最開始的形狀。

5.Group(only)by [column]。對當前聚焦的列進行一級索引。

6.Ungroup All。取消所有的索引。


除了這6種批量的變形操作,還可以對某一列某一行進行單獨操作,比如在側邊欄可以過濾行或隱藏列,表頭位置可以排序,手動調整列寬和順序,手動摺疊/展開索引等。所有的變形因爲不影響數據,都是可逆操作,也不會觸發請求。

和表格變形有關的模塊包括表格交互模塊,表格變形配置模塊。

4.2.2 雷達圖

繪製統計圖是爲了更直觀的表現表格數據,主要是爲了表現項目需求與部門的付出之間的對比。本來根據數據結構,有4種統計方式,分別是:

1)person/project

2)person/type

3)department/project

4)department/type

他們分別代表每一個person對應所有project或type,每一個department對應所有project或type,並以此爲基礎畫出需求值和實際使用值的多邊形(雷達圖),然後進行面積的比較,從而達到觀察需求是否滿足的目的。至於選擇雷達圖是爲了更好的表現面積。

但是考慮到實際情況,本系統只需要第3種方式,也就是對於某一個部門,將所有項目每7個一組繪製成一個雷達圖,圖中分別是demand線和actual(spent)線。

和雷達圖有關的模塊包括雷達圖模塊。

4.2.3 Excel導出

這個功能可以讓用戶將當前編輯過的表格導出成excel文件[10],這個功能設計在右鍵菜單中。

和excel導出有關的模塊是表格交互模塊。

4.2 編輯與設置

4.2.1 對象增刪改查

更新包含增,刪,改,其中增與改對應的http方法是post和put[11]

本系統需要考慮3種對象的添加與修改,但主要考慮由用戶操作直接引起的person對象和project對象。在允許操作前需要經過層層的驗證和過濾方可通行,其中包括:

1)用戶是否已經登錄,檢查request.session.user是否存在。

2)是否有權限,檢查用戶的_departmentList和_typeList字段。

3)用戶_capacity字段是否>0

4)確保person對象的_department或project對象的_type存在。

5)所有string類型字段需要滿足相應的正則表達式。

刪除對象操作對應的是delete方法,過濾器只需要判斷是否有權限即可允許通過。刪除project對象的時候要注意同時刪除掉person和department集合中存在的相應的project字段,以避免數據庫黑洞。

更新對象的流程如圖4.4所示。

圖4.4 update對象的流程圖


主頁面初始化的時候,客戶端會主動請求“所有數據”,但並不是數據庫中的所有數據,而是自身需要的所有,比如某個測試賬戶只需要1個部門下所有員工信息以及4個type下的所有project信息,這樣對整個數據庫表的讀取只需要過濾成1行或者4行,其他行通常是別的地區的員工信息。這種過濾操作對應的api是/get/filteredAll

但是在account setting界面初始化有點不同,這時候需要所有的部門員工以及所有的project,但又要屏蔽掉表格中不需要的許多列比如員工的時間分配信息,這樣是爲了避免讀取整個數據庫,那是很可怕的。所以這時候需要關係代數中的“投影(project)”操作,即過濾掉不需要的屬性(列)。這種投影操作對應的api是/get/projectedAll

2種關係型操作可以用圖4.5來簡單理解:filter是“過濾行”,project是“過濾列”。

圖4.5:2種使用到的關係的api請求範圍

對象增刪改查有關的模塊包括增刪改查模塊,數據過濾模塊。

4.2.2 賬戶設置

賬戶設置功能指用戶登錄以後可以設置自己的賬號信息[12],包括修改密碼,調整自己的管轄範圍或者切換部門。賬戶設置將放在一個單獨的頁面裏來展現,頁面中將呈現數據庫中所有的員工和項目的信息,並高亮出用戶自己所管轄的那部分,然後所有的數據擁有多選框可供用戶選擇,已達到“切換”部門的功能。

和賬戶設置有關的模塊包括數據過濾模塊,增刪改查模塊。

4.2.3 登錄登出

登錄登出即最基本的用戶會話連接的維護功能。

和登錄登出有關的模塊是會話控制模塊。

4.4 管理員

4.4.1 日誌訪問

系統日誌是爲了排錯[13]而設計的,通常用戶的每一個操作都會被記錄下,同時還要求管理員有權限來訪問。

和日誌訪問有關的模塊是日誌模塊。

4.4.2 遠程調試

遠程調試模塊叫做debug remotely,也是給管理員調試後端程序服務的,這個功能希望能夠給管理員用戶提供一個接口,通過網絡傳輸,在服務端的nodejs環境下執行命令,從而達到直接操作服務器的目的。

和遠程調試有關的模塊是遠程調試模塊。

4.4.3 用戶註冊

由於本系統用戶數量穩定,同時每個用戶還需要和他對應的公司個人信息認證,實名認證稍有麻煩,再加上用戶註冊的頻率很低,本系統沒有設計自動註冊賬戶的功能。取而代之的是讓管理員去添加新用戶或刪除用戶。

5 系統實現

圖5.1根據前後端分類,列舉出了本系統爲了實現所有的功能(系統功能圖4.1),所需要的所有模塊。

圖5.1 前後端模塊一覽

5.1 前端

5.1.1 表格交互模塊

context菜單是鼠標右鍵彈出的菜單。在表格的任意位置點擊都可以觸發菜單,但是點擊的位置會影響當前聚焦的對象。聚焦對象指的是,在某一時刻,進行增刪查改的對象聚焦到唯一的person,唯一的project,以及唯一的department。當菜單觸發以後,觸發點所在的那一行中相關的對象就會覆蓋上一次的焦點。這樣設計的目的是,想要修改某一個數據,比如某一個人,只要將鼠標移動到他附近再右鍵就好了。

其中,update和remove分別對應着更新和刪除操作,而且會彈出包含編輯器的對話框,還可以在表格右半部分的嵌入式編輯器中直接修改員工的數據。chart則表示繪製圖[14],transform是在view層面對錶格進行變形,但不影響數據。Export可以將本表格導出成csv或者Excel文件。

Aggrid框架提供了許多功能與事件,功能可以提供更友好的用戶操作[15],事件可以和開發者自己的腳本對接起來。下面一一列舉所使用到的功能和事件的配置方法和作用。

1.側邊欄。表格側邊欄是分佈在右側的一個多標籤頁的窗口,提供一些快捷鍵,雖然這些快捷鍵被context menu裏的選項替代,但放在右側更直觀。

2.動畫。框架提供了動畫效果,當用戶拖拽,縮放表格的時候都會出現相應的漸變動畫,使得操作效果更友好直觀。

3.整行嵌入式編輯。除了group行,每一行都可以直接在行內使用文本框和選擇器編輯文本和數字。雙擊或者任意字符鍵打開編輯器,編輯完整行數據後回車或失去焦點即完成編輯,觸發事件,發送到服務器更新。

4.允許分組。分組功能指對所有行進行分類,類似數據庫表中的索引操作。系統加載時默認只對人名來索引,用戶可以通過查找某人快速定位到某一行。和數據庫索引不同的是,這裏的分組是有層級關係的,比如對部門進行一級索引,再對人名進行二級索引。

5.單擊打印本行對象。當主鍵單擊某一行,都會打印這一行所對應的內存對象,方便debug。

6.允許排序。排序的作用不言而喻,尤其是對索引列的排序至關重要。

7.允許搜索。允許在某一列當中通過關鍵字搜索某一行。

8.編輯器濾鏡。用戶編輯完某一單元格數據後,數據並不會立即更新,新數據以文本串的形式傳遞到parser函數,經過一定的規則驗證或“修訂”後再寫入新數據。比如數字類型的spent time一列編輯完後需要審查是否是一個合法的數字,還要將string轉成number類型。


5.1.2 schema封裝模塊

本系統的表格擁有以下幾列,並且從採用平鋪的方式導入數據,比如一個人對應多個項目的話,就生成多行。本系統初始化表格的時候是通過每個人----每個項目的形式遍歷的,及總行數(不包含group的行)爲人數*項目數,然後默認將demand爲空的那些行給隱藏起來,這樣做的目的是既照顧到所有的資源又可以自動屏蔽不需要的數據。

1)Group:當前表格彙總行所佔據的一列,由系統自動生成,類似於索引值所單獨佔據的一列。

2)Person:員工的姓名(ID)。

3)Department:員工的部門。

4)Personal Info:員工的備註信息。(默認隱藏)

5)Project:某一個項目名(ID)。

6)Project Type:該項目的類型。

7)Sub Project Type:項目子分類。(默認隱藏)

8)Department Demand:該項目對該部門要求的資源數(number類型)。

9)Spent Time:該員工在該項目上花費的時間數(number類型)。

10)Action:該員工在該項目上的所作所爲。

11)Status:該員工在該項目上的進度(枚舉類型)。

12)Comment:該員工在該項目上所作所爲的備註信息。

5.1.3 異步封裝模塊

主界面”/”引入了2個js文件,分別是主線劇情/public/my/main.js和異步方法/public/my/async.js。其中async.js提供了所有封裝好的異步操作,從任務的開始到結束都封裝在一個promise內,等待調用。根據類型,這些異步模塊分爲編輯器UI異步工具和網絡類異步工具。

1)編輯器UI異步。在很多情況下,UI的變化是異步完成的,比如UI的加載有時候就很慢,還有比如某一個對話框需要等側邊欄隱藏起來後才能打開。所以本系統準備了3個編輯器對話框的異步函數,分別是登錄框,person編輯框以及project編輯框。Promise從對話框打開的一瞬間開始,到用戶點擊確定或取消時結束。

2)網絡層面的異步[16]模塊則較多,包含登錄,初始化數據請求,debug remotely,下載日誌,CRUD對象,申請賬戶設置,拷貝用戶模板。網絡層的promise則從接收一個原始數據開始,發送http,返回結果並解析返回數據完成。

就網絡層的異步模塊來說就有多達13種:

window.curd = {

        login,

        getAll,

        debug,

        log,

        getExtraData,

        setHuman,

        dropHuman,

        addHuman,

        addSkill,

        setSkill,

        dropSkill,

        setRole,

        dropRole,

    };


5.1.4 前端自動化腳本

與debug remotely相對應,debug locally可以在本地解析執行瀏覽器環境下的JavaScript腳本。通過localstorage api接口在用戶瀏覽器本地存儲一段用戶自制的代碼段,每次頁面加載時自動執行,由於本地執行的原因,無需擔心安全性。

不過debug locally的應用場景並不多,主要適合一些極端用戶的個性需求,比如調整界面的主題顏色,自動隱藏不想看到的表格行等等。

前端自動化腳本模塊對應的函數是debug_locally

// onclick

function debug_local() {

    let cmd = prompt('Overwrite current command:', localStorage.getItem('debug') || '');

    if (cmd !== null) {

        if (cmd.trim() === '') localStorage.removeItem('debug');

        else localStorage.setItem('debug', cmd);

        if (confirm('Command updated, reload?'))

            location.reload();

    }

}

5.1.5 渲染循環模塊

渲染循環(render loop)是對UI刷新的常見函數,在本系統中有一個repaint函數專門用來對錶格“重畫”,也就是全部更新(局部更新的情況不適用)。Repaint的作用是將掛載在全局變量下的所有數據列表渲染進表格裏。

5.1.6 UI佈局模塊

主界面和account setting界面都是基於material的扁平化佈局,佈局方向是上下,左中右結構。首先上方是top app bar或者標題欄,下方從左到右分別是抽屜,網格,側邊欄,其中抽屜可以隱藏到頁面左邊,側邊欄的功能由aggrid配置決定,本系統設置了3個側邊標籤頁,可以非常方便的對網格進行變形。

還有3個臨時出現的UI元素,分別是snackbar,progress bar,tooltip。Snackbar是一個偶爾彈出的消息框,用於提示用戶操作的結果,progress bar出現在界面下方,用於顯示當前網絡請求的狀態,tooltip是鼠標提示框,當鼠標懸浮在某個按鈕上,可以提示一些幫助信息。這三個“隱藏”元素如圖5.7所示。

5.7 3種隱藏UI----snackbar,progress bar,tooltip

另一邊,setting頁面的佈局則是常見的頂部標籤頁分佈,外加動畫切換和tooltip提示。Json列表的編輯器採用複選框checkboxes的模式來實現。

5.1.7 表格變形配置模塊

5.8 6種批量表格變形操作

如圖5.8所示,本系統在context菜單中提供了6種表格變形的功能,分別是摺疊所有索引,展開所有索引,自動調整列寬,重置所有列,對當前列索引,取消所有索引。配置代碼如下。

const menu_transform = {

        name: 'Transform',

        icon: 'transform',

        subMenu: [

            'contractAll',

            'expandAll',

            'autoSizeAll',

            'separator',

            'resetColumns',

            {

                name: `Group(only) by ${event.column.colDef.headerName}`,

                action: () => {

                    let col = gridOptions.columnApi.getColumn(event.column.colDef.field);

                    gridOptions.columnApi.setRowGroupColumns([col]);

                    gridOptions.api.expandAll();

                    gridOptions.columnApi.autoSizeAllColumns();

                }

            }, {

                name: 'Ungroup All',

                action: () => {

                    gridOptions.columnApi.setRowGroupColumns([]);

                }

            },

        ]

    }

5.1.8 雷達圖模塊

雷達圖的具體實現方法是,先對錶格進行變形,以department作爲一級分類(通常也就一個部門),project作爲2級分類,如圖5.9所示。然後對spent time一列進行求和運算彙總到彙總行上,對department demand一列進行first運算(選擇第一個值作爲聚合值,因爲都一樣)彙總到彙總行上,最後提取這些彙總的數據畫出雷達圖。

圖5.9 雷達圖一一對應的表格結構示例(變形後)

圖5.10 雷達圖示例


5.2 後端

5.2.1 目錄設計模塊

開始實現之前先確定好代碼的目錄結構,添加必要的文件和目錄,然後開始編輯內容,目錄結構圖如圖5.11。

5.11 本系統中文件與目錄結構

1)README.mdGitHub默認的幫助文件。

2)model/:該目錄存放了MVC模型層必要的工具文件,主要是針對project表,person表,department表,log表進行高效CRUD的調用函數。

3)package.jsonnode項目說明文件,從開發環境的角度描述了整個項目。

4)LICENSE項目開源許可證。

5)index.js項目的入口執行文件,通過node命令解釋執行。

6)cfg.js配置文件,存儲了所有的配置數據。只有配置文件和mongodb數據庫儲存了所有必要的和本系統相關的數據,其餘地方和文件都儲存的是代碼信息。

7)其他/:該目錄存放了一些不重要的文件,比如前期開發文檔,用戶使用說明書,自動化測試腳本等。

8)view/:該目錄存放了MVC視圖層的模板引擎ejs文件,一個ejs對應一個html頁面,總共設計了3個頁面,分別是main.ejs,error.ejs,setting.ejs,分別是主界面,錯誤跳轉界面和用戶設置界面。爲了滿足SPA單頁應用的設計原則,絕大部分的應用任務在主頁面上完成。

9)ssl/:該目錄存放了https網站必須的ssl證書以及私鑰,但由於本項目沒有購買證書的必要,這裏存放了以localhost爲common name的自簽名證書,所以網站訪問的時候會顯示“不安全”。

10)route/:該目錄存放了MVC路由層的handler文件,根據restful設計模式分爲log,set,get,add,drop這5個文件。本項目的所有業務邏輯基本都在這一層實現。

11)public/:該目錄存放了所有直接扔給前端的靜態文件,包括前端框架,必要的js腳本,圖片等。同時這個目錄的文件還會被瀏覽器緩存30天以提高web app的效率。

12)node_modules/:該目錄存放了所有後端使用的nodejs第三方庫,比如archiver,body-parser,ejs,express,session,mongodb等。

13)mongo_backup/:該目錄存放了數據庫的備份文件。管理員登錄系統後可以使用“一鍵備份”的功能,將mongodb中重要的3個表分別導出json文件,再打包下載。

5.2.2 入口設計模塊

後端提供的可交互api的具體設計方式是,首先用戶打開主界面後要登錄(7天的緩存免登錄),然後向後端請求相關地區所有的person對象和project對象,得到之先遍歷所有的人再遍歷所有項目,將遍歷之後的二層嵌套結構渲染進表格,同時department demand爲空的那些行可以過濾掉,因爲他們被認爲是不需要參與的項目。

整個系統的入口程序主要是/index.js和/cfg.js

爲了不濫用頂級對象global的屬性,本系統將所有的全局對象掛載在global.cfg下,這個cfg對象來自/cfg.js導出。Cfg對象包含server的信息,數據庫mongodb的信息,app的信息,前端文件映射的信息,數據庫對象的字段驗證信息,常用工具類函數等。

/index.js分成3個promise,分別是初始化全局變量,初始化MongoDB,初始化expressjs。3個任務併發進行,全部結束後打印url,即可正常訪問,如若失敗則終止進程。

1)初始化nodejs全局變量。首先require /cfg.js文件,掛在在global.cfg下,然後在標準庫上自定義一些實用的方法,比如RegExp.escape用於將用戶發來的一段文本轉譯成普通文本再構建成正則表達式,比如Date和Function原型鏈上的toJSON方法設計成一個可讀的文本串,方便前後端傳遞json數據。

2)初始化expressjs。首先生成express對象,然後指定模板引擎爲ejs並指定模板地址。開始路由,設置靜態文件目錄爲/public/並掛載在/public/下,之後經過session過濾器,再然後設置入口地址“/”返回渲染後的main.ejs,再引入之前定義好的5個路由模塊,最後保留一條缺省路由指向404的錯誤頁面,結束路由。路由配置完成後,require https模塊生成服務器對象,同時導入/ssl/目錄中的私鑰和證書,以及之前創建的express對象,最後申請443端口號,開啓服務。

3)初始化mongodb。連接到指定的數據庫主機需要經過一系列步驟:首先利用Mongo官方開發的node連接器連接指定url,將得到的數據庫對象掛載在global.DB下,同時將MVC model層的4個集合對象掛載在global.model下;然後檢查當前數據庫中是否已經存在所需要的5個集合,如果沒有則創建出來;之後對person的_department和project集合的_type列添加索引(如果存在則不變);最後根據cfg中保存的schema對必要的集合列添加驗證器,完成任務。

等待3個promise任務完成後打印url或者報錯時退出程序的代碼如下:

Promise.all([initGlobal(), initExpress(), initMongo()])

    .then(() => {

        console.log('[init OK]');

        console.log(`   ${cfg.app.protocol}://${cfg.server.domain || cfg.server.ip}:${cfg.app.port}`);

    }).catch(err => {

        console.log(err.message);

        process.exit(0);

    });


5.2.3 增刪改查模塊

增刪改查模塊提供一個完整的請求回調函數,對用戶的請求進行驗證,執行,記錄,返回,所有的CRUD函數都在路由層實現。函數接收request對象,返回一個response對象。

5.2.4 頁面跳轉模塊

雖然應該遵守SPA的原則,但是現代瀏覽器並不是完全爲app而設計的虛擬機,有時候系統需要“子窗口”的功能,又不能頻繁使用對話框,所以就採用了第二章頁面作爲賬戶設置界面,出錯處理界面,數據庫備份(臨時頁面)和logout頁面(臨時頁面),以兼容現在的前端技術。

除了主頁面所在的根路徑“/”,其餘2個頁面都掛載在/get/下。

1)/get/error_page?status&msg:跳轉到錯誤頁面,還可以定製http返回碼以及錯誤提示,通常訪問/get/setting和/get/mongo_backup的時候出現權限問題會跳轉到這個頁面,如果前端發現後端數據有致命漏洞或者瀏覽器有兼容性問題的時候也會停止渲染,跳轉到錯誤頁面。

2)/get/setting:用戶賬戶設置界面。這個界面可以重置自己的密碼,切換到別的地區(針對總監級別擁有該權限),查看所有地區的數據。進入account setting界面有2種方式:點擊抽屜裏的按鈕或者點擊右上角自己的ID。界面如圖5.12所示。

3)【臨時頁面】本系統從邏輯上總共4個跳轉url,除了get/error_page/get/setting,還有/get/mongo_backup和/log/logout。這兩個頁面真實情況並不存在,前者在備份文件下載完成後界面自動消失,後者訪問後會被重定向到根“/”。只是爲了邏輯上處理方便而設置了這2個虛擬頁面。


5.12 account setting是一個單獨的界面


5.2.5 遠程調試模塊

Debug remotely模塊是一個非常實用的,供管理員用戶使用的功能。原理是通過root user從前端發來的一串明文nodejs代碼,在後端通過eval函數解釋執行,理論上通過sudo出來的node進程可以有權限對服務器進行任何操作,所以eval是非常危險的,debug remotely的使用必須謹慎。效果如圖5.13所示。

5.13 debug remotely的效果示例

遠程調試模塊代碼較簡單,整個接收函數如下。

// _root用戶only

// 接收string of code, 返回json或者錯誤msg

router.put('/debug', bodyParser.text(), (req, res, next) => {

    new Promise((res, rej) => {

        assert(req.session.user && req.session.user._root, 'Permission denied, root user required');

        res();

    }).then(() => model.log.insertOne({

        ip: req.ip,

        user: req.session.user._id,

        method: req.method,

        extra: req.body

    })).then(() => {

        res.set('Content-Type', `application/json`);

        res.end(JSON.stringify(eval(req.body)));

    }).catch(err => {

        res.status(400).json(err.message);

    })

});

5.2.6 數據庫備份模塊

爲了方便管理員定期備份數據庫,本系統設計了一個“一鍵備份”的功能,即一鍵導出數據庫中3個主要集合,分別導出json文件再將文件夾打包成zip下載下來。

首先建立一個mongodb的可讀流和文件系統的可寫流,將person,department,project集合分別導向/mongo_backup目錄下的person.json,department.json以及project.json。事件完成後再將/mongo_backup目錄打包成zip文件,同樣以流的形式返回給用戶,整個過程共享一個http來回。

因爲數據庫備份相比其他操作更消耗資源,所以設置一個時長5分鐘的最小間隔,以避免頻繁備份,同時只有管理員有權限執行此操作。

5.2.7 數據過濾模塊

數據過濾模塊是在MVC的業務邏輯層中的請求回調函數中放置一些assert斷言方法對request對象中攜帶參數進行驗證和過濾,比如最常使用的驗證是否登錄:

            assert(req.session.user, 'session expired, login first');

5.2.8 會話控制模塊

系統需要一個用戶登錄登出的功能。登錄的本質是認證,並且利用cookie-session機制建立一箇中程的連接,後端存儲session有3種方式:

1)存儲在內存中。

2)存儲在文件系統中。

3)存儲在各種類型的數據庫中。

其中第一種方式是不可取的,因爲將session存放在寶貴的內存中很容易被ddos攻擊,剩下2種方式都是存在外存當中,相對合理得多,又由於本項目已經使用mongodb數據庫了,就統一將session也存入數據庫中的sessions集合。

每次用戶訪問都會刷新cookie的到期時間,添加或者維持與之對應的session消息。每次用戶登錄都會檢查session看用戶是否已經登錄過,如果有就直接返回session種存放的user對象,如果沒有就檢查person集合進行認證(request對象中包含用戶發來的user對象)。由於本系統使用https,傳輸中密碼無需加密,但是數據庫中的密碼統一採用sha1加密,由node標準庫中的crypto模塊簡潔實現。

登出模塊的實現只要刪除用戶session中的user對象即可。代碼詳見目錄中/route/log.js文件。

5.2.9 日誌模塊

日誌系統的設計分爲讀與寫,其中寫入日誌需要路由到model層的log模塊來調用,直接傳入log對象即可寫入,同時還會主動分配_id作爲寫入的時間以便排序,當然該字段寫入前會做一個防抖,以防同一ms級出現2個相同的_id。讀取日誌時則選擇最新的200條日誌返回給用戶,同時還要定期清除過期(30天)的日誌。插入一條log的代碼實例:

model.log.insertOne({

            ip: req.ip,

            user: req.session.user._id,

            human: human._id,

            method: req.method

        })

5.3 數據庫

5.3.1 索引模塊

數據庫索引是最常見的優化操作,在本次的mongodb數據庫中,除了本身默認的對_id字段的索引外,本系統還需要對person集合和project集合的分類字段進行索引,也就是_department和_type字段。

Promise.all([

                DB.collection('human').createIndex({

                    _role: -1

                }), DB.collection('skill').createIndex({

                    _type: -1

                })

            ]);

5.3.2 模型層模塊

MVC中模型層提供的數據接口,提供一些常用的數據庫增刪改查操作的封裝api,比如登錄方法login:

(user) => new Promise((res, rej) => {

        // 更新並返回更新前的數據

        coll.findOne(user, (err, result) => {

            if (err) rej(err);

            // 否則返回null

            else if (result) res(result);

            else rej(new Error(`Login failed: \n username or password not right`));

        });

    })

5.3.3 數據驗證模塊

數據驗證模塊是mongodb數據庫在添加或更新時經過的一層驗證器,對字段進行一些條件審查,比如對_type字段強制存在:

DB.command({

                collMod: "skill",

                validator: {

                    _type: {

                        $exists: true

                    }

                },

                validationLevel: "strict",

                validationAction: "error",

            })

6 測試

6.1 功能性測試(用戶數據驗證)

本次採用黑盒測試法,選取一個具有代表性的功能,通過添加惡意project對象來測試後端的字段驗證器是否正常工作。

6.1 黑盒測試示例

6.1 黑盒測試結果

類型

輸入

輸出

預期結果

       結果

添加大寫person_id

JinHengyu

Jinhengyu

人名全部轉成小寫

符合預期

添加惡意的project_id

-test-test$test

-test-test-test

特殊字符全部被轉換成‘-’

符合預期

更新500字符以上的project_about

[500+的任意文本]

[…..] failed the Regular Expression /^[\s\S]{0,500}$/,try another one pls

 提示正則表達式驗證失敗,promise被rejected。

符合預期

添加重名project

兩次“-”

E11000 duplicate key error collection: graduation.skill index: _id_ dup key: { : "-" }

Mongodb提示唯一索引_id重複了,promise被rejected。

符合預期

結果表明,每次添加的project對象的屬性都在後端被過濾和轉換了,沒有出現惡意字符逃逸的情況,所以本次測試結果全部符合預期,後端數據過濾器測試通過。

6.2 安全性測試

6.2.1 請求未知資源(404

請求一個錯誤的url:/nothing,測試錯誤是否捕捉到,預期會得到404頁面,結果如下。

6.2 404界面

結果表明,當請求404資源的時候,系統會捕獲異常,並且提示用戶錯誤,不會因爲異常請求導致系統出錯。測試通過。

6.2.2 權限測試

非root user使用debug remotely(遠程調試)功能,預期被攔截:

6.3 瀏覽器提示用戶權限不夠

結果表明,低級別用戶使用高級別功能的時候,無論在系統處理上,還是在UI上都進行了攔截。測試通過。

7 總結與展望

本系統爲產品經理和項目經理服務,提供了對“員工”和“項目”這兩種資源之間關係的增刪改查操作,其中的“查”指的是統計功能。

本系統設計上的特色在於,全面實現了material design主題,SPA單頁面應用程序,底層上通過函數式編程風格,結合promise模塊化的理念實現了高可用同時易擴展的特點。本系統的設計從功能,性能與安全性上考慮:功能上考慮了整體UI和表格的各種操作,性能上主要考慮算法優化,控制內存的使用,以及減少靜態文件體積,安全性上利用https協議防止外部攻擊,利用後端數據驗證防止內部的操作失誤。

經過了對本系統的功能和性能測試,本系統的使用效果做到了儘可能的舒適,安全性上也足夠健壯。

本系統仍然有一些可以提升的地方,比如數據庫中department集合和project集合可以合併以提高內聚性;使用w3c最新的web component組件標準可以減少框架帶來的壓力;可以同時採用除雷達圖之外其他的圖表,如柱狀圖和線形圖;升級http1.1至二進制傳輸的http2.0可以大幅提升網絡資源的利用率。







參考文獻

[1] 韓萬江.軟件項目管理案例教程(第三版).北京機械工業出版社,2015101-102

[2] HTTP設計模式RESTful 維基百科. https://ssl123d1063af181fe606e55ed93dd5b867169.vpn.nuist.edu.cn/wiki/Representational_state_transfer
[3] 李洪海,石爽.交互界面設計(第一版).化學工業出版社出版,201145-51
[4] Rick Copeland.MongoDB應用設計模式(第一版).中國電力出版社,201594-96

[6] https://expressjs.com/. Express web框架的官方網站. 2019.4-1

[7] http://nodejs.cn/ . NodeJS中文網. 2019.3-1

[8] https://www.mongodb.com/docs . mongodb數據庫開發文檔. 2019.3-1

[9] https://material.io/develop/web/ . google material design components for web 官方網站. 2019.4-1

[10] https://www.ag-grid.com/ . ag-grid前端框架官網. 2019.4-1

[11] https://developer.mozilla.org/zh-CN/ . mozilla前端開發者網站(MDN. 2019.2-1

[12] Mingmin Zhang,Zhigeng Pan.EasyHome:an online virtual home decoration system[J].Computer Animation and Virtual Worlds,2014,25(2):101-105

[13] Williams ME,Consolazio GR,Hoit MI.Advances in Engineering Software [J].2005;36

[14] Elver G.Geometric texture modeling[J].IEEE Computer Graphics and Applications 2005;25(4):66-67.

[15] Nashat Mansour,Manal Houri.Testing web application[J].Infomation and Software Technology2006,48(1):31-42

[16] MATTSON RLR,GHOSH S.HTTP-MPLEX:An enhanced hypertext transfer protocol and its performance evalution [J],Journal of Network and Compjter /applications,2009,32(4):925-939








致謝


在論文的末尾我想對幫助過我的老師以及同學,說聲謝謝!感謝這段時間你們不厭其煩的幫助,在知識上對我有莫大的推動力讓我有了質的提升,非常的感謝

  首先誠摯的感謝我的論文指導老師XXX老師。她在忙碌的教學工作中擠出時間來審查、修改我的論文。徐老師對我們特別負責任,很早就告訴我們該如何切入自己的論文研究點,可以通過哪些途徑查詢到較新的資料,我從老師身上學到了很多完成一件事就要把做好,用最認真的態度去完成每一個細節,尤其最後寫論文的時候,老師指導了我們很多次關於如何排版和畫圖,真的由衷感謝老師這段時間的付出,老師辛苦了。

還要感謝教過我的所有老師們,你們嚴謹細緻、一絲不苟的作風一直是我工作、學習中的榜樣。能夠完成我大學裏最後一道作業,我感覺榮幸,感謝學院裏的每一位老師,給我這個機會來證明自己是可以的,事實證明只要努力就會有成果,希望下一屆的學弟學妹們不要鬆懈。祝福大學裏遇到的所有人,曾經幫助過我的人,非常感謝!


本文分享自微信公衆號 - WebHub(myWebHub)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章