tornado項目之基於領域驅動模型架構設計的京東用戶管理后台
本博文將一步步揭秘京東等大型網站的領域驅動模型,致力於讓讀者完全掌握這種網絡架構中的“高富帥”。
一、預備知識:
1.接口:
python中並沒有類似java等其它語言中的接口類型,但是python中有抽象類和抽象方法。如果一個抽象類有抽象方法,那么繼承它的子類必須實現抽象類的所有方法,因此,我們基於python的抽象類和抽象方法實現接口功能。
示例代碼:
接口示例代碼
2.依賴注入:
依賴注入的作用是將一系列無關的類通過注入參數的方式實現關聯,例如將類A的對象作為參數注入給類B,那么當調用類B的時候,類A會首先被實例化。
示例代碼:
依賴注入示例
注:原理:首先需要明確一切事物皆對象類也是對象,類是有Type創建的,當類實例化的時候,會調用type類的call方法,call方法會調用new方法,new方法調用init方法。
二、企業級應用設計
1.總體框架目錄結構:

備注:
- Infrastructure:一些公共組件,例如md5加密,分頁模塊,session等。
- Model :關於數據庫的邏輯處理模塊
- Repository :數據訪問層,包含數據庫的增刪改查
- Service :服務層,調用Model,包含帶有規則的請求和返回
- Statics:靜態文件目錄
- UI層:業務處理
- Views:模板文件
- Application:tornado程序的起始文件
- Config:配置文件
- Mapper:依賴注入文件,負責整個框架不同類的依賴注入
2.首先我們從Moldel開始查看:
文件目錄:

本文主要以用戶管理為例進行介紹,因此我們來關注一下User.py文件:
代碼結構:

下面對上述代碼結構做一一介紹:
IUseRepository類:接口類,用於約束數據庫訪問類的方法
示例代碼:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
class
IUseRepository:
"""
用戶信息倉庫接口
"""
def
fetch_one_by_user_pwd(
self
, username, password):
"""
根據用戶名密碼獲取模型對象
:param username: 主鍵ID
:param password: 主鍵ID
:return:
"""
def
fetch_one_by_email_pwd(
self
, email, password):
"""
根據郵箱密碼獲取模型對象
:param email: 主鍵ID
:param password: 主鍵ID
:return:
"""
def
update_last_login_by_nid(
self
,nid,current_date):
"""
根據ID更新最新登陸時間
:param nid:
:return:
"""
|
從上述代碼可以看出,數據庫訪問類如果繼承IUseRepository類,就必須實現其中的抽象方法。
接下來的三個類,VipType、UserType、User是與用戶信息相關的類,是數據庫需要保存的數據,我們希望存入數據庫的數據格式為:nid 、username、email、last_login、user_type_id、vip_type_id,其中User類用於保存上述數據。因為user_type_id、vip_type_id存的是數字,即user_type_id、vip_type_id是外鍵,不能直接在前端進行展示,因此,我們創建了VipType、UserType類,用於根據id,獲取對應的VIP級別和用戶類型。
示例代碼:
User類
UserType類
VipType類
注:VipType、UserType這兩個類獲取對應的caption均是通過類的普通特性訪問,即類似字段方式訪問。
接下來的類UserService是本py文件的重中之重,它負責調用對應的數據庫訪問類的方法,並被服務層service調用,具有承上啟下的作用:
示例代碼:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class
UserService:
def
__init__(
self
, user_repository):
self
.userRepository
=
user_repository
def
check_login(
self
, username
=
None
, email
=
None
, password
=
None
):
if
username:
user_model
=
self
.userRepository.fetch_one_by_user_pwd(username, password)
else
:
user_model
=
self
.userRepository.fetch_one_by_email_pwd(email, password)
if
user_model:
current_date
=
datetime.datetime.now()
self
.userRepository.update_last_login_by_nid(user_model.nid, current_date)
return
user_model
|
這里,我們重點介紹一下上述代碼:
初始化參數user_repository:通過依賴注入對應的數據庫訪問類的對象;
check_login:訪問數據庫的關鍵邏輯處理方法,根據用戶是用戶名+密碼方式還是郵箱加密碼的方式登錄,然后調用對應的數據庫處理方法,如果登陸成功,更新時間和最后登錄時間,最后將User類的實例返回給調用它的服務層service。(詳細見下文數據庫處理類的方法)
我們先來看一下對應的數據庫處理類中的一個方法:
|
1
|
示例代碼:
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def
fetch_one_by_user_pwd(
self
, username, password):
ret
=
None
cursor
=
self
.db_conn.connect()
sql
=
"""select nid,username,email,last_login,vip,user_type from UserInfo where username=%s and password=%s"""
cursor.execute(sql, (username, password))
db_result
=
cursor.fetchone()
self
.db_conn.close()
if
db_result:
ret
=
User(nid
=
db_result[
'nid'
],
username
=
db_result[
'username'
],
email
=
db_result[
'email'
],
last_login
=
db_result[
'last_login'
],
user_type
=
UserType(nid
=
db_result[
'user_type'
]),
vip_type
=
VipType(nid
=
db_result[
'vip'
])
)
return
ret
|
這里我們使用pymysql進行數據庫操作,以用戶名+密碼登陸為例,如果數據庫有對應的用戶名和密碼,將查詢結果放在User類中進行初始化,至此,ret中封裝了用戶的全部基本信息,將ret返回給上面的check_login方法,即對應上文中的返回值user_model,user_model返回給調用它的服務層service。
總結:Molde最終將封裝了用戶基本信息的User類的實例返回給服務層service。
3.接下來我們看一下服務層service:
service也是一個承上啟下的作用,它調用Moldel文件對應的數據庫業務協調方法,並被對應的UI層調用(本例中是UIadmin)。
目錄結構:

同樣的,我們只介紹User文件夾:它包含4個py文件:
- ModelView:用於用戶前端展示的數據格式化,重點對user_type_id、vip_type_id增加對應的用戶類型和VIP級別,即將外鍵數據對應的caption放在外鍵后面,作為增加的參數。
- Request:封裝請求Moldel文件對應數據庫協調類的參數
- Response:封裝需要返回UI層的參數
- Sevice:核心服務處理文件
下面對上述目錄做詳細代碼:
ModelView:
|
1
2
3
4
5
6
7
8
9
10
11
|
class
UserModelView:
def
__init__(
self
, nid, username, email, last_login, user_type_id, user_type_caption, vip_type_id, vip_type_caption):
self
.nid
=
nid
self
.username
=
username
self
.email
=
email
self
.last_login
=
last_login
self
.user_type
=
user_type_id
self
.user_type_caption
=
user_type_caption
self
.vip_type
=
vip_type_id
self
.vip_type_caption
=
vip_type_caption
|
注:對user_type_id、vip_type_id增加對應的用戶類型和VIP級別,即將外鍵數據對應的caption放在外鍵后面,作為增加的參數。
Request:
|
1
2
3
4
5
6
|
class
UserRequest:
def
__init__(
self
, username, email, password):
self
.username
=
username
self
.email
=
email
self
.password
=
password
|
Response:
|
1
2
3
4
5
6
|
class
UserResponse:
def
__init__(
self
, status
=
True
, message
=
'', model_view
=
None
):
self
.status
=
status
# 是否登陸成功的狀態
self
.message
=
message
#錯誤信息
self
.modelView
=
model_view
#登陸成功后的用戶數據
|
UserService:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
class
UserService:
def
__init__(
self
, model_user_service):
#通過依賴注入Moldel對應的數據庫業務協調方法,此例中對應上文中的user_service
self
.modelUserService
=
model_user_service
def
check_login(
self
, user_request):
#核心服務層業務處理方法
response
=
UserResponse()
#實例化返回類
try
:
model
=
self
.modelUserService.check_login(user_request.username, user_request.email, user_request.password)
#接收上文中的用戶基本信息,是User類的實例
if
not
model:
raise
Exception(
'用戶名或密碼錯誤'
)
else
:
#如果登陸成功,通過UserModelView類格式化返回前端的數據
model_view
=
UserModelView(nid
=
model[
'nid'
],
username
=
model[
'usename'
],
email
=
model[
'email'
],
last_login
=
model[
'last_login'
],
user_type_id
=
model[
'user_type'
].nid,
user_type_caption
=
model[
'user_type'
].caption,
vip_type_id
=
model[
'vip_type'
].nid,
vip_type_caption
=
model[
'vip_type'
].caption,)
response.modelView
=
model_view
#定義返回UI層的用戶信息
except
Exception as e:
response.status
=
False
response.message
=
str
(e)
|
總結:至此,Service返回給Ui層的數據是是否登陸成功的狀態status、錯誤信息、已經格式化的用戶基本信息。
4.UI層
UI層主要負責業務處理完成后與前端的交互,它是服務層Service的調用者:
示例代碼:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class
Login(AdminRequestHandler):
def
get(
self
,
*
args,
*
*
kwargs):
is_login
=
self
.session[
"is_login"
]
current_user
=
""
if
is_login:
current_user
=
self
.session[
"user_info"
].username
self
.render(
'Account/Login.html'
,current_user
=
current_user)
def
post(
self
,
*
args,
*
*
kwargs):
user_request
=
[]
#獲取用戶輸入的用戶名郵箱密碼
user_request.append(
self
.get_argument(
'name'
,
None
))
user_request.append(
self
.get_argument(
'email'
,
None
))
user_request.append(
self
.get_argument(
'pwd'
,
None
))
checkcode
=
self
.get_argument(
"checkcode"
,
None
)
Mapper.mapper(
*
user_request)
obj
=
UserService.check_login()
self
.session[
"is_login"
]
=
True
self
.session[
"user_info"
]
=
obj.modelView
self
.write(
"已登陸"
)
|
總結以上就是基於領域驅動模型的用戶管理后台,包含數據庫操作文件,數據庫業務處理文件,服務端文件,UI層文件。如果本文對您有參考價值
tornado源碼系列
tornado項目之基於領域驅動模型架構設計的京東用戶管理后台
posted @ 2016-09-07 09:15 戰神王恆 閱讀(506) | 評論 (7) 編輯
tornado高效開發必備之源碼詳解
posted @ 2016-09-01 09:10 戰神王恆 閱讀(945) | 評論 (22) 編輯
tornado web高級開發項目之抽屜官網的頁面登陸驗證、form驗證、點贊、評論、文章分頁處理、發送郵箱驗證碼、登陸驗證碼、注冊、發布文章、上傳圖片
posted @ 2016-08-29 09:17 戰神王恆 閱讀(1072) | 評論 (18) 編輯
Web框架之Tornado
posted @ 2016-08-25 18:41 戰神王恆 閱讀(91) | 評論 (0) 編輯
本博文將一步步揭秘京東等大型網站的領域驅動模型,致力於讓讀者完全掌握這種網絡架構中的“高富帥”。
一、預備知識:
1.接口:
python中並沒有類似java等其它語言中的接口類型,但是python中有抽象類和抽象方法。如果一個抽象類有抽象方法,那么繼承它的子類必須實現抽象類的所有方法,因此,我們基於python的抽象類和抽象方法實現接口功能。
示例代碼:
接口示例代碼
2.依賴注入:
依賴注入的作用是將一系列無關的類通過注入參數的方式實現關聯,例如將類A的對象作為參數注入給類B,那么當調用類B的時候,類A會首先被實例化。
示例代碼:
依賴注入示例
注:原理:首先需要明確一切事物皆對象類也是對象,類是有Type創建的,當類實例化的時候,會調用type類的call方法,call方法會調用new方法,new方法調用init方法。
二、企業級應用設計
1.總體框架目錄結構:

備注:
- Infrastructure:一些公共組件,例如md5加密,分頁模塊,session等。
- Model :關於數據庫的邏輯處理模塊
- Repository :數據訪問層,包含數據庫的增刪改查
- Service :服務層,調用Model,包含帶有規則的請求和返回
- Statics:靜態文件目錄
- UI層:業務處理
- Views:模板文件
- Application:tornado程序的起始文件
- Config:配置文件
- Mapper:依賴注入文件,負責整個框架不同類的依賴注入
2.首先我們從Moldel開始查看:
文件目錄:

本文主要以用戶管理為例進行介紹,因此我們來關注一下User.py文件:
代碼結構:

下面對上述代碼結構做一一介紹:
IUseRepository類:接口類,用於約束數據庫訪問類的方法
示例代碼:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
class
IUseRepository:
"""
用戶信息倉庫接口
"""
def
fetch_one_by_user_pwd(
self
, username, password):
"""
根據用戶名密碼獲取模型對象
:param username: 主鍵ID
:param password: 主鍵ID
:return:
"""
def
fetch_one_by_email_pwd(
self
, email, password):
"""
根據郵箱密碼獲取模型對象
:param email: 主鍵ID
:param password: 主鍵ID
:return:
"""
def
update_last_login_by_nid(
self
,nid,current_date):
"""
根據ID更新最新登陸時間
:param nid:
:return:
"""
|
從上述代碼可以看出,數據庫訪問類如果繼承IUseRepository類,就必須實現其中的抽象方法。
接下來的三個類,VipType、UserType、User是與用戶信息相關的類,是數據庫需要保存的數據,我們希望存入數據庫的數據格式為:nid 、username、email、last_login、user_type_id、vip_type_id,其中User類用於保存上述數據。因為user_type_id、vip_type_id存的是數字,即user_type_id、vip_type_id是外鍵,不能直接在前端進行展示,因此,我們創建了VipType、UserType類,用於根據id,獲取對應的VIP級別和用戶類型。
示例代碼:
User類
UserType類
VipType類
注:VipType、UserType這兩個類獲取對應的caption均是通過類的普通特性訪問,即類似字段方式訪問。
接下來的類UserService是本py文件的重中之重,它負責調用對應的數據庫訪問類的方法,並被服務層service調用,具有承上啟下的作用:
示例代碼:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class
UserService:
def
__init__(
self
, user_repository):
self
.userRepository
=
user_repository
def
check_login(
self
, username
=
None
, email
=
None
, password
=
None
):
if
username:
user_model
=
self
.userRepository.fetch_one_by_user_pwd(username, password)
else
:
user_model
=
self
.userRepository.fetch_one_by_email_pwd(email, password)
if
user_model:
current_date
=
datetime.datetime.now()
self
.userRepository.update_last_login_by_nid(user_model.nid, current_date)
return
user_model
|
這里,我們重點介紹一下上述代碼:
初始化參數user_repository:通過依賴注入對應的數據庫訪問類的對象;
check_login:訪問數據庫的關鍵邏輯處理方法,根據用戶是用戶名+密碼方式還是郵箱加密碼的方式登錄,然后調用對應的數據庫處理方法,如果登陸成功,更新時間和最后登錄時間,最后將User類的實例返回給調用它的服務層service。(詳細見下文數據庫處理類的方法)
我們先來看一下對應的數據庫處理類中的一個方法:
|
1
|
示例代碼:
|
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
def
fetch_one_by_user_pwd(
self
, username, password):
ret
=
None
cursor
=
self
.db_conn.connect()
sql
=
"""select nid,username,email,last_login,vip,user_type from UserInfo where username=%s and password=%s"""
cursor.execute(sql, (username, password))
db_result
=
cursor.fetchone()
self
.db_conn.close()
if
db_result:
ret
=
User(nid
=
db_result[
'nid'
],
username
=
db_result[
'username'
],
email
=
db_result[
'email'
],
last_login
=
db_result[
'last_login'
],
user_type
=
UserType(nid
=
db_result[
'user_type'
]),
vip_type
=
VipType(nid
=
db_result[
'vip'
])
)
return
ret
|
這里我們使用pymysql進行數據庫操作,以用戶名+密碼登陸為例,如果數據庫有對應的用戶名和密碼,將查詢結果放在User類中進行初始化,至此,ret中封裝了用戶的全部基本信息,將ret返回給上面的check_login方法,即對應上文中的返回值user_model,user_model返回給調用它的服務層service。
總結:Molde最終將封裝了用戶基本信息的User類的實例返回給服務層service。
3.接下來我們看一下服務層service:
service也是一個承上啟下的作用,它調用Moldel文件對應的數據庫業務協調方法,並被對應的UI層調用(本例中是UIadmin)。
目錄結構:

同樣的,我們只介紹User文件夾:它包含4個py文件:
- ModelView:用於用戶前端展示的數據格式化,重點對user_type_id、vip_type_id增加對應的用戶類型和VIP級別,即將外鍵數據對應的caption放在外鍵后面,作為增加的參數。
- Request:封裝請求Moldel文件對應數據庫協調類的參數
- Response:封裝需要返回UI層的參數
- Sevice:核心服務處理文件
下面對上述目錄做詳細代碼:
ModelView:
|
1
2
3
4
5
6
7
8
9
10
11
|
class
UserModelView:
def
__init__(
self
, nid, username, email, last_login, user_type_id, user_type_caption, vip_type_id, vip_type_caption):
self
.nid
=
nid
self
.username
=
username
self
.email
=
email
self
.last_login
=
last_login
self
.user_type
=
user_type_id
self
.user_type_caption
=
user_type_caption
self
.vip_type
=
vip_type_id
self
.vip_type_caption
=
vip_type_caption
|
注:對user_type_id、vip_type_id增加對應的用戶類型和VIP級別,即將外鍵數據對應的caption放在外鍵后面,作為增加的參數。
Request:
|
1
2
3
4
5
6
|
class
UserRequest:
def
__init__(
self
, username, email, password):
self
.username
=
username
self
.email
=
email
self
.password
=
password
|
Response:
|
1
2
3
4
5
6
|
class
UserResponse:
def
__init__(
self
, status
=
True
, message
=
'', model_view
=
None
):
self
.status
=
status
# 是否登陸成功的狀態
self
.message
=
message
#錯誤信息
self
.modelView
=
model_view
#登陸成功后的用戶數據
|
UserService:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
class
UserService:
def
__init__(
self
, model_user_service):
#通過依賴注入Moldel對應的數據庫業務協調方法,此例中對應上文中的user_service
self
.modelUserService
=
model_user_service
def
check_login(
self
, user_request):
#核心服務層業務處理方法
response
=
UserResponse()
#實例化返回類
try
:
model
=
self
.modelUserService.check_login(user_request.username, user_request.email, user_request.password)
#接收上文中的用戶基本信息,是User類的實例
if
not
model:
raise
Exception(
'用戶名或密碼錯誤'
)
else
:
#如果登陸成功,通過UserModelView類格式化返回前端的數據
model_view
=
UserModelView(nid
=
model[
'nid'
],
username
=
model[
'usename'
],
email
=
model[
'email'
],
last_login
=
model[
'last_login'
],
user_type_id
=
model[
'user_type'
].nid,
user_type_caption
=
model[
'user_type'
].caption,
vip_type_id
=
model[
'vip_type'
].nid,
vip_type_caption
=
model[
'vip_type'
].caption,)
response.modelView
=
model_view
#定義返回UI層的用戶信息
except
Exception as e:
response.status
=
False
response.message
=
str
(e)
|
總結:至此,Service返回給Ui層的數據是是否登陸成功的狀態status、錯誤信息、已經格式化的用戶基本信息。
4.UI層
UI層主要負責業務處理完成后與前端的交互,它是服務層Service的調用者:
示例代碼:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class
Login(AdminRequestHandler):
def
get(
self
,
*
args,
*
*
kwargs):
is_login
=
self
.session[
"is_login"
]
current_user
=
""
if
is_login:
current_user
=
self
.session[
"user_info"
].username
self
.render(
'Account/Login.html'
,current_user
=
current_user)
def
post(
self
,
*
args,
*
*
kwargs):
user_request
=
[]
#獲取用戶輸入的用戶名郵箱密碼
user_request.append(
self
.get_argument(
'name'
,
None
))
user_request.append(
self
.get_argument(
'email'
,
None
))
user_request.append(
self
.get_argument(
'pwd'
,
None
))
checkcode
=
self
.get_argument(
"checkcode"
,
None
)
Mapper.mapper(
*
user_request)
obj
=
UserService.check_login()
self
.session[
"is_login"
]
=
True
self
.session[
"user_info"
]
=
obj.modelView
self
.write(
"已登陸"
)
|
總結以上就是基於領域驅動模型的用戶管理后台,包含數據庫操作文件,數據庫業務處理文件,服務端文件,UI層文件。如果本文對您有參考價值
