免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
!!!!基于VueJs的前后端分離框架搭建之完全攻略

!!!!基于VueJs的前后端分離框架搭建之完全攻略

首先請(qǐng)?jiān)彵疚臉?biāo)題取的有點(diǎn)大,但并非為了嘩眾取寵。本文取這個(gè)標(biāo)題主要有3個(gè)原因,這也是寫(xiě)作本文的初衷:

 

(1)目前國(guó)內(nèi)幾乎搜索不到全面講解如何搭建前后端分離框架的文章,講前后端分離框架思想的就更少了,而筆者希望在本文中能夠全面、詳細(xì)地闡述我們團(tuán)隊(duì)在前后端分離的摸索中所得到的搭建思路、最佳實(shí)踐以及架構(gòu)思想;

 

(2)我們團(tuán)隊(duì)所搭建的前后端分離框架,并非只是將網(wǎng)上傳播的知識(shí)碎片簡(jiǎn)單拼裝,而是一開(kāi)始就從全局出發(fā),按照整個(gè)系統(tǒng)對(duì)前后端分離框架的最高期望進(jìn)行設(shè)計(jì),到目前為止,可以說(shuō)我們的框架完全實(shí)現(xiàn)了對(duì)我們前后端分離的全部期望;

 

(3)我們?cè)诖罱ㄟ^(guò)程中產(chǎn)生了一些創(chuàng)新(比如最大的創(chuàng)新就是API文檔服務(wù)器的搭建),希望這些創(chuàng)新可以為您的團(tuán)隊(duì)在前后端分離的探索中提供一些有用的思路。

 

本文適合的讀者對(duì)象:對(duì)軟件系統(tǒng)架構(gòu)有一定經(jīng)驗(yàn)+對(duì)WEB前端/客戶(hù)端軟件開(kāi)發(fā)有一定經(jīng)驗(yàn)+對(duì)服務(wù)器端開(kāi)發(fā)有一定經(jīng)驗(yàn)。

 

注:本文中所提的“前端”主要指WEB前端,當(dāng)然在很多情況下也適用于客戶(hù)端軟件,如桌面程序、APP等。

 

第一章   為什么要前后端分離

 

1、引用“為什么我不喜歡「前后端分離」(個(gè)人觀(guān)點(diǎn),歡迎來(lái)噴)”

首先大家可以閱讀一下中文版原文:https://www.v2ex.com/t/298014?p=4,很有意思的一篇文章,作者文筆幽默,閱讀起來(lái)很輕松。

 

文中有幾個(gè)觀(guān)點(diǎn)是筆者特別贊同的,比如:

(1)前后端不分離的團(tuán)隊(duì),前端工程師都是頁(yè)面仔話(huà)語(yǔ)權(quán)很弱,技術(shù)大牛都在后端,前端相當(dāng)于給后端工程師打雜的;前端工程師晉升機(jī)會(huì)很少,薪資不高,發(fā)展前景渺茫;

(2)前后端分離后,更好招聘,團(tuán)隊(duì)耦合度更低,職責(zé)更分明。

 

但是文中也有一些觀(guān)點(diǎn)是筆者不敢認(rèn)同的。比如作者最終推薦【全棧工程師】,雖然筆者多年前就是一名全棧工程師,但我深知前后端分離的好處遠(yuǎn)大于全棧工程師帶來(lái)的好處。原因有4,詳見(jiàn)下一小節(jié)。

 

2、為什么我們團(tuán)隊(duì)要采用前后端分離

我們團(tuán)隊(duì)最終決定進(jìn)行前后端分離改造的4個(gè)主要原因:

(1)全棧工程師很難招聘,很難培養(yǎng),很多后端開(kāi)發(fā)人員不愿意學(xué)前端技術(shù),而很多前端開(kāi)發(fā)人員學(xué)后端技術(shù);

(2)如果前后端不分離,前端工程師的工作就必須依賴(lài)后端工程師,前端工程師變成打雜的,職業(yè)生涯前景慘淡;

(3)前后端分離后,前端和后端工程師獨(dú)立開(kāi)發(fā),大大提高開(kāi)發(fā)效率;

(4)綜合來(lái)講,前后端分離的用人成本遠(yuǎn)低于全棧工程師用人成本;同時(shí),前后端分離的工作效率遠(yuǎn)大于耦合工作的工作效率;

 

然而我們團(tuán)隊(duì)也是從最近才開(kāi)始全面實(shí)施前后端分離的,因?yàn)楣P者深知,上面4個(gè)原因所描繪的美好愿景,其實(shí)際效果將會(huì)極大的取決于一個(gè)關(guān)鍵環(huán)節(jié):API文檔服務(wù)器。一個(gè)將就的API文檔服務(wù)器會(huì)使前后端開(kāi)發(fā)工作痛不欲生,團(tuán)隊(duì)矛盾日益尖銳,最終將會(huì)使程序質(zhì)量下降,然后沒(méi)有人愿意維護(hù)。

 

筆者在2018年3月終于完成一個(gè)近乎完美的API文檔服務(wù)器的搭建方案,該方案完全實(shí)現(xiàn)了我對(duì)API文檔服務(wù)器所期望的全部特性,然后花了一個(gè)周末開(kāi)發(fā)完成。

 

在下一章中,筆者將會(huì)詳細(xì)闡述API文檔服務(wù)器的重要性以及分享我們團(tuán)隊(duì)自創(chuàng)的搭建方案。

 

第二章   前后端分離最困難、最關(guān)鍵的環(huán)節(jié)——API文檔服務(wù)器

1、API文檔服務(wù)器是什么?

請(qǐng)先看下圖。

 

正如上圖所示,前后端開(kāi)發(fā)人員可以獨(dú)立開(kāi)發(fā)、獨(dú)立運(yùn)行、獨(dú)立調(diào)試,他們之間的接口就是通過(guò)API文檔服務(wù)器定義的。通常,一個(gè)頁(yè)面的加載或者表單的提交,都有數(shù)據(jù)在客戶(hù)端和服務(wù)器端之間傳輸,而API文檔服務(wù)器就是專(zhuān)門(mén)用來(lái)生成API文檔的。有了API文檔,前端開(kāi)發(fā)人員就可以基于API文檔產(chǎn)生模擬數(shù)據(jù)(mock),然后使用mock的數(shù)據(jù)完成頁(yè)面樣式和頁(yè)面交互;有了API文檔,后端開(kāi)發(fā)人員就可以基于API文檔完成請(qǐng)求的處理以及返回響應(yīng)數(shù)據(jù)。

 

而API文檔服務(wù)器(通常為WEB服務(wù)器)是一個(gè)可以動(dòng)態(tài)生成最新版本API文檔的服務(wù)器,并支持本地維護(hù)+遠(yuǎn)程訪(fǎng)問(wèn)。

 

(如果你們的項(xiàng)目還在使用靜態(tài)的API文檔,比如word文檔,那你們必定經(jīng)歷著巨大的痛苦)

 

2、為什么API文檔服務(wù)器是最困難、最關(guān)鍵的環(huán)節(jié)?

為什么本文會(huì)專(zhuān)門(mén)寫(xiě)這樣一個(gè)章節(jié)來(lái)表述API文檔服務(wù)器的重要性呢?因?yàn)楣P者認(rèn)為,很多團(tuán)隊(duì)在前后端分離的探索中舉步維艱,可能最重要的原因就是對(duì)API文檔的搭建方案重視不夠(因?yàn)楝F(xiàn)成的方案俯拾皆是,如word文檔做API載體)。因此,筆者希望大家看清楚前后端分離過(guò)程中最重要的一個(gè)環(huán)節(jié),不是原型,不是設(shè)計(jì),不是開(kāi)發(fā),也不是測(cè)試,而是API文檔的編寫(xiě)/維護(hù)/發(fā)布/閱讀。

 

然后讓我們來(lái)回想一下軟件開(kāi)發(fā)流程中的幾個(gè)關(guān)鍵環(huán)節(jié):

(1)產(chǎn)品經(jīng)理提需求,畫(huà)原型;

(2)UI設(shè)計(jì)師根據(jù)原型出設(shè)計(jì)圖;

(3)測(cè)試團(tuán)隊(duì)根據(jù)產(chǎn)品原型編寫(xiě)測(cè)試用例,制定測(cè)試計(jì)劃;

(4)架構(gòu)師根據(jù)原型編寫(xiě)API文檔;

(5)前后端工程師基于API文檔完成業(yè)務(wù)開(kāi)發(fā);

(6)測(cè)試、改BUG、發(fā)布。

 

在上面這個(gè)流程中,API文檔環(huán)節(jié)直接關(guān)系到了前端和后端兩個(gè)開(kāi)發(fā)團(tuán)隊(duì),也是整個(gè)軟件開(kāi)發(fā)流程中耗時(shí)最大的環(huán)節(jié)。一旦API文檔編寫(xiě)不合理,或者維護(hù)太麻煩,或者閱讀不方便,將極大的影響開(kāi)發(fā)效率,影響團(tuán)隊(duì)士氣。而其他環(huán)節(jié)通常不會(huì)跨部門(mén)耦合,常用解決方案非常成熟,并且所消耗的資源也遠(yuǎn)不及開(kāi)發(fā)團(tuán)隊(duì),因此,API文檔環(huán)節(jié)就變成了前后端分離團(tuán)隊(duì)中最關(guān)鍵的環(huán)節(jié)。

 

如果你曾經(jīng)參與過(guò)前后端分離團(tuán)隊(duì)的開(kāi)發(fā)工作,那你很可能對(duì)上文描述的場(chǎng)景深有體會(huì)。

 

接下來(lái)筆者說(shuō)說(shuō)為什么API文檔服務(wù)器是最困難的環(huán)節(jié)。這也是為了讓大家做足心理準(zhǔn)備:搭建API文檔服務(wù)器并沒(méi)有想象那么容易。

 

首先,最大的難點(diǎn)在于這個(gè)世界上已經(jīng)有大量現(xiàn)成的API文檔服務(wù)方案,比如用Word/Excel來(lái)做API的載體,或者使用類(lèi)似swagger這樣的框架。我們大多數(shù)架構(gòu)師,包括筆者在內(nèi),的第一反應(yīng)就是找現(xiàn)成的,然后去對(duì)比各個(gè)現(xiàn)成的方案,對(duì)比每個(gè)方案的實(shí)施難度以及適用度。我們(指架構(gòu)師們)最終找來(lái)找去,其實(shí)也沒(méi)有找到一個(gè)完美的方案,但不得不從各個(gè)現(xiàn)成的方案中選擇一個(gè),我們很少去想有沒(méi)有可能自己來(lái)搭建一個(gè),即使有時(shí)候想著自己去搭建一個(gè),但是往往一想到其中的困難(甚至無(wú)從下手)以及項(xiàng)目進(jìn)度壓力,可能就淺嘗輒止了。

 

筆者的團(tuán)隊(duì)在2018年以前的項(xiàng)目中也使用過(guò)word文檔和swagger,但我是一個(gè)追求完美的人,我一直沒(méi)有停止思考去搭建一個(gè)完美的API文檔服務(wù)器方案,直到2018年3月,終于靈光一現(xiàn),解決了搭建過(guò)程中的一個(gè)關(guān)鍵問(wèn)題(API版本管理),于是才有了我們團(tuán)隊(duì)的前后端分離之路。

 

其實(shí),本文所闡述的方案對(duì)于使用者來(lái)講也可以說(shuō)是現(xiàn)成的了,因?yàn)槊總€(gè)人注冊(cè)個(gè)賬號(hào)就可以使用。但是本文的目的并不只是簡(jiǎn)單的告訴大家我們做了一個(gè)新的API文檔服務(wù)器,而是想跟大家分享我們?yōu)槭裁匆鲞@個(gè)文檔服務(wù)器,以及為什么這樣做。

 

3、為什么我們不用word文檔作為API文檔的載體?

用word文檔(或者Excel)算是最落后的方式了吧,其缺點(diǎn)很明顯:

(1)API一多,維護(hù)和閱讀就變得極其困難;

(2)每次API文檔修改之后,需要修改者自己去維護(hù)版本修改記錄,這操作是違背人性的,并且如果想要基于單個(gè)API維護(hù)版本歷史,那可以算得上違背天理了;

(3)在word里面寫(xiě)JSON格式的數(shù)據(jù)結(jié)構(gòu)是很難的,如果用截圖那就極大的增加了維護(hù)成本;

 

說(shuō)完word文檔的缺點(diǎn),按照套路應(yīng)該說(shuō)說(shuō)word文檔的優(yōu)點(diǎn)了吧。好吧,word文檔的優(yōu)點(diǎn)就是方便傳播、離線(xiàn)閱讀,但是除非你們項(xiàng)目的API文檔的維護(hù)頻率是按年計(jì)的,那還是早早放棄word吧。

 

4、為什么我們不用swagger(及類(lèi)似方案)?

考慮到本文的讀者有可能從未接觸過(guò)swagger,筆者首先得說(shuō)說(shuō)swagger是做什么的,以及它的先進(jìn)性(沒(méi)有一定的先進(jìn)性怎么會(huì)得到這么多人的追捧是吧)。

 

swagger是一個(gè)API文檔生成框架,說(shuō)白了它是一個(gè)類(lèi)庫(kù),集成到系統(tǒng)之后,能夠通過(guò)反射讀取后端代碼定義的API文檔,java和.NET體系下都有對(duì)應(yīng)的版本。

 

swagger最大的先進(jìn)性:不需要專(zhuān)門(mén)有人來(lái)編寫(xiě)API文檔,自動(dòng)根據(jù)代碼生成API文檔,API文檔維護(hù)成本極低。swagger還有其他一些小優(yōu)點(diǎn)本文就不細(xì)說(shuō)了,因?yàn)槟切┒疾皇谴蠹疫x擇swagger的主要原因。

 

那swagger到底有什么不夠完美的地方讓我們團(tuán)隊(duì)最終完全放棄了swagger?

 

swagger之不夠完美的地方:

(1)通過(guò)swagger生成的API文檔看不見(jiàn)版本修改記錄,你不知道什么時(shí)候后端開(kāi)發(fā)人員悄悄改了下API文檔而忘記/有意不通知前端開(kāi)發(fā)人員,這樣的鍋前端背了太多;

(2)接口文檔由后端開(kāi)發(fā)人員編寫(xiě),前端開(kāi)發(fā)人員的地位實(shí)際上比后端的低,并且前端開(kāi)發(fā)人員仍然會(huì)經(jīng)常找后端開(kāi)發(fā)人員溝通修改API文檔(強(qiáng)依賴(lài)仍然存在);

(3)本來(lái)swagger的API定義應(yīng)該由架構(gòu)師或項(xiàng)目經(jīng)理編寫(xiě),但由于后端開(kāi)發(fā)人員可以直接改文檔,這導(dǎo)致的實(shí)際效果就是:基本上API文檔都直接由開(kāi)發(fā)人員編寫(xiě)(或修改),其質(zhì)量水平很難達(dá)到期望;

(4)swagger生成API文檔的類(lèi)的定義可能是多層引用關(guān)聯(lián)的,但是這個(gè)類(lèi)又太容易被開(kāi)發(fā)人員修改到,或者不小心改到,如果開(kāi)發(fā)人員忘記通知前端或者只通知了部分改動(dòng),那就會(huì)造成嚴(yán)重的問(wèn)題;

(5)使用swagger的語(yǔ)法來(lái)編寫(xiě)API文檔,其實(shí)還是很麻煩的,我們希望這個(gè)語(yǔ)法能夠超級(jí)簡(jiǎn)單;

(6)swagger會(huì)污染你的代碼。

 

關(guān)于上方的第(1)點(diǎn),筆者想跟大家分享一些工作中的趣事。以前我們團(tuán)隊(duì)使用swagger的時(shí)候,有時(shí)我們的java開(kāi)發(fā)人員發(fā)現(xiàn)某個(gè)字段的命名寫(xiě)錯(cuò)了,但是他以為客戶(hù)端開(kāi)發(fā)人員還沒(méi)有做這個(gè)功能,就悄悄的將命名修正了。后來(lái)測(cè)試提交了BUG。。。。

 

本文列出的swagger的這些缺點(diǎn),其實(shí)每一個(gè)都不算大,這也是這么多團(tuán)隊(duì)可以一直忍受它的緣故。swagger的這些缺點(diǎn)其實(shí)綜合來(lái)講,其主要的問(wèn)題就在于它讓API編寫(xiě)/修改太過(guò)容易,讓軟件開(kāi)發(fā)過(guò)程和管理過(guò)程太容易出錯(cuò)。如果你們團(tuán)隊(duì)建立了嚴(yán)格的管理機(jī)制,那還是可以將swagger用的很和諧的,但這不是筆者,作為一個(gè)架構(gòu)師,可以撇開(kāi)責(zé)任的理由。

 

作為一個(gè)架構(gòu)師,筆者以為一個(gè)好的框架應(yīng)該讓開(kāi)發(fā)人員不那么容易犯錯(cuò),甚至杜絕了開(kāi)發(fā)人員寫(xiě)出錯(cuò)誤的代碼。關(guān)于這一觀(guān)點(diǎn),筆者會(huì)在另外的文章中以我們對(duì)hibernate的改造為例,進(jìn)行更詳細(xì)的闡述:如何讓開(kāi)發(fā)人員更不容易寫(xiě)出錯(cuò)誤的代碼是評(píng)價(jià)一個(gè)架構(gòu)師能力的重要標(biāo)準(zhǔn)。

 

行文至此,筆者已經(jīng)殘忍的批判了很多團(tuán)隊(duì)的API文檔方案,如果讓您感覺(jué)不適,我只能深表歉意了。

 

在說(shuō)其他方案的缺點(diǎn)時(shí),其實(shí)筆者已經(jīng)逐漸透露了我們自創(chuàng)的API文檔服務(wù)框架將要解決的問(wèn)題了。那么,接下來(lái)請(qǐng)看我們的解決方案,以及我們?yōu)槭裁催@么設(shè)計(jì)。

 

第三章   我們自創(chuàng)的API文檔服務(wù)框架詳解

1、我心目中的API文檔服務(wù)器應(yīng)該是什么樣子?

筆者在寫(xiě)代碼或做架構(gòu)的時(shí)候有一個(gè)思維習(xí)慣,就是不管某個(gè)問(wèn)題多么復(fù)雜具體解決方案是什么,我會(huì)先去想想這個(gè)問(wèn)題的最佳的處理方式應(yīng)該是什么樣子,然后再去想這些最佳的處理方式哪些可以實(shí)現(xiàn),哪些實(shí)現(xiàn)不了而只能用次一點(diǎn)的方案,然后次一點(diǎn)的方案是否可以接受。

 

對(duì)于API文檔服務(wù)框架,在我的心中早已有了期望:

(1)編寫(xiě)API文檔的語(yǔ)法一定要非常簡(jiǎn)單,同時(shí)又要非常靈活,對(duì)于大多數(shù)常見(jiàn)API必須能夠快速編寫(xiě),對(duì)于某些特殊API,又能夠支持自定義編寫(xiě);

(2)每一個(gè)API文檔能夠非常容易的定義請(qǐng)求和響應(yīng)數(shù)據(jù)結(jié)構(gòu),最好能夠自動(dòng)生成請(qǐng)求和響應(yīng)示例,更重要的是,生成的示例必須看起來(lái)是符合業(yè)務(wù)需求的真實(shí)數(shù)據(jù);

(3)能夠非常方便的編寫(xiě)JSON格式的數(shù)據(jù);

(4)API文檔的發(fā)布要非常簡(jiǎn)單,最好能在幾秒鐘內(nèi)完成;    

(5)API文檔的源文件最好獨(dú)立于項(xiàng)目源碼,不能污染項(xiàng)目源碼;

(6)每次修改API文檔,最好能夠自動(dòng)創(chuàng)建版本歷史記錄,同時(shí)要能夠非常方便的查看歷史版本;

(7)能夠通過(guò)WEB瀏覽器訪(fǎng)問(wèn);

(8)API數(shù)量達(dá)到成千上萬(wàn)的時(shí)候,能夠呈現(xiàn)一個(gè)樹(shù)形目錄結(jié)構(gòu),方便閱讀和搜索;

 

好了,大概就這8個(gè)特性吧,下面請(qǐng)看我們是如何完成的。

2、我們自創(chuàng)的API文檔服務(wù)框架核心工作原理

首先請(qǐng)看簡(jiǎn)易框架示意圖:

 

 

這個(gè)框架搭建起來(lái)并不復(fù)雜,甚至可以說(shuō)是很簡(jiǎn)單的。所用到的技術(shù)和工具如下:

(1)使用JavaScript作為API文檔源文件的編寫(xiě)語(yǔ)言;

(2)使用任何支持JavaScript的IDE作為API文檔編寫(xiě)工具,我們團(tuán)隊(duì)使用intellij idea;

(3)使用SVN服務(wù)器作為版本管理工具,用來(lái)管理API版本;

(4)WEB服務(wù)器可以隨便使用哪個(gè)框架搭建。

 

核心工作原理(4步):

 

1、獲取JS目錄結(jié)構(gòu)。當(dāng)用戶(hù)在瀏覽器中輸入API文檔服務(wù)地址(如:http://api.some-domain.com)時(shí),WEB服務(wù)器根據(jù)事先配置好的SVN地址和賬戶(hù)信息,從SVN服務(wù)器獲取JS文件(即API定義源文件)目錄,然后WEB服務(wù)器將這些JS文件的樹(shù)形目錄響應(yīng)到瀏覽器(非JS文件內(nèi)容,僅僅是JS目錄結(jié)構(gòu)),后面當(dāng)用戶(hù)點(diǎn)擊某個(gè)JS文件名稱(chēng)時(shí),才會(huì)加載相應(yīng)JS文件內(nèi)容,這樣即使當(dāng)API文檔增加至上萬(wàn)個(gè),也不會(huì)太大影響加載速度。

 

2、加載apiHelper.js文件。在上一步響應(yīng)完成后,頁(yè)面會(huì)通過(guò)script標(biāo)簽加載一個(gè)特別重要的apiHelper.js 文件。這個(gè)JS文件是做什么的呢?它會(huì)極大的簡(jiǎn)化我們編寫(xiě)API文檔的語(yǔ)法!首先,這個(gè)文件在window下面定義了一個(gè)apiHelper對(duì)象,這個(gè)對(duì)象用來(lái)封裝大量的靜態(tài)方法,這些靜態(tài)方法主要是用于定義API文檔數(shù)據(jù)結(jié)構(gòu)的,比如apiHelper.response.page(object)方法將會(huì)直接根據(jù)object對(duì)象生成分頁(yè)響應(yīng)數(shù)據(jù)結(jié)構(gòu)。

 

3、加載單個(gè)API。當(dāng)用戶(hù)點(diǎn)擊某個(gè)API時(shí),頁(yè)面會(huì)動(dòng)態(tài)將該JS文件加載到瀏覽器并且執(zhí)行。那么這個(gè)JS的API文件到底執(zhí)行了什么代碼呢?其實(shí)很簡(jiǎn)單,我們的每個(gè)JS API文件都在window下面定義了一個(gè)api對(duì)象(當(dāng)然,是按照一定數(shù)據(jù)結(jié)構(gòu)定義的對(duì)象),當(dāng)這個(gè)JS文件執(zhí)行完成后,當(dāng)前頁(yè)面的下的window.api對(duì)象已經(jīng)被更新了,這時(shí)我們只需要調(diào)一個(gè)render()方法,將此window.api對(duì)象用HTML呈現(xiàn)出來(lái)即可。在呈現(xiàn)window.api對(duì)象的render方法中,我們充分利用JS這門(mén)語(yǔ)言的動(dòng)態(tài)性及其反射機(jī)制,從而極大的簡(jiǎn)化了API文檔的定義。

 

4、查看單個(gè)API的歷史版本。在加載完單個(gè)API的JS文件后,我們可以通過(guò)SVN查找該JS文件的修改記錄,然后呈現(xiàn)一個(gè)revision記錄列表,點(diǎn)擊每一個(gè)revision即可加載曾經(jīng)某個(gè)版本的JS,這時(shí)window.api對(duì)象已經(jīng)被替換成了歷史版本,這時(shí)我們只需要再次調(diào)用之前的render方法,將這個(gè)window.api對(duì)象重新呈現(xiàn)出來(lái)即可,這樣就可完成快速版本切換和智能對(duì)比。

 

以上就是我們這個(gè)API框架的核心工作原理了,是不是非常簡(jiǎn)單呢!如果你擁有豐富的軟件架構(gòu)經(jīng)驗(yàn),相信讀到這里你已經(jīng)完全明白我們的思路并可以搭建一套類(lèi)似的API文檔服務(wù)框架了。但是可能對(duì)于大多數(shù)讀者來(lái)說(shuō),讀到這里還是有些云里霧里。別擔(dān)心,接下來(lái)筆者將會(huì)以我們項(xiàng)目中的一個(gè)API文檔為例,結(jié)合界面和代碼對(duì)核心原理進(jìn)行闡述。

 

首先請(qǐng)看我們某個(gè)API的閱讀界面(包含4個(gè)tab的一個(gè)網(wǎng)頁(yè)):

 

 

 

 

 

以上4張圖片分別是我們某個(gè)API文檔的請(qǐng)求、響應(yīng)、請(qǐng)求示例和響應(yīng)示例的定義文檔。這個(gè)文檔就是通過(guò)對(duì)window.api對(duì)象進(jìn)行解析得到的。別看這個(gè)文檔定義的內(nèi)容這么多,但這個(gè)API的源文件卻是非常簡(jiǎn)單的,請(qǐng)看下圖:

 

 

數(shù)一數(shù),大概只有二十多行代碼就完成了一個(gè)這么復(fù)雜的API的定義!這全都得歸功于JavaScript這門(mén)動(dòng)態(tài)語(yǔ)言的強(qiáng)大!

 

如果你仔細(xì)閱讀上方的API源文件,你可能會(huì)發(fā)現(xiàn)我們定義了很多特殊語(yǔ)法,比如下劃線(xiàn)“_”屬性代表當(dāng)前對(duì)象的整體說(shuō)明,而api對(duì)象下面的POST屬性則同時(shí)定義了http method和請(qǐng)求URL。還有apiHelper.p()方法可以將一個(gè)請(qǐng)求/響應(yīng)字段的定義放在一行代碼里面,其4個(gè)參數(shù)分別是:數(shù)據(jù)類(lèi)型、是否可空(字符串哦)、示例數(shù)據(jù)(不僅僅支持string哦)和字段說(shuō)明。這個(gè)JS文件執(zhí)行后的最終效果就是定義window.api對(duì)象,然后瀏覽器加載完該JS后,我們的render()方法就可以將其呈現(xiàn)出來(lái)了。

 

下面,我們到瀏覽器的控制臺(tái)中來(lái)看看實(shí)際的window.api對(duì)象是長(zhǎng)什么樣子吧:

 

 

可以看出,這個(gè)window.api對(duì)象實(shí)際上是非常復(fù)雜的,之所以我們的API源文件這么簡(jiǎn)單,那是因?yàn)閍piHelper.js做了大量的事情,從而簡(jiǎn)化了API的編寫(xiě)。這就是一個(gè)架構(gòu)師該做的事情:將盡可能多的事情交給框架來(lái)完成,在保證可擴(kuò)展性的前提下,讓開(kāi)發(fā)人員寫(xiě)盡量少的代碼就可以完成工作。

 

最后,似乎就只差網(wǎng)頁(yè)中的render()方法了,但是筆者并不打算將其呈現(xiàn)在本文中,因?yàn)樗娴暮芎?jiǎn)單了并且已經(jīng)遠(yuǎn)離了本文的主旨。如果基于上文的信息你還無(wú)法完成render()方法的編寫(xiě),那么你可以使用我們現(xiàn)成的解決方案(加jframe官方QQ群了解吧:651499479)。

 

最終,我們的API文檔服務(wù)框架完全實(shí)現(xiàn)了我們最初的期望:

(1)API文檔編寫(xiě)語(yǔ)法超級(jí)簡(jiǎn)單,可擴(kuò)展性強(qiáng);

(2)非常容易編寫(xiě)真實(shí)的請(qǐng)求和響應(yīng)示例;

(3)非常容易編寫(xiě)JSON格式的數(shù)據(jù);

(4)發(fā)布API文檔超級(jí)簡(jiǎn)單:提交SVN即可;                       

(5)API文檔的源文件完全獨(dú)立于項(xiàng)目源碼;

(6)修改API文檔將自動(dòng)創(chuàng)建版本歷史記錄,在網(wǎng)頁(yè)中可以非常容易的查看/對(duì)比歷史版本;

(7)通過(guò)WEB瀏覽器訪(fǎng)問(wèn);

(8)API數(shù)量達(dá)到成千上萬(wàn)的時(shí)候,能夠呈現(xiàn)一個(gè)樹(shù)形目錄結(jié)構(gòu),方便閱讀和搜索;

 

到此為止,我們的API文檔服務(wù)框架已經(jīng)介紹完畢。篇幅有點(diǎn)長(zhǎng),那是因?yàn)楣P者認(rèn)為API文檔框架確實(shí)是前后端分離過(guò)程中最重要的一個(gè)環(huán)節(jié),因?yàn)橄啾群蠖丝蚣芑蛘咔岸丝蚣?,API文檔框架不確定性因素更大,基于現(xiàn)有的開(kāi)源項(xiàng)目很難完成高質(zhì)量的API文檔框架,而不像前端或后端框架搭建過(guò)程中成熟的方案很多,完成高質(zhì)量前端和后端框架相對(duì)容易很多。

 

第四章   我們的前后端分離框架詳解

我們的前后端分離框架主要采用了如下技術(shù):

(1)使用VueJs作為前端模板引擎;

(2)使用jQuery以及我們多年積累的JS控件作為DOM操作函數(shù)庫(kù);

(3)后端采用java體系的spring MVC返回HTML。

 

接下來(lái)筆者將會(huì)解釋我們?yōu)槭裁磿?huì)選擇這些技術(shù)。

 

1、筆者對(duì)VueJs的理解

首先,筆者相信很多人對(duì)VueJs或者react到底有什么用都不是很清楚的,因?yàn)樗麄兊墓俜骄W(wǎng)站講述了很多的特性,以致讓我們分不清楚VueJs的本職工作是什么。筆者在權(quán)衡VueJs和react的過(guò)程中,也感到非常的困惑。因?yàn)榘凑誚ueJs官網(wǎng)的介紹,似乎我應(yīng)該建立以.vue文件為主的項(xiàng)目工程,然后通過(guò)編譯器將其編譯成html、css和js。并且VueJs官網(wǎng)還大量介紹了基于NodeJs的Vue服務(wù)端渲染、Vue Ruoter、Vue Loader、規(guī)?;?,以及打包工具webpack等??瓷先ミ@是一套全新的、完整的、包含服務(wù)器端的前端開(kāi)發(fā)框架。

 

我相信Vue官網(wǎng)介紹的確實(shí)是一套全新的、完整的前端開(kāi)發(fā)框架。但是,在筆者看來(lái)這套框架并不是最好的前端開(kāi)發(fā)框架。對(duì)于一個(gè)不懂服務(wù)器后端架構(gòu)的前端開(kāi)發(fā)人員來(lái)講,使用NodeJs搭建WEB服務(wù)器確實(shí)是一個(gè)最優(yōu)的選擇,因?yàn)镹odeJs比java、.NET簡(jiǎn)單太多了,我相信Vue官網(wǎng)也是基于這個(gè)原因才對(duì)服務(wù)器端解決方案做了大量的介入。

 

然而我們團(tuán)隊(duì)有非常成熟的java服務(wù)器后端框架,只需要增加幾行代碼即可完成Vue官方所介紹的那一堆堆特性。筆者也是把Vue官網(wǎng)上面介紹的這些服務(wù)端方案讀了很久,才明白Vue官網(wǎng)的真正意圖,并且最終明白,Vue官網(wǎng)所描述的架構(gòu)還沒(méi)有基于我們的java服務(wù)端增加幾行代碼所得到的架構(gòu)好。

 

這是筆者在閱讀Vue官網(wǎng)時(shí)遇到的最大的一個(gè)困惑。后面最終決定:我們只把Vue當(dāng)做一個(gè)HTML模板引擎,這才是Vue的本職工作。

 

這個(gè)決定下的并不容易,因?yàn)檫@會(huì)讓我們的框架看上去不那么新潮。因?yàn)閂ue官網(wǎng)上介紹的知識(shí),除了把Vue當(dāng)做模板引擎的知識(shí)外,其他知識(shí)我們一點(diǎn)都沒(méi)有用得上。

 

Vue官網(wǎng)上還有一個(gè)隱形的基礎(chǔ)認(rèn)識(shí)沒(méi)有介紹清楚,因?yàn)楣P者發(fā)現(xiàn),Vue官網(wǎng)上幾乎全部的知識(shí)都是基于SPA(單頁(yè)應(yīng)用)這個(gè)框架下進(jìn)行描述的,包括webpack、Vue Ruoter等。但是我們的系統(tǒng)是非常龐大又復(fù)雜的,根本不可能用SPA架構(gòu)。關(guān)于這一點(diǎn),筆者也是讀了很久才發(fā)現(xiàn),Vue官網(wǎng)的默認(rèn)設(shè)定場(chǎng)景就是SPA架構(gòu)。

 

2、為什么我們會(huì)選擇VueJs?

前后端分離之后,前端工程師需要將通過(guò)API獲取的數(shù)據(jù)呈現(xiàn)到頁(yè)面上,雖然也可以通過(guò)jQuery對(duì)頁(yè)面一個(gè)一個(gè)賦值,但是這種效率太低了,或者也可通過(guò)在JavaScript中拼接HTML,但是這種方式太難維護(hù)HTML代碼了,也很難閱讀。因此最好的方式就是使用模板引擎。

 

前端的模板引擎跟后端模板引擎很相似,比如JSP或cshtml(razor),他們的語(yǔ)法都非常相似,他們所實(shí)現(xiàn)的功能也幾乎一樣:將數(shù)據(jù)綁定到HTML模板。VueJs和react都可以充當(dāng)這樣的模板引擎。我們最終沒(méi)有選用react而是選用了VueJs的原因只有一個(gè),那就是VueJs是真正的響應(yīng)式,而react改變model之后需要手工調(diào)用setState才會(huì)更新UI,這是完全無(wú)法忍受的。

 

因?yàn)檫@個(gè)原因,我們只能選擇VueJS作為模板引擎。

 

3、我們的前端框架的工作原理

雖然本文寫(xiě)的有點(diǎn)長(zhǎng),但我們的前端框架卻是非常簡(jiǎn)單的,這也是我們?yōu)槭裁床贿x擇采用.vue文件構(gòu)建工程的原因,因?yàn)槟翘珡?fù)雜了。

 

核心工作原理:

 

(1)定義頁(yè)面URL格式。我們每個(gè)頁(yè)面的地址格式大概長(zhǎng)這樣:http://www.your-domain.com/admin#home/index。admin代表模塊名稱(chēng),#后面的home代表子模塊對(duì)應(yīng)controller,而index對(duì)應(yīng)controller里面的方法。所以當(dāng)在同一個(gè)模塊中切換頁(yè)面的時(shí)候,只會(huì)改變地址的hash值,瀏覽器不會(huì)進(jìn)行跳轉(zhuǎn)。但是當(dāng)切換頁(yè)面之后,如果用戶(hù)點(diǎn)擊瀏覽器的刷新按鈕,框架能夠根據(jù)hash值加載當(dāng)前頁(yè)面。

 

(2)根據(jù)URL加載layout.html。當(dāng)服務(wù)器收到“/admin#home/index”地址的請(qǐng)求時(shí),不管后面的hash值為多少,直接返回一個(gè)layout.html。該layout.html文件包含頁(yè)面的基本框架,比如公共js、css頁(yè)面、導(dǎo)航、footer等公共元素。

 

(3)初始化layoutVue。Layout.html加載完成之后,其中的JS會(huì)根據(jù)layout.html的HTML結(jié)構(gòu)生成一個(gè)Vue實(shí)例,并將layout.html下面的全部動(dòng)態(tài)HTML交給該Vue實(shí)例托管,比如根據(jù)用戶(hù)角色顯示相應(yīng)的導(dǎo)航菜單,在頁(yè)面header顯示用戶(hù)個(gè)人信息等。

 

(4)根據(jù)location.hash通過(guò)jQuery ajax加載相應(yīng)的內(nèi)容HTML文件。這時(shí)我們會(huì)在服務(wù)器端定義另一個(gè)接口,根據(jù)內(nèi)容頁(yè)的路徑返回對(duì)于的html代碼。

比如:GET /admin/getPage?path=home/index。

 

內(nèi)容頁(yè)的html除了返回html代碼之外,還會(huì)包含該頁(yè)面所需的JS和CSS。這樣,當(dāng)內(nèi)容頁(yè)的html呈現(xiàn)到layout中的某個(gè)容器div中后,內(nèi)容頁(yè)的JS就會(huì)被加載并執(zhí)行。那么內(nèi)容頁(yè)的JS都有些什么邏輯呢?當(dāng)然是初始化內(nèi)容頁(yè)的Vue實(shí)例并接管內(nèi)容頁(yè)的動(dòng)態(tài)html生成工作。

 

以上4個(gè)步驟可以用下圖簡(jiǎn)單表示:

 

 

讀到這里,如果你對(duì)軟件架構(gòu)很有經(jīng)驗(yàn),那么相信你已經(jīng)完全明白了我們的前后端分離框架的工作原理了,你也應(yīng)該可以按照本文的思路完成你自己的前后端分離框架了。但是對(duì)于大多數(shù)讀者來(lái)說(shuō),可能讀到這里只是大概明白怎么回事,如果說(shuō)要自己動(dòng)手開(kāi)始搭建,可能就會(huì)面臨無(wú)從下手的尷尬了。不用擔(dān)心,接下來(lái)筆者就以我們的框架為例,一步一步通過(guò)代碼來(lái)展示我們框架的搭建過(guò)程。

 

4、一步一步搭建我們的前端框架

(1)頁(yè)面地址生成。服務(wù)器根據(jù)同步請(qǐng)求URL(/pe#home/index…)響應(yīng)一個(gè)layout.html. 請(qǐng)看java源碼:

 

上圖中的java代碼就是我們前端框架中全部的后端處理代碼了(請(qǐng)仔細(xì)讀這句話(huà),有點(diǎn)繞哈),是不是非常簡(jiǎn)單呢?雖然簡(jiǎn)單,但是功能卻是很強(qiáng)大的。從上面的代碼中可以看出:

 

a. 只要是以“/pe#”開(kāi)頭的URL,服務(wù)器將直接返回某個(gè)目錄下的layout.html頁(yè)面;

 

b. 前端開(kāi)發(fā)人員可以在“/modules/pe/views/”下面隨便建立目錄、子目錄以及HTML文件,然后即可通過(guò)ajax請(qǐng)求類(lèi)似“/pe/page?path=home/index”這樣的URL直接加載下面的HTML文件,這樣前端開(kāi)發(fā)人員不需要?jiǎng)右恍泻蠖舜a,只需要按照約定建立目錄和HTML文件就可以在瀏覽器中加載出來(lái)。這樣,前端開(kāi)發(fā)人員就完全不需要依賴(lài)后端開(kāi)發(fā)人員來(lái)獲得頁(yè)面地址了,前端開(kāi)發(fā)人員自己就可以創(chuàng)建頁(yè)面地址!

 

上面的java代碼中,還可以將同步請(qǐng)求跟異步請(qǐng)求合并成一個(gè)(@GetMapping(“/pe/*”)),然后在方法內(nèi)部判斷是否是同步請(qǐng)求,如果是同步請(qǐng)求就返回layout.html,否則返回內(nèi)容頁(yè)。這樣做就不是監(jiān)聽(tīng)hash變化了,而是每個(gè)URL地址都看上去像一個(gè)同步請(qǐng)求地址,如“/pe/home/index”的URL進(jìn)入服務(wù)器后,服務(wù)器首先返回layout.html,然后layout.html再發(fā)起ajax請(qǐng)求“/pe/home/index”這時(shí)服務(wù)器返回內(nèi)容頁(yè)HTML。在我們項(xiàng)目中,我們更愿意使用監(jiān)聽(tīng)hash變化的方式。當(dāng)然筆者認(rèn)為這兩種方式都是OK的,如果后期想切換也是比較容易的。

 

(2)layout.html。 下面讓我們來(lái)看看服務(wù)器首先返回的layout.html大概長(zhǎng)什么樣子,請(qǐng)看下圖:

 

這個(gè)HTML文件就是服務(wù)器的同步響應(yīng)內(nèi)容,也是我們每一個(gè)頁(yè)面的入口。這時(shí)我們需要把一個(gè)網(wǎng)頁(yè)理解成一個(gè)應(yīng)用(APP),而這個(gè)layout.html只定義APP啟動(dòng)入口和框架??梢钥吹皆撐募昧嘶镜腸ss和js,其最后的core.js內(nèi)部完成了這個(gè)APP的初始化。下面我們來(lái)看看這個(gè)core.js內(nèi)部的主要部分代碼。

 

(3)core.js。完成APP初始化的代碼如下:

 上面的示例代碼是筆者為了本文精簡(jiǎn)過(guò)的,實(shí)際上這個(gè)JS文件在完成APP初始化的過(guò)程中還做了很多的操作,比如獲取用戶(hù)登錄信息、獲取頁(yè)面動(dòng)態(tài)導(dǎo)航菜單數(shù)據(jù)等,然后將獲取的數(shù)據(jù)通過(guò)一個(gè)layoutVue實(shí)例呈現(xiàn)到頁(yè)面上,從而layoutVue實(shí)例完全接管layout.html中全部的HTML呈現(xiàn)工作。

 

在APP初始化的最后一步,就是根據(jù)URL #后面的路徑加載內(nèi)容頁(yè)HTML到一個(gè)id為body的DIV中了。服務(wù)器如何異步響應(yīng)URL(/pe/page?path=home/index),請(qǐng)參考本章第一小節(jié)中的異步請(qǐng)求java源碼(pePage方法)。

 

(4)內(nèi)容頁(yè)HTML。請(qǐng)看ajax加載的內(nèi)容頁(yè)的HTML:

 

從上方代碼可以看出,每個(gè)內(nèi)容頁(yè)對(duì)應(yīng)一個(gè)js和一個(gè)css文件,然后html代碼以一個(gè)id為page的DIV開(kāi)始。當(dāng)然,這些都不是必須的,只是我們的項(xiàng)目規(guī)范,當(dāng)然,筆者也建議大家可以參考我們的規(guī)范。

 

當(dāng)內(nèi)容頁(yè)HTML加載完成后,就會(huì)執(zhí)行其引用的js文件了。接下來(lái)就讓我們來(lái)看看內(nèi)容頁(yè)的JS代碼。

 

(5)內(nèi)容頁(yè)JS代碼。請(qǐng)看下圖:

 

 

這個(gè)JS文件首先是由一個(gè)自執(zhí)行函數(shù)包裹,好處是避免不經(jīng)意將對(duì)象定義到window下面(編碼開(kāi)發(fā)人員寫(xiě)出錯(cuò)誤的代碼),這也是我們的規(guī)范之一,實(shí)際上我們項(xiàng)目的所有JS文件都由自執(zhí)行函數(shù)包裹。

 

上方代碼的主入口是Vue.nextTick方法的回調(diào)function。Vue.nextTick是一個(gè)非常重要的方法,但是官網(wǎng)上并沒(méi)有給他一個(gè)特別明顯的位置,因此筆者要在此多說(shuō)兩句,這個(gè)方法有什么用。這得要回到Vue的render機(jī)制了。當(dāng)Vue實(shí)例發(fā)現(xiàn)綁定的數(shù)據(jù)改變之后,Vue采用了異步更新UI元素的方式,因此,當(dāng)我們修改了數(shù)據(jù)的時(shí)候,這時(shí)DOM元素還沒(méi)有生成出來(lái),如果這時(shí)去操作DOM(比如通過(guò)jQuery),那么就會(huì)報(bào)找不到該DOM元素,所以一定要在改變Vue數(shù)據(jù)后使用Vue.nextTick去操作其影響的DOM元素。

 

再回到上方代碼。在Vue.nextTick回調(diào)中,首先是初始化內(nèi)容頁(yè)的Vue實(shí)例,從而接管id為page的div及其下的所有DOM元素的呈現(xiàn)工作。

 

至此,一個(gè)完整的頁(yè)面就算加載完成了,用戶(hù)在瀏覽器中就能看到這個(gè)完整的頁(yè)面了。

 

這就是我們前后端分離框架的整個(gè)工作流程,希望筆者已經(jīng)把這個(gè)流程解釋的足夠清晰,然后你可以開(kāi)始動(dòng)手搭建自己的前后端分離框架了。但是在你真正開(kāi)始之前,筆者還想跟大家分享一個(gè)我們前后端分離的最佳實(shí)踐:mock,請(qǐng)看下一章。

 

第五章 前后端分離框架中的API mock思路

想要實(shí)現(xiàn)真正的前后端分離,那就必須得用好API mock(模擬數(shù)據(jù))。使用mock數(shù)據(jù)的好處有兩個(gè):

(1)前端開(kāi)發(fā)人員可以基于API文檔生成mock數(shù)據(jù),在后端開(kāi)發(fā)人員將API發(fā)布出來(lái)之前就可以完成整個(gè)業(yè)務(wù)流程的開(kāi)發(fā);

(2)使用mock數(shù)據(jù)能夠更低成本、更快速地,通過(guò)直接修改mock數(shù)據(jù)的方式,調(diào)試頁(yè)面樣式、調(diào)試頁(yè)面功能。

 

在本文中,筆者不會(huì)給大家推薦任何mock框架,因?yàn)槲覀兏居貌恢何覀円眉兪止ぴ鞌?shù)據(jù)的方式造出更真實(shí)的mock數(shù)據(jù)。

 

我們前后端分離框架中需要用到mock數(shù)據(jù)的地方,主要就是API,因此其他使用場(chǎng)景(如硬件mock、第三方系統(tǒng)API)本文不做示例介紹,因?yàn)槠鋗ock思路其實(shí)是一樣的。

 

1、全局mock開(kāi)關(guān)

 

API的mock數(shù)據(jù)主要分為兩種,一種是零散的、手工發(fā)起的ajax API請(qǐng)求;另一種是被封裝到控件內(nèi)部的ajax API請(qǐng)求。不管是哪一種mock,首先我們?cè)诿總€(gè)頁(yè)面都會(huì)加載的core.js里面定義了一個(gè)全局的mock開(kāi)關(guān):mvcApp.mock = true/false,然后在頁(yè)面加載完成后,判斷如果設(shè)置mock==true,則提示用戶(hù)/開(kāi)發(fā)者當(dāng)前使用的是mock數(shù)據(jù)!

 

 為什么要設(shè)置這樣一個(gè)全局的mock開(kāi)關(guān)呢?主要基于以下兩點(diǎn)考慮:

(1)設(shè)置全局的mock開(kāi)關(guān)之后就不再需要針對(duì)每一個(gè)頁(yè)面設(shè)置mock開(kāi)關(guān),更容易維護(hù),避免項(xiàng)目中有多個(gè)mock開(kāi)關(guān)而難以統(tǒng)一開(kāi)關(guān)狀態(tài);

(2)如果發(fā)布時(shí)忘記將mock開(kāi)關(guān)給關(guān)掉,那么發(fā)布之后一運(yùn)行發(fā)布者就會(huì)發(fā)現(xiàn)mock開(kāi)關(guān)忘了關(guān),然后可以快速修復(fù)之后再重新發(fā)布,從而避免不小心將正式服更新為mock數(shù)據(jù)源。

 

正是由于以上兩點(diǎn)考慮,我們的全局mock開(kāi)關(guān)可以幫助程序開(kāi)發(fā)者和發(fā)布者更不容易犯錯(cuò)。

 

下面筆者將會(huì)給大家展現(xiàn)全局的mock開(kāi)關(guān)如何跟頁(yè)面API配合,從而完成整個(gè)站點(diǎn)的mock狀態(tài)控制。

 

2、普通API的mock

在我們的前端框架中,我們使用了grunt來(lái)將整個(gè)頁(yè)面的全部JS文件打包成一個(gè)JS文件,因此,在我們的前端框架中,每個(gè)頁(yè)面對(duì)應(yīng)一個(gè)JS源文件的文件夾,在打包的時(shí)候,grunt會(huì)將該文件夾中的全部JS文件合并打包(發(fā)布到生產(chǎn)環(huán)境時(shí)將執(zhí)行壓縮混淆)。下圖所展示的是我們admin端的一個(gè)列表頁(yè)面所對(duì)應(yīng)的的JS源文件目錄(index文件夾):

 

 可以看到該文件夾下面的第一個(gè)JS文件叫01.page.js,這個(gè)JS是整個(gè)頁(yè)面的入口,包括定義了頁(yè)面全部的配置(比如用到的ajax URL)。第2個(gè)文件是02.api.js文件,該文件包含了所有的ajax請(qǐng)求。我們把全部的ajax請(qǐng)求封裝到這個(gè)文件中,也是為了更好的mock。

 

下面就讓我們來(lái)看這個(gè)02.api.js大概長(zhǎng)什么樣子吧:

 

 

從上面的代碼中可以看到,我們定義了page.api這個(gè)對(duì)象兩次,而中間有一個(gè)if判斷,那就是判斷我們?nèi)值膍ock開(kāi)關(guān)是否處于開(kāi)啟中,如果mock開(kāi)啟,則不會(huì)執(zhí)行return而會(huì)繼續(xù)第二段page.api對(duì)象賦值的代碼,這樣第一段代碼定義的page.api對(duì)象就被覆蓋了,于是這個(gè)頁(yè)面中的其他JS文件就將使用mock的數(shù)據(jù)。如果全局的mock開(kāi)關(guān)處于關(guān)閉狀態(tài),那么第一段page.api對(duì)象賦值代碼執(zhí)行完成之后,就會(huì)調(diào)用if下面的return語(yǔ)句了,這樣就不會(huì)執(zhí)行第二段page.api對(duì)象賦值,于是這個(gè)頁(yè)面的其他JS文件就將使用真實(shí)數(shù)據(jù)。

 

這就是全局mock開(kāi)關(guān)在頁(yè)面中的應(yīng)用,使用方法簡(jiǎn)單而靈活。這樣,前端開(kāi)發(fā)人員就可以在API開(kāi)發(fā)出來(lái)之前通過(guò)mock的API完成樣式和交互。

 

3、以Grid控件為例的控件級(jí)mock

在WEB前端開(kāi)發(fā)過(guò)程中,一定會(huì)用到大量的控件(UI組件)。如果這個(gè)控件(比如Grid)內(nèi)部封裝了ajax請(qǐng)求,那么其ajax的mock操作就很難通過(guò)上一小節(jié)中的mock方法實(shí)現(xiàn)。

 

下面,筆者就將以我們項(xiàng)目的Grid控件為例,給大家詳細(xì)闡述我們的改造過(guò)程。

 

由于我們項(xiàng)目中的Grid控件是我們自己開(kāi)發(fā)的,雖然只有300行代碼,但是功能很強(qiáng)大,可定制性很高。因此,要改造我們的Grid就變得很容易了。

 

首先,我們定義了一個(gè)VueGrid類(lèi)繼承自Grid類(lèi),然后重寫(xiě)了其loadData這個(gè)ajax方法,請(qǐng)看下圖:

 

 

改造之后的VueGrid類(lèi)多了一個(gè)getMockDataFunction這個(gè)屬性,在loadData方法中,首先判斷該grid實(shí)例是否設(shè)置了getMockDataFunction屬性,如果設(shè)置了再判斷getMockDataFunction方法的返回值是否為空,如果返回值為空則也使用真實(shí)數(shù)據(jù),因此使用mock數(shù)據(jù)的條件是很苛刻的:必須設(shè)置getMockDataFunction屬性并且其返回值不能為null。

 

然后我們?cè)赩ueGrid類(lèi)中還公開(kāi)了一個(gè)設(shè)置getMockDataFunction屬性的方法,如下圖:

 

 

在初始化Grid和Vue的頁(yè)面JS中(01.page.js),我們像下方代碼這樣使用:

 

 

在上方代碼中初始化VueGrid實(shí)例時(shí),設(shè)置了mock數(shù)據(jù)源為page.api.mockSearchList這個(gè)方法。我們可以通過(guò)全局的mock開(kāi)關(guān)控制page.api.mockSearchList這個(gè)方法是否為null從而控制該grid是否使用mock數(shù)據(jù)。

 

請(qǐng)看02.api.js中的代碼:

 

 

上方代碼中,如果mvcApp.mock被設(shè)置為了false,那么page.api.mockSearchList就不會(huì)被定義,也就是undefined(null);如果mvcApp.mock被設(shè)置為了true,那么page.api.mockSearchList才會(huì)被賦值,這時(shí)grid將使用mock數(shù)據(jù)。

 

最后,為了方便大家理解整個(gè)Grid控件的使用過(guò)程,筆者再給大家看看我們自己寫(xiě)的VueGrid的html端的代碼,很簡(jiǎn)單,很靈活,支持排序、分頁(yè),支持JSON和HTML兩種數(shù)據(jù)格式:

 

 

至此,我們的Grid控件的mock改造就已經(jīng)完全完成了。改造后實(shí)現(xiàn)的效果:不需要修改01.page.js,不需要VueGrid.js,也不需要修改02.api.js,只需要修改mvcApp.mock的值就可以切換是否使用mock數(shù)據(jù)。

 

這樣,我們mock開(kāi)關(guān)的狀態(tài)控制就非常的簡(jiǎn)單,并且,最關(guān)鍵的是,不容易出錯(cuò)!

 

第六章   結(jié)語(yǔ)

最后,筆者再帶大家回顧一下本文中的提到的一些關(guān)鍵技術(shù)、觀(guān)點(diǎn)和看法:

 

(1)前后端分離最關(guān)鍵的環(huán)節(jié)是API文檔服務(wù)框架,沒(méi)有一個(gè)好的API文檔服務(wù)做支撐,前后端分離之路舉步維艱。筆者建議大家按照本文提供的思路自行搭建,或者考慮使用我們現(xiàn)成的框架;

 

(2)VueJs官網(wǎng)介紹的規(guī)?;軜?gòu)方案并不一定是最好的,如果你們團(tuán)隊(duì)擁有后端架構(gòu)師,筆者建議僅僅把VueJs當(dāng)做HTML模板引擎即可,至于VueJs官網(wǎng)描述的其他特性可以忽略;

 

(3)VueJs的異步渲染是一個(gè)非常重要的知識(shí)點(diǎn),但是VueJs官網(wǎng)并沒(méi)有將之置于顯眼的地方,因此一定要熟練掌握Vue.nextTick方法及其工作原理;

 

(4)VueJs是完全可以和其他第三方框架/庫(kù)兼容的,關(guān)鍵是要掌握其工作原理,比如我們項(xiàng)目中VueJs就很好地與jQuery、jQueryUI以及我們自己的JS控件庫(kù)交互,雖然VueJs官網(wǎng)建議DOM操作全部交由VueJs接管,但筆者仍然建議很多時(shí)候用jQuery操作DOM更有優(yōu)勢(shì),因?yàn)閖Query的封裝性更好(比如我們的Grid控件,之所以使用起來(lái)很簡(jiǎn)單,那是因?yàn)閮?nèi)部通過(guò)jQuery封裝了很多操作);

 

(5)真正的前后端分離一定離不開(kāi)mock,不要覺(jué)得mock是一個(gè)多么復(fù)雜多么高深的東西,在筆者看來(lái),mock僅僅是一種思想,你只要明白其核心思想,自己寫(xiě)出的mock框架才是最好用的;

 

(6)前后端分離,如果做好了,利遠(yuǎn)大于弊。從我們團(tuán)隊(duì)實(shí)施分離之后的這段時(shí)間來(lái)看,其對(duì)團(tuán)隊(duì)的正面影響非常明顯;從長(zhǎng)遠(yuǎn)來(lái)看,前后端分離促進(jìn)社會(huì)分工,讓公司的人才培養(yǎng)之路更加清晰,更加高效,更加具有競(jìng)爭(zhēng)力。

 

(完)

posted @ 2018-04-26 22:17 Leo C.W Views(7650) Comments(14) Edit 收藏

Post Comment
#1樓 2018-04-27 09:11 | geek_power  
看了1/4,有2個(gè)疑問(wèn):1.后端發(fā)布出來(lái)的api也受源代碼管理工具管理,并不存在后端偷偷修改代碼沒(méi)有記錄的情況。2.你的這種方案api文檔修改后通知不到位,同樣會(huì)出現(xiàn)開(kāi)發(fā)人員不知道的情況,用swagger反而更效率,api層也可以做代碼寫(xiě)權(quán)限控制只讓架構(gòu)師或PM或其他有權(quán)限的人來(lái)做。

佩服樓主鉆研精神,點(diǎn)了個(gè)推薦。

#2樓 2018-04-27 09:26 | 史亞健  
總的來(lái)說(shuō),文章的觀(guān)點(diǎn)很明確,有自己的想法,也做出的相應(yīng)的決策。 但是個(gè)人觀(guān)點(diǎn),還是沒(méi)有達(dá)到完全意義前后分離,我初步觀(guān)察作者應(yīng)該是后臺(tái)出身,對(duì)VUE的理解的有點(diǎn)偏移,使用方式不對(duì)。 而且前后分離中,后臺(tái)的服務(wù)治理或者微服務(wù)化沒(méi)有什么提及,前后分離和這兩個(gè)有密不可分的聯(lián)系。個(gè)人薄見(jiàn)

#3樓 2018-04-27 21:19 | 多寶道人  
前端nodejs,傳輸json+token,后端給出api
很好的前后端分離

#4樓 2018-04-27 21:51 | redfox105  
vuejs用法不對(duì)呢,真要前后端分離,后端只返回JSON格式的數(shù)據(jù),不要返回HTML了。

#5樓 2018-04-28 11:29 | Maxima-Go  
剛那種其員工mock數(shù)據(jù)的方式如果只是案例說(shuō)明沒(méi)問(wèn)題。
如果實(shí)際應(yīng)用開(kāi)發(fā)這種模擬數(shù)據(jù)代碼和真實(shí)代碼混在一起不太好。
以后發(fā)布生產(chǎn),模擬數(shù)據(jù)需要?jiǎng)h除,會(huì)很麻煩

#6樓 2018-04-28 11:30 | 大佛腳下  
@史亞健
引用
總的來(lái)說(shuō),文章的觀(guān)點(diǎn)很明確,有自己的想法,也做出的相應(yīng)的決策。 但是個(gè)人觀(guān)點(diǎn),還是沒(méi)有達(dá)到完全意義前后分離,我初步觀(guān)察作者應(yīng)該是后臺(tái)出身,對(duì)VUE的理解的有點(diǎn)偏移,使用方式不對(duì)。 而且前后分離中,后臺(tái)的服務(wù)治理或者微服務(wù)化沒(méi)有什么提及,前后分離和這兩個(gè)有密不可分的聯(lián)系。個(gè)人薄見(jiàn)

同意。同時(shí)給樓主點(diǎn)個(gè)贊

#7樓[樓主] 2018-04-28 11:32 | Leo C.W  
@M-Silencer
全局mock開(kāi)關(guān)設(shè)置在grunt里面就可以解決這個(gè)問(wèn)題啊。本文僅僅是提供一些思路,實(shí)際項(xiàng)目中肯定要靈活應(yīng)變不能照搬的。

#8樓 2018-04-28 13:42 | 婷風(fēng)  
看到這句話(huà),作為一名前端表示不服,,,【前后端不分離的團(tuán)隊(duì),前端工程師都是頁(yè)面仔話(huà)語(yǔ)權(quán)很弱,技術(shù)大牛都在后端,前端相當(dāng)于給后端工程師打雜的;前端工程師晉升機(jī)會(huì)很少,薪資不高,發(fā)展前景渺?!?br>
還有現(xiàn)在打包工具誰(shuí)還用grunt,基本都是webpack,另外從你這頁(yè)面看,根本不叫前后端分離啊,vue搭的項(xiàng)目結(jié)構(gòu)也亂七八槽的,既然用了vue,就要用人家的mvvm思想啊,還搞jquery干啥子?

#9樓 2018-04-28 13:45 | 婷風(fēng)  
還有頁(yè)面切換,走的是router,前端基本都是用es6寫(xiě)法了,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import CapitalInfo from "../components/accountInfo/CapitalInfo.vue"
export default {
    routes: [{
            path: '/',
            name: '首頁(yè)',
            component: Index,
            redirect: '/Index',
            children: [
                { path: "Index", component: Index }
            ]
        },
        {
            path: "/LoginProcxy.html",
            name: "登錄代理",
            component: LoginProcxy,
        }
    ]
}

#10樓 2018-04-28 13:47 | 婷風(fēng)  
看到你們這個(gè)前后端的代碼,想到兩年前,我們就是用這種方式的。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Vue.js 為何能逆襲 Angular 和 React 而主導(dǎo)前端?
Vue 項(xiàng)目架構(gòu)設(shè)計(jì)與工程化實(shí)踐
阿里云云棲社區(qū)聯(lián)合Vue.js完全自學(xué)手冊(cè)第一章
邂逅Vue.js – 初始及安裝
6周學(xué)習(xí)計(jì)劃,攻克JavaScript難關(guān)
Angular、React 和 Vue 三大框架,Web 開(kāi)發(fā)該如何選擇?
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服