电竞比分网-中国电竞赛事及体育赛事平台

分享

恕我直言:Web 開發(fā)太 low??!

 昵稱10087950 2022-06-20 發(fā)布于江蘇
來源:https://lepdou./blogs/web_develop_standard/blog.html

引言

網(wǎng)上經(jīng)常有這樣的言論:

1.web開發(fā)太low,沒技術(shù)含量。

2.web開發(fā)根本涉及不到多線程的問題等。

對于第一點,我想說技術(shù)沒有高低貴賤之分,能把自己領(lǐng)域方向做到極致的才是最吊的。

對于第二點,談一下個人對web應(yīng)用的理解。web應(yīng)用的定義:提供http協(xié)議支持的應(yīng)用。 每一個系統(tǒng)都不是封閉的,肯定得和其它系統(tǒng)或者人交互。http協(xié)議因為其簡單、支持廣泛的特性被不同領(lǐng)域的系統(tǒng)作為其輸入輸出的協(xié)議。近幾年微服務(wù)的出現(xiàn),越來越多的web應(yīng)用不再是只輸出html頁面了。更多的是Restful規(guī)范的API接口,json數(shù)據(jù)格式,以及http協(xié)議。

所以說,web應(yīng)用既然有這么多的應(yīng)用場景,肯定有復雜的系統(tǒng)涉及到多線程問題。

本文要講述的是如何開發(fā)規(guī)范Java Web應(yīng)用。規(guī)范包括:如何分層、每一層的職責、層之間如何交互、數(shù)據(jù)如何流通等。

我相信大部分人都知道怎么實現(xiàn)一個功能,也知道最簡單的三層模型Controller、Service、Dao。以及數(shù)據(jù)模型對象:VO,BO,PO,DTO,Model。但是,我以及我身邊很多的開發(fā)其實并不是非常清楚每個組件的定義和職責。所以本文的目標就是理清楚這些概念、組件。

分層

典型的web應(yīng)用分為三層,即:Controller層、Service層、Dao層。

如下圖所示:

圖片
三層模型

Controller層

Controller層,我認為是系統(tǒng)的Facade。職責包括以下幾點:

  1. 接收系統(tǒng)輸入
  2. 數(shù)據(jù)校驗
  3. 協(xié)議轉(zhuǎn)化
  4. 系統(tǒng)輸出
  5. 定義系統(tǒng)接口

接收系統(tǒng)輸入

常見的包括從request中提取path variable,query param,request payload、用戶認證信息等。另外,Web 系列面試題和答案全部整理好了,微信搜索Java技術(shù)棧,在后臺發(fā)送:面試,可以在線閱讀。

數(shù)據(jù)校驗

基本的數(shù)據(jù)校驗包括:數(shù)據(jù)類型,數(shù)據(jù)取值范圍、數(shù)據(jù)格式。舉個例子,假設(shè)有一個轉(zhuǎn)賬接口,其中有一個金額字段。這里對金額字段做的校驗包括:不能為負數(shù)。而業(yè)務(wù)型的檢查包括金額不能大于賬戶余額、不能大于賬戶類型所對應(yīng)的最大轉(zhuǎn)賬額度不應(yīng)該放在Controller層進行校驗。

協(xié)議轉(zhuǎn)化

協(xié)議轉(zhuǎn)化包含兩個方面。

  1. 系統(tǒng)內(nèi)部數(shù)據(jù)類型轉(zhuǎn)化
  2. 數(shù)據(jù)內(nèi)容協(xié)議轉(zhuǎn)化
  3. 數(shù)據(jù)傳輸格式協(xié)議轉(zhuǎn)化

系統(tǒng)內(nèi)部數(shù)據(jù)類型轉(zhuǎn)化

包括:BO轉(zhuǎn)化成DTO、BO轉(zhuǎn)化成VO。這幾種數(shù)據(jù)模型含義下一節(jié)會具體講述。

數(shù)據(jù)內(nèi)容協(xié)議轉(zhuǎn)化

舉個例子說明會更加容易理解。假設(shè)有一個Open API,功能是返回User信息。這個Open API對A公司開放的信息包括:昵稱、頭像兩個字段,而B公司是本公司的VIP用戶,對其開放的信息不僅包含昵稱、頭像還包括電話、email等隱私信息。

在Service層只有一個返回UserBO的接口,UserBO包含用戶所有的信息,在Controller層根據(jù)不同公司的類型,生成不同的UserDTO,此過程稱為數(shù)據(jù)內(nèi)容協(xié)議轉(zhuǎn)化。

數(shù)據(jù)傳輸格式協(xié)議轉(zhuǎn)化

包括:把對象序列化成json、xml格式數(shù)據(jù)、html頁面等

系統(tǒng)輸出

把協(xié)議轉(zhuǎn)化之后的數(shù)據(jù),組裝成Http Response輸出給外部應(yīng)用。

定義系統(tǒng)接口

一個系統(tǒng)提供了那些能力,則由系統(tǒng)接口決定的。接口包含三部分內(nèi)容:

  1. 輸入值
  2. 接口標識:url+http method
  3. 返回值

Service層

service層主要負責系統(tǒng)業(yè)務(wù)邏輯的處理。上面提到的轉(zhuǎn)賬金額上限的校驗應(yīng)該放在此層。service層根據(jù)業(yè)務(wù)系統(tǒng)的復雜度又可以劃分成多層。以兩層為例:

  1. 跟數(shù)據(jù)表一一對應(yīng)的資源Service層
  2. 在資源Service層之上的聚合業(yè)務(wù)邏輯層

資源Service層 一般跟一張表、一個Dao對應(yīng)。在SOA領(lǐng)域里,把一部分高度內(nèi)聚的資源作為一個SOA Service,例如UserSerivce,OrderService等。其它應(yīng)用不應(yīng)該直接訪問User相關(guān)的數(shù)據(jù)庫,而應(yīng)該調(diào)用UserService。資源高度內(nèi)聚,便于管理和控制。

在分布式系統(tǒng)如此,在一個系統(tǒng)內(nèi)部也應(yīng)該如此。也就是說,一張表也可以作為一個資源,其它的Service不應(yīng)該直接訪問這張表,而應(yīng)該通過這張表對應(yīng)的Service來訪問。當然,有些時候可以把幾張表的資源內(nèi)聚到一個Service當中。

換句話說,Dao不應(yīng)該到處散落在不同的Service中,訪問資源應(yīng)該調(diào)用資源對應(yīng)的Serivce。資源Service層理論上應(yīng)該涉及很薄的、跟資源相關(guān)的業(yè)務(wù)邏輯。附加dao一些簡單的業(yè)務(wù)邏輯能力。另外一個職責就是數(shù)據(jù)類型轉(zhuǎn)換,也就是PO轉(zhuǎn)化為BO,后面會詳細講述。

聚合業(yè)務(wù)邏輯層 這一層是真正核心業(yè)務(wù)邏輯處理的地方,在資源Service層之上。完全負責處理業(yè)務(wù)邏輯,不用關(guān)心資源訪問。最新 Web 面試題整理好了,點擊Java面試庫小程序在線刷題。

對于不復雜的應(yīng)用系統(tǒng)來說,大部分的Service其實可以合為一層,有些特別復雜的業(yè)務(wù)邏輯可以單獨抽象出一層,切記Service角色要清晰。判斷是否清晰最簡單的方式就是能否自然的想出Service的名字。

另外插一句題外話,很多公司或者書籍提倡面向接口編程,導致一個很常見的現(xiàn)象就是一個Service包含兩部分:XXService和XXServiceImpl。這樣寫好處就是接口和實現(xiàn)分離,接口亦是文檔,清晰。壞處就是多了一個類。

我們不應(yīng)該不假思索的按照慣性思維去實踐,在剛提到的這種面向接口編程不是完全可取的。接口的本意是可以有多種實現(xiàn),也就是可能有多個子類。但是上面提到的這種Service基本上都只有一個實現(xiàn)類,那么接口的意義何在?當然并不是說就不需要接口實現(xiàn)分離。

我覺得以下情況可以考慮分離:

  1. 接口可能會有多種實現(xiàn)
  2. SOA系統(tǒng)對外提供服務(wù)的Facade Service
  3. 復雜的系統(tǒng),框架面向接口編程更邏輯理清楚組件之間的關(guān)系

很顯然對于大部分的web應(yīng)用,以上三點并不符合,所以我覺得沒必要接口實現(xiàn)分離,多出一個沒有意思類實在是很丑。

點擊關(guān)注公眾號,Java干貨及時送達圖片

Dao層

dao層比較簡單,應(yīng)該只負責和數(shù)據(jù)庫打交道,不應(yīng)該涉及業(yè)務(wù)邏輯,只涉及跟數(shù)據(jù)存儲相關(guān)的邏輯。

數(shù)據(jù)類型

數(shù)據(jù)類型一般分為以下幾種:PO、BO、VO、DTO、Model、POJO。

PO(persistence object)

持久化對象,一般表示一張表,屬性跟表字段一一對應(yīng)。

BO (business object)

業(yè)務(wù)對象,在業(yè)務(wù)組件中流通的對象。字段集合可能比PO多,也可能比PO少。一個PO可能對應(yīng)多個BO。

VO (view object)

視圖對象,只用來給前端頁面渲染的數(shù)據(jù)結(jié)構(gòu)。

DTO (data transaction object)

數(shù)據(jù)傳輸對象,在各個系統(tǒng)間傳輸?shù)膶ο螅话阈枰獙崿F(xiàn)Serializable接口。

Model

表單數(shù)據(jù)模型,一般對應(yīng)request payload。

POJO (plain ordinary Java object)

只用來表示數(shù)據(jù)類型,游離在系統(tǒng)業(yè)務(wù)之外的java bean。

數(shù)據(jù)類型和分層結(jié)合

理論上每一種數(shù)據(jù)類型只能在特定的層中出現(xiàn)。po => dao層, 資源Service層 bo => Service層,Controller層 * vo、dto、model => Controller層。

推薦一個 Spring Boot 基礎(chǔ)教程及實戰(zhàn)示例:https://github.com/javastacks/spring-boot-best-practice

如下圖所示:

圖片

任何的規(guī)范都是靈活的,如果按照上面嚴格執(zhí)行的話,就會產(chǎn)生很多屬性基本一致的類,而且類型轉(zhuǎn)換代碼非常機械化。對于大部分簡單的系統(tǒng)來說,各個類型之間,字段幾乎是完全一致。

靈活的做法是下層的對象可以上升到上層,比如某一個資源沒有BO,也沒有VO,只有PO。也就是說PO存在于Dao,Service和Controller三層。但是反之則不行,例如VO、DTO、Model不應(yīng)該在Service層出現(xiàn),更不能在Dao層出現(xiàn)。所以最佳實踐則是最少要兩層。

如下圖所示:

圖片

另外需要注意一點就是:其它系統(tǒng)的DTO等于自身系統(tǒng)的PO,也就是說上面提到的所有的類型其實是相對于數(shù)據(jù)流的位置而定的。所以,在Service層流通的DTO其實是PO的角色。但是自身系統(tǒng)對外的DTO就不應(yīng)該在Service層出現(xiàn)。

結(jié)語

做任何事情都需要規(guī)范,web開發(fā)亦是如此。規(guī)范的好處是:整潔、易維護、易理解。規(guī)范也是每個程序員進階的必經(jīng)之路。上述對于分層和數(shù)據(jù)類型的理解都是個人對于項目開發(fā)的思考,可能跟其它規(guī)范有出入。

規(guī)范不是協(xié)議,規(guī)范是約定并不是強制,只要清晰可實踐即可。每個人都可以有自己的規(guī)范,但是需要要大部分人所能接受理解。

注:以上分層和類型的稱呼只是定義角色,具體系統(tǒng)中使用的叫法可以不一致。只要團隊內(nèi)部約定好即可。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多