本篇在上篇的基础上为其增设路由功能,同时将上篇中的数据库中数据备份添加进去。

一、装饰器

  在之前有介绍过为一个函数不改变源代码不改变原函数的调用方式下为其增设附加功能,需要用到装饰器,而在该上篇的web-mini框架中每当服务器发送动态资源请求过来时,我们需要做if判断,那么我们可不可以省去这繁琐的步骤呢?

  1.1 通过闭包来实现装饰器:

# 为函数附加新功能 - 计算运算时长
import time
def timmer(func):
def wrapper(*args,**kwargs):
start_time = time.time()
ret = func(*args,**kwargs)
end_time = time.time()
print("spend time --> %s"%(end_time -start_time))
return ret
return wrapper @timmer # 等价于 ==》test = timmer(test)
def test(num):
time.sleep(1)
print("in the test --> %s"%num )
return num*num +1 ret = test(8)
print(ret)

  注1:装饰器在原函数在调用之前就以及开始装饰了。即写上@timmer时test1 = timmer(test)就开始执行。下面我们介绍一种由类实现的装饰器:

  1.2 由类实现的装饰器

class Test(object):
"""定义一个装饰器类"""
def __init__(self,func):
self.func = func
def __call__(self,*args,**kwargs):
print("在此为函数附加新功能")
ret = self.func(*args,**kwargs)
return ret @Test # get_str = Test(get_str),相当于将get_str传入创建实例对象
def get_str(num):
print("in the get_str-->%s"%num)
return "hello world!"
get_str() # Test(get_str)() ,必须有call魔法方法,实则运行实例的__call__方法

  这种由类实现的装饰器,其效果与由闭包实现的装饰器效果几乎一样,但是由于进行一次装饰,需创建一个实例对象,即每次需要开辟一个内存空间,存放着实例属性、方法以及类的中方法的指针等,比较浪费资源,即 杀鸡用牛刀;

  1.3 带参数的装饰器

  

def set_level(level_num):  # 用来接收参数
def set_func(func): # 装饰器函数
def call_func(*args,**kwargs):
if level_num = 1:
print("设置权限1")
elif level_num = 2:
print("设置权限2")
else:
print("你个瓜皮,没有这个权限验证")
ret = func(*args,**kwargs)
return ret
return call_func
return set_func @setlevel(1)
def test1():
print("hello world") @setlevel(2)
def test1():
print("妈的个巴子哟") # setlevel(para) --- test1 = set_level(1)
# 1、首先调用set_level,并且传入参数1, --- test1 = set_level(1)
# 2、启动装饰器set_func,装饰函数,--- test1 = set_func(test1)

 带参数的装饰器:

  1、其最外层函数set_level,相当于一个容器用来封装,存储装饰器和一些变量等;而真正的装饰器部分实则为set_func装饰器;

  2、进行装饰时:@setlevel(1)实则执行两步操作:

   ①、首先调用set_level,并且传入参数1, --- test1 = set_level(1) ;

     ②、启动装饰器set_func,装饰函数,--- test1 = set_func(test1);


二、静态、动态、伪静态URL

  目前开发的网站其实真正意义上都是动态网站,只是URL上有些区别,一般URL分为静态URL、动态URL、伪静态URL,他们的区别是什么?

静态URL

静态URL类似 域名/news/2012-5-18/110.html 我们一般称为真静态URL,每个网页有真实的物理路径,也就是真实存在服务器里的。

动态URL

动态URL类似 域名/NewsMore.asp?id=5 或者 域名/DaiKuan.php?id=17,带有?号的URL,我们一般称为动态网址,每个URL只是一个逻辑地址,并不是真实物理存在服务器硬盘里的。

伪静态URL

伪静态URL类似 域名/course/74.html 这个URL和真静态URL类似。他是通过伪静态规则把动态URL伪装成静态网址。也是逻辑地址,不存在物理地址。

 三者的优缺点:

  1、静态URL:网页打开速度快,SEO最好,但是对于大中型网站而言页面多,修改起来不方便,不便管理;

  2、动态URL:由于需要调用框架从数据库中读取数据,故网页打开速度不如静态URL,SEO不如静态URL,但是适合中大型网站,修改页面很方便,因为是逻辑地址,所以占用硬盘空间要比纯静态网站小。

  3、伪静态URL:其输入浏览器的形式与静态URL相同,但是确实调用框架读取数据库中的数据来实现的,是相对于前两种的折中方案;URL比较友好,利于记忆;修改页面也十分方便,但是设置麻烦,服务器要支持重写规则,小企业网站或者玩不好的就不要折腾;


二、案例

  该实例是在上篇(web-mini框架的基本实现(一))的基础上对其进行修改的,即为其添加路由功能,实现伪静态网页、以及替换成数据库中的数据;

 服务端web_server.py

import socket
import re
import multiprocessing
import time
# import dynamic.mini_frame
import sys class WSGIServer(object):
def __init__(self, port, app, static_path):
# 1. 创建套接字
self.tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 2. 绑定
self.tcp_server_socket.bind(("", port)) # 3. 变为监听套接字
self.tcp_server_socket.listen(128) self.application = app
self.static_path = static_path def service_client(self, new_socket):
"""为这个客户端返回数据""" # 1. 接收浏览器发送过来的请求 ,即http请求
# GET / HTTP/1.1
# .....
request = new_socket.recv(1024).decode("utf-8")
# print(">>>"*50)
# print(request) request_lines = request.splitlines()
print("")
print(">"*20)
print(request_lines) # GET /index.html HTTP/1.1
# get post put del
file_name = ""
ret = re.match(r"[^/]+(/[^ ]*)", request_lines[0])
if ret:
file_name = ret.group(1)
# print("*"*50, file_name)
if file_name == "/":
file_name = "/index.html" # 2. 返回http格式的数据,给浏览器
# 2.1 如果请求的资源不是以.py结尾,那么就认为是静态资源(html/css/js/png,jpg等)
if not file_name.endswith(".html"):
try:
f = open(self.static_path + file_name, "rb")
except:
response = "HTTP/1.1 404 NOT FOUND\r\n"
response += "\r\n"
response += "------file not found-----"
new_socket.send(response.encode("utf-8"))
else:
html_content = f.read()
f.close()
# 2.1 准备发送给浏览器的数据---header
response = "HTTP/1.1 200 OK\r\n"
response += "\r\n"
# 2.2 准备发送给浏览器的数据---boy
# response += "hahahhah" # 将response header发送给浏览器
new_socket.send(response.encode("utf-8"))
# 将response ic.mini_frame.applicationbody发送给浏览器
new_socket.send(html_content)
else:
# 2.2 如果是以.py结尾,那么就认为是动态资源的请求 env = dict() # 这个字典中存放的是web服务器要传递给 web框架的数据信息
env['PATH_INFO'] = file_name
# {"PATH_INFO": "/index.py"}
# body = dynamic.mini_frame.application(env, self.set_response_header)
body = self.application(env, self.set_response_header) header = "HTTP/1.1 %s\r\n" % self.status for temp in self.headers:
header += "%s:%s\r\n" % (temp[0], temp[1]) header += "\r\n" response = header+body
# 发送response给浏览器
new_socket.send(response.encode("utf-8")) # 关闭套接
new_socket.close() def set_response_header(self, status, headers):
self.status = status
self.headers = [("server", "mini_web v8.8")]
self.headers += headers def run_forever(self):
"""用来完成整体的控制""" while True:
# 4. 等待新客户端的链接
new_socket, client_addr = self.tcp_server_socket.accept() # 5. 为这个客户端服务
p = multiprocessing.Process(target=self.service_client, args=(new_socket,))
p.start() new_socket.close() # 关闭监听套接字
self.tcp_server_socket.close() def main():
"""控制整体,创建一个web 服务器对象,然后调用这个对象的run_forever方法运行"""
if len(sys.argv) == 3:
try:
port = int(sys.argv[1]) #
frame_app_name = sys.argv[2] # mini_frame:application
except Exception as ret:
print("端口输入错误。。。。。ret:",ret)
return
else:
print("请按照以下方式运行:")
print("python3 xxxx.py 7890 mini_frame:application")
return # mini_frame:application
ret = re.match(r"([^:]+):(.*)", frame_app_name)
if ret:
frame_name = ret.group(1) # mini_frame
app_name = ret.group(2) # application
else:
print("请按照以下方式运行:")
print("python3 xxxx.py 7890 mini_frame:application")
return with open("./web_server.conf") as f:
conf_info = eval(f.read()) # eval(str)函数很强大,官方解释为:将字符串str当成有效的表达式来求值并返回计算结果 # 此时 conf_info是一个字典里面的数据为:
# {
# "static_path":"./static",
# "dynamic_path":"./dynamic"
# } sys.path.append(conf_info['dynamic_path']) # import frame_name --->找frame_name.py
frame = __import__(frame_name) # 返回值标记这 导入的这个模板
app = getattr(frame, app_name) # 此时app就指向了 dynamic/mini_frame模块中的application这个函数 # print(app) wsgi_server = WSGIServer(port, app, conf_info['static_path'])
wsgi_server.run_forever() if __name__ == "__main__":
main()

web_server.py

 基于上篇的web_server.py实现了伪静态URL,即读取的URL中的页面filename是以.html结尾即视为动态资源,则调用框架读取数据库中资源替换模板。相当于欺骗浏览器,输入的是静态URL,确实按照动态URL的方式进行处理的;

 web_mini框架 mini_frame.py

import re
from pymysql import connect # 方式二:通过定义装饰器,自动添加文件名和函数名的映射关系,实现路由效果 URL_FUNC_DICT = dict()
# 带参数的装饰器
def route(url):
def get_func(func):
URL_FUNC_DICT[url] = func
def call_func(*args,**kwargs):
ret = func()
return ret
return call_func
return get_func def select_date(sql):
conn = connect(host="localhost",port=3306,database="stock_db",user="root",password= "mysql",charset="utf8")
cs = conn.cursor()
cs.execute(sql)
data_content = cs.fetchall() # 得到的是一个元组,里面有很多个元组
cs.close()
conn.close()
return data_content # 1.index = route("/index.py")即 index = get_func
# 2.index = get_func(index)即index = call_func
@route("/index.html")
def index():
with open("./templates/index.html") as f:
content = f.read() sql = "select * from info;"
my_stock_info = select_date(sql) html_template = """
<tr>
<td>{0}</td>
<td>{1}</td>
<td>{2}</td>
<td>{3}</td>
<td>{4}</td>
<td>{5}</td>
<td>{6}</td>
<td>{7}</td>
<td>
<input type="button" value="添加" id="toAdd" name="toAdd" >
</td>
</tr>
"""
html = ""
for temp in my_stock_info:
html += html_template.format(*temp)
# print("----->>>{}<<<---------".format(html)) content = re.sub(r"\{%content%\}", html, content) return content @route("/center.html")
def center():
with open("./templates/center.html") as f:
content = f.read() sql ="select i.code,i.short,i.chg,i.turnover,i.price,i.highs,f.note_info from info as i inner join focus as f on i.id=f.info_id;" my_stock_info = select_date(sql)
# print(mys)
html =""
html_template = """
<tr>
<td>{0}</td>
<td>{1}</td>
<td>{2}</td>
<td>{3}</td>
<td>{4}</td>
<td>{5}</td>
<td>{6}</td>
<td>
<a type="button" class="btn btn-default btn-xs" href="/update/index.html"> <span class="glyphicon glyphicon-star" aria-hidden="true"></span> 修改 </a>
</td>
<td>
<input type="button" value="删除" id="toDel" name="toDel" >
</td>
</tr>
"""
for temp in my_stock_info:
html += html_template.format(*temp) content = re.sub(r"\{%content%\}", html, content) return content # 方式一:这种方式通过映射,手动定义字典添加key为文件名:value为对应函数名;
# URL_FUNC_DICT = {
# "/index.py":index,
# "/center.py":center # } print(URL_FUNC_DICT) def application(env, start_response):
start_response('200 OK', [('Content-Type', 'text/html;charset=utf-8')]) file_name = env['PATH_INFO']
# file_name = "/index.py" run_func = URL_FUNC_DICT[file_name]
return run_func() # if file_name == "/index.py":
# return index()
# elif file_name == "/center.py":
# return center()
# else:
# return 'Hello World! 我爱你中国....'

mini_frame.py

 基于上篇的 mini_frame.py 实现了添加路由功能、及替换成MySQL数据库中的资源的效果;

  over~~~其他部分基本与其他相同~~~

 

02- web-mini框架添加路由、MySQL(二)的更多相关文章

  1. Web API中的路由(二)——属性路由

    一.属性路由的概念 路由让webapi将一个uri匹配到对应的action,Web API 2支持一种新类型的路由:属性路由.顾名思义,属性路由使用属性来定义路由.通过属性路由,我们可以更好地控制We ...

  2. Web API框架学习——路由(一)

    HttpConfiguration(ASP.NET Web API管道的配置是通过HttpConfiguration来完成) : 包括路由注册在内的对整个ASP.NET Web API管道的配置是通过 ...

  3. [Python之路] 使用装饰器给Web框架添加路由功能(静态、动态、伪静态URL)

    一.观察以下代码 以下来自 Python实现简易HTTP服务器与MINI WEB框架(利用WSGI实现服务器与框架解耦) 中的mini_frame最后版本的代码: import time def in ...

  4. ASP.NET Web API框架揭秘:路由系统的几个核心类型

    ASP.NET Web API框架揭秘:路由系统的几个核心类型 虽然ASP.NET Web API框架采用与ASP.NET MVC框架类似的管道式设计,但是ASP.NET Web API管道的核心部分 ...

  5. ASP.NET Web API 框架研究 ASP.NET Web API 路由

    ASP.NET Web API 核心框架是一个独立的.抽象的消息处理管道,ASP.NET Web API有自己独立的路由系统,是消息处理管道的组成部分,其与ASP.NET路由系统有类似的设计,都能找到 ...

  6. 从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建

    从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建 废话不说,直接撸步骤!!! 1.创建主项目:ncc-parent 选择maven创建项目,注意在创建项目中,packing选择 ...

  7. ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道

    Web Host 模式下的路由本质上还是通过ASP.NET 路由系统来进行路由的,只是通过继承和组合的方式对ASP.NET路由系统的内部的类进行了一些封装,产生自己专用一套类结构,功能逻辑基本都是一样 ...

  8. 国产 WEB UI 框架 (收费)-- Quick UI,Mini UI

    国产 WEB UI 框架 (收费)-- Quick UI,Mini UI : http://www.uileader.com/ http://www.miniui.com/

  9. express框架+jade+bootstrap+mysql开发用户注册登录项目

    完整的项目代码(github):https://github.com/suqinhui/express-demo express是基于Node.js平台的web应用开发框架,用express框架开发w ...

随机推荐

  1. Android 编译 product 分区

    https://source.android.google.cn/devices/bootloader/product-partitions 编译 product 分区 Android 9​ 支持使用 ...

  2. mac安装MySQLdb:IndexError: string index out of range

    使用mac安装MySQLdb的时候出现string index out of range 大概的错误是这样的: 然后尝试手动安装,我下载了包后,依然出现这个错误. 于是百度了下: https://ww ...

  3. python问题集

    1.selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in P ...

  4. C#中 ??、 ?、 ?: 、?.、?[ ] 问号

    1. 可空类型修饰符(?) 引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; 是正确的,int i=null; 编译器就会报错.为了使值类型也 ...

  5. Cannot start service WMSvc on computer '.'.

    批处理,管理员权限执形 taskkill /im wmsvc.exe /f net stop WMSVC net start WMSVC pause

  6. 移动端播放直播流(video.js 播放 m3u8 流)

    流媒体服务器: wowza 流媒体格式: m3u8 播放端:移动端网页(Android.IOS) 播放工具: video.js 代码如下: <!DOCTYPE html> <html ...

  7. [LeetCode] 245. Shortest Word Distance III 最短单词距离 III

    This is a follow up of Shortest Word Distance. The only difference is now word1 could be the same as ...

  8. LeetCode:字符串相加【415】

    LeetCode:字符串相加[415] 题目描述 给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和. 注意: num1 和num2 的长度都小于 5100.num1 和num2 都只 ...

  9. jquery json对象转换

    jquery json对象转换 <pre>//json数组转json串var arr = [1,2,3, { a : 1 } ];JSON.stringify( arr ); //json ...

  10. docker+k8s基础篇一

    Docker+K8s基础篇(一) docker的介绍 A:为什么是docker B:k8s介绍 docker的使用 A:docker的安装 B:docker的常用命令 C:docker容器的启动和操作 ...