tornado项目
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级别和用户类型。
示例代码:
注: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级别和用户类型。
示例代码:
注: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项目的更多相关文章
- inotify监控目录变化重启服务器tornado项目
pycharm 配置了提交服务器项目每次pycharm修改后,虽然保存到服务器但是项目还得自己去服务器kill再启动.就花几分钟写了shell脚本用于监控项目目录变化并重启tornado项目的脚本 如 ...
- Centos7部署tornado项目
今天帮一个学生解决tornado的部署问题,在此记录了这其中的过程,其中的tornado项目更换为demo示例. 开发环境: 本地开发环境:Win10 + Python3.5.4 + PyCharm ...
- pycharm tornado 项目 配置
ycharm 配置tornado项目 使得能够像django项目一样运行
- 环境配置——tornado项目准备工作
新建tornado项目后,采用Pycharm作为开发工具,采用Xshell链接Ubuntu模拟服务端方便方便测试.项目编码前进行以下几个方面的配置. 1.Ubuntu配置 1.1安装ssh服务 sud ...
- alembic在tornado项目中的应用
在项目中引用alembic 协助tornado项目生成数据表结构 alembic revision --autogenerate -m "create tables" 第二步执行 ...
- Tornado项目简单创建
Tornado是使用Python编写的一个强大的.可扩展的Web服务器.它在处理严峻的网络流量时表现得足够强健,但却在创建和编写时有着足够的轻量级,并能够被用在大量的应用和工具中. tornado技术 ...
- 浅谈tornado项目应用设计
一.预备知识 最近开始尝试做一些tornado商城项目,在开始之前需要引入一些项目设计知识,如接口,抽象方法抽象类,组合,程序设计原则等,个人理解项目的合理设计可增加其灵活性,降低数据之间的耦合性,提 ...
- 潭州课堂25班:Ph201805201 tornado 项目 第十二课 项目部署(课堂笔记)
运行多个Tornado实例 网页响应不是特别的计算密集型处理 多个实例充分利用 CPU 多端口怎么处理 Linux 常见应用服务配置模式 nginx 和 supervisord:采用主配置文件 + 项 ...
- 潭州课堂25班:Ph201805201 tornado 项目 第八课 增加喜欢功能(课堂笔记)
tornado 相关说明 新增一个页面,用来做图片收藏, 还要在 account.py 创建一个数据库表,记录用户喜欢的图片,哪些图片用户疯狂传奇 cd 到 项目目录下,执行数据库更新 alembic ...
随机推荐
- 双有序队列算法——处理哈夫曼K叉树的高效算法
算法介绍: 哈夫曼树的思路及实现众所周知,大部分是用堆来维护和实现,这种思路比较清晰,在K比较小的时候处理较快(具体例子接下来再说),而且编程复杂度不是很高,利于应用.但是,其所用的数据结构是树,是在 ...
- Clairewd’s message - HDU 4300(next[]运用)
题目大意:给两个串第一个串是翻译表(密文可以通过翻译表翻译成明文),第二个串是由密文+明文组成,前面是密文(完整的),后面是明文(未必完整),问能不能把第二个串补全,输出最短的一种可能. 分析:题 ...
- motan源码分析十一:部分特性
本章将描述motan部分的特性并对源码进行分析. 1.requestid的维护,使用了当前时间左移20位,再和一个自增变量组合 public class RequestIdGenerator { ); ...
- C#中MessageBox使用方法大全(附效果图)
我们在程序中常常会用到MessageBox. MessageBox.Show()共同拥有21中重载方法.现将其常见使用方法总结例如以下: 1.MessageBox.Show("Hello~~ ...
- 2013ACM暑假集训总结-致将走上大三征途的我
回想起这个暑假,从开始与雄鹰一起的纠结要不要进集训队,与吉吉博博组队参加地大邀请赛,害怕进不了集训队.当时激励我月份开始接触的,记得当时在弄运动会来着,然后就问了雄鹰一些输入输出的东西,怀着满心的期待 ...
- Qt应用中检测内存泄露——VLD
本文简要描述一下在Qt应用中使用VLD来检测内存泄露.本次测试环境:QtCreator2.3 + Qt4.7.4-vs2008 + VS2008 Express. 1.下载并安装:VLD-2.2: h ...
- vijos P1375 大整数(高精不熟的一定要做!)
/* 我尼玛这题不想说啥了 亏了高精写的熟..... 加减乘除max都写了 高精二分 */ #include<iostream> #include<cstdio> #inclu ...
- DEDECMS织梦列表页每隔N行文章添加一条分隔线
这是给一个朋友做模板的时候,用到的一个小小的技巧,今天正好用上了,以前看到有人问过不知道解决没有,今天整理了一下,本想保存在自己的电脑里,后来一想,不如咱们一起共享一下,也是对织梦的感恩,有好东西就来 ...
- jsp引入struts标签,引入自己写的jquery需要注意的问题
1.使用struts2标签的时候在jsp页面开头引入这句话: <%@ taglib prefix="s" uri="/struts-tags"%> ...
- mysql复习增删改查
select * from torder where status='退款申请' UPDATE torder SET `status`='退款申请' WHERE status='等待付款' and i ...