摘要:介紹下一個新項目,后端該如何從零去搭建。我們先假設這個項目由兩部組成提供給站點使用的提供給運營人員使用的管理后臺。因此通過回顧,我們得出我們的后端項目需要一個的層次,來存放業務邏輯。
這是 后端開發者從零做一個移動應用 的后端部分第二篇。介紹下一個新項目,后端該如何從零去搭建。我們先假設這個項目由兩部組成
提供給wap站點、app使用的api;
提供給運營人員使用的管理后臺。
整個項目采用 Phalcon,項目的demo可以 點這里 參閱
備注:跟隨文章進度,項目持續更新,最后會與配套的wap app形成一個整體
項目最終至少會包含以下內容:
小米消息推送
支付集成(支付寶、招商、微信)
基于 Codeception 的api測試
登陸api(這部分采用oauth2,會基于 "bshaffer/oauth2-server-php" 做)
項目結構回顧后端系統一般都是采用 MVC 結構(這里均以PHP為例),M 代表模型,V 代表視圖,C 代表控制器。我在啰嗦幾句
Model指的是數據模型,這個數據模型包括你的Mysql中的表結構,或者redis的緩存對象結構都可以。它代表一個數據操作單元。
View指的展示給用戶瀏覽、直接操作的界面,這個大家都懂,不多說
Controller 控制器,主要是為了隔離 View 與 Model 直接打交道,他做為一個中間人,兩頭傳遞小紙條。
在我過往的項目中,我主要的困惑在于,業務邏輯是放在 C 還是放在 M。
從對象角度出發,業務邏輯無非就是操作數據,要么讀取,要么修改,那么應該放在M層,因為一個對象應該有自己的屬性與方法。
業務放在M中實際工作中我們常常有這樣的場景,比如:讀取一個游戲列表數據,數據包括游戲的詳情以及游戲的版本信息以及下載信息。因為游戲app會存在升級,因此一個游戲會對應多個包。那么這里至少存在兩個model
游戲詳情model,包括游戲的名稱,logo等基本信息
游戲的包信息model,包括包所屬平臺,大小,下載地址,版本信息等
那么這個動作的方法應該封裝在哪里呢?以前的做法是,分別封裝對應的操作到對應的model,然后在控制器中分別調用。說回到這里,游戲model封裝了查詢游戲列表的method,然后包model封裝了根據游戲id查詢包信息的method。
然后我們在控制器中分別調用這個兩個方法,然后再進行組裝,把游戲對應的包設置到對應的游戲中。
那么有一個問題,假設我們在游戲詳情這個控制器方法中,需要返回一個相關游戲的集合,難道又重復一次上面的操作?
有人會說把處理游戲部分抽離成一個公共方法,那么假設是要在新聞詳情里邊調用呢?這根本不該在同一個控制器里邊啊!
上面我們把方法放在model中遇到了復用的小麻煩,那么繼續看看放到controller中會怎樣?
這個時候的一個好處是:我們可以使用連接查詢,將剛剛的2次查詢,通過連接查詢1次完成,對于mysql的時間減少了,程序性能提升,然后對查詢結果啪啪啪處理完成。
好吧,不往后面說了,相信大家已經發現了,這個查詢過程還是不可復用。自然而然的,我們這里應該想到,將它提煉成一個方法,無法滿足其他控制器使用(一個控制器調用另外一個控制器的想法想都別想?。?。那么只能提煉成一個類了,這個類來封裝所有的業務。
這樣之后,任何需要游戲列表數據的地方,直接調用這個GameServer(假設封裝的業務邏輯都放在xxxServer中)就可以獲得相同的數據,然后如果業務變動,我們也只需要改動這一處,所有地方得到的數據也將會是一致的。
因此通過回顧,我們得出我們的后端項目需要一個server的層次,來存放業務邏輯。
Server層存在的意義分離出來的這一層,集中涵蓋了所有的業務功能,極大的提高了代碼的復用性,除了不同控制器不同方法的直接使用,還包括了不同模塊之間的復用。
但是在不同模塊之前服用,server層也需要考慮一些額外的東西,比如我們有一個app api模塊,有一個后臺管理模塊。那么都是獲取列表數據,可能給app api模塊可能不需要某些字段,但是后臺管理需要知悉全部內容,以及后臺用戶權限上的一些問題。這些部分可以繼續進行拆分,與server組合。需要結合自己的業務來進行管理。
我個人實踐過程中代碼的另外一個好處是,server層從某種層度上讓C層變得簡單,這讓團隊中的新人能夠快速上手接觸代碼。比如小明是團隊新人,那么在他熟悉所使用框架的前提下,他可以立刻在C層開始做事情,因為這里沒有業務,有的只是驗證客戶端傳過來的數據,以及對server層的調用返回。通過這個過程可以加速其融入團隊的進程。
統一的返回格式約定api返回的數據格式,這基本上是系統開發開始的第一步,原先常用的方式就是在每個控制器中通過
return json_encode([ "msg" => "ok",// 攜帶的信息,可以用來前端 alert 提示用戶 "data" => [// 具體數據 ... ... ], "code" => "0", // 0表示成功,其他表示對應錯誤 ])
那么這里首先遇到的第一個問題,為了簡化前端對類型的判斷,基本上所有的字段值,都是返回字符串形式。那么 data 里邊的內容就需要在每個控制器中進行處理字符串、utf-8編碼等問題。要重復代碼,就算你抽離成一個方法,也需要面對該問題。好點的解決方案是在返回數據的攔截器(每一個框架都有類似的概念)內進行統一的處理。
像上面這樣的代碼寫法,帶來的額外問題可能有,字段名稱打錯,比如: code 寫成 cdoe ,data 寫成 date。為程序代碼額外的風險(尤其是bug修復時最容易出現該情況)
那么一種解決辦法就該由此想到,采用對象的方式來規范化返回的數據結構。比如我們定義一個類:
class ResultData { /** * 返回的信息提示 * @var string $msg */ private $msg; /** * 返回的數據結構 * @var array|object|string */ private $data; /** * api 狀態碼 * @var int $apiCode * @see ApiCode */ private $apiCode; public function __construct(int $apiCode, string $msg = "ok", $data = null) { $this->apiCode = strval($apiCode); $this->msg = trim(strval($msg)); $this->data = $data; } /** * 獲取數據結果 * @return array */ public function getRetData() { if (! is_array($this->data) && is_object($this->data) && method_exists($this->data, "toArray")) { $this->data = $this->data->toArray(); } // valueToString 將data的value轉化為 string 并且做utf-8轉碼 $result = [ "code" => $this->apiCode, "msg" => $this->msg, "data" => $this->data ? ArrayUtil::valueToString($this->data) : [], ]; if (! APP_ENV_PROD) {// 測試環境顯示 api 的處理時間信息 方便優化 $result["use_time"] = microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]; } return $result; } }
有了上面這個類,我們所有的服務層或者controller都應該用它作為返回值。然后在攔截器中統一進行json encode即可。這樣子即減少了犯錯的可能性,同時對統一處理數據的地方做了統一管理集中到 ResultData 中,那么以后有什么特殊變動,調整一處,處處生效。
其它問題另外還有關于 oauth2 如何集成到項目中等等問題,這部分均放到 x-api 項目中進行說明,紙上說來終覺淺嘛。
日志的記錄也是系統開發非常重要的部分,這部分沒什么太多說的,用規范的格式,存儲指定的數據(介質可以是:db、file)。
系統開發中應該拒絕使用 var_dump、echo 這些方式進行調試,另外建議采用:PhpStorm IDE來進行系統開發。
后續分享接下來會完善一個 x-api 的基本結構,以及php自動化測試部分文檔教程,然后后端部分就告一段落。(本系列的分享主要集中在代碼層面,不涉及相關系統部署問題)
GitHub:https://github.com/helei112g
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/25613.html
摘要:后端開發的疑惑后端開發最常面對的一個問題性能高并發等等。而到了時代,在方面有了前后端分離概念移動后端更是無力渲染天然前后端分離。 先來上一張前端頁面的效果圖(Vue + Vux + Vuex + Vue-Router)。showImg(https://segmentfault.com/img/remote/1460000010207850); 第一次做gif 沒什么經驗,太大了。加載...
摘要:以實現自己熟悉的東西為導向比如我們做后端開發,首先是常用的循環迭代條件判斷增刪改成。它是由實現的,不保證元素的順序,也就是說所說元素插入的順序與輸出的順序不一致。 下面是我直播的文字版,直播地址:https://segmentfault.com/l/15...代碼:https://github.com/zhoumengka...整個項目我們我又細分了6個版本來演進,希望更加便于大家對比...
摘要:以實現自己熟悉的東西為導向比如我們做后端開發,首先是常用的循環迭代條件判斷增刪改成。它是由實現的,不保證元素的順序,也就是說所說元素插入的順序與輸出的順序不一致。 下面是我直播的文字版,直播地址:https://segmentfault.com/l/15...代碼:https://github.com/zhoumengka...整個項目我們我又細分了6個版本來演進,希望更加便于大家對比...
摘要:先來說說關鍵字。什么時候用來修飾方法關鍵字大家都知道是用來修飾方法與屬性的。一句話學會面向對象的方式來思考。充分發揮其性能優勢,又能解決擴展性差的問題。這里不會進行與的比較。 你以為你知道了一切,只是你以為而已。知識的美妙就在于,一生的時光在它面前顯得多么的短暫。 嗯嗯,扯遠了,我今天只想說說:static 與 yield。 先來說說 static 關鍵字。本篇只講靜態方法的使用與后期...
閱讀 2458·2021-11-19 09:40
閱讀 3586·2021-11-17 17:08
閱讀 3784·2021-09-10 10:50
閱讀 2214·2019-08-27 10:56
閱讀 1942·2019-08-27 10:55
閱讀 2638·2019-08-26 12:14
閱讀 994·2019-08-26 11:58
閱讀 1494·2019-08-26 10:43