大體框架思想
如果你做的專案是偏向中小型的話,MTV或者MVC已經足夠支撐起整個專案,而如果你做的專案比較大大話,或者說可能以後的業務量很大的話,那你就需要用到四層架構的思想了,那麼我們就各自分析下倆框架的結構。
1、MVC
MVC是眾所周知的模式,即:將應用程式分解成三個組成部分:model(模型),view(檢視),和 controller(控制 器)。其中:
M 管理應用程式的狀態(通常儲存到資料庫中),並約束改變狀態的行為(或者叫做“業務規則”)。
C 接受外部使用者的操作,根據操作訪問模型獲取資料,並呼叫“檢視”顯示這些資料。控制器是將“模型”和“檢視”隔離,併成為二者之間的聯絡紐帶。
V 負責把資料格式化後呈現給使用者。
2、四層框架
我們通常所說的四層框架,實際上是DAO層、Service層、Controller層、View層這四層的相互組合形成。
DAO層:DAO層主要是做資料持久層的工作,負責與資料庫進行聯絡的一些任務都封裝在此,DAO層的設計首先是設計DAO的介面
Service層:Service層主要負責業務模組的邏輯應用設計。同樣是首先設計介面,再設計其實現的類
Controller層:Controller層負責具體的業務模組流程的控制,在此層裡面要呼叫Serice層的介面來控制業務流程
View層 : 此層與控制層結合比較緊密,需要二者結合起來協同工發。View層主要負責前臺jsp頁面的表示
UI--->Service---->Model------>Repository
驗證碼
驗證碼原理在於後臺自動建立一張帶有隨機內容的圖片,然後將內容通過img標籤輸出到頁面
安裝影象處理模組:
pip3 install pillow
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import io
import check_code
li = []
class CheckCodeHandler(tornado.web.RequestHandler):
def get(self):
mstream = io.BytesIO()
img, code = check_code.create_validate_code()
li.append(code) #這裡可以儲存到session中
img.save(mstream, "GIF")
self.write(mstream.getvalue())
print(code) class LoginHandler(tornado.web.RequestHandler):
def get(self):
self.render('login.html',status="")
def post(self, *args, **kwargs):
user = self.get_argument("user",None)
pwd = self.get_argument("pwd",None)
mima = self.get_argument("mima",None)
if user == "alex" and pwd == "" and mima.upper() == li[0].upper(): #不區分大小寫
self.write("登入成功")
else:
# self.redirect("/login")
self.render("login.html",status = "驗證碼錯誤") settings = {
'template_path': 'tpl',
'static_path': 'static',
'static_url_prefix': '/static/',
'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
} application = tornado.web.Application([
(r"/login", LoginHandler),
(r"/check_code", CheckCodeHandler),
], **settings) if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
start.py
#!/usr/bin/env python
#coding:utf-8
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小寫字母,去除可能干擾的i,l,o,z
_upper_cases = _letter_cases.upper() # 大寫字母
_numbers = ''.join(map(str, range(3, 10))) # 數字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) def create_validate_code(size=(120, 30),
chars=init_chars,
img_type="GIF",
mode="RGB",
bg_color=(255, 255, 255),
fg_color=(0, 0, 255),
font_size=18,
font_type="Monaco.ttf",
length=4,
draw_lines=True,
n_line=(1, 2),
draw_points=True,
point_chance = 2):
'''
@todo: 生成驗證碼圖片
@param size: 圖片的大小,格式(寬,高),預設為(120, 30)
@param chars: 允許的字元集合,格式字串
@param img_type: 圖片儲存的格式,預設為GIF,可選的為GIF,JPEG,TIFF,PNG
@param mode: 圖片模式,預設為RGB
@param bg_color: 背景顏色,預設為白色
@param fg_color: 前景色,驗證碼字元顏色,預設為藍色#0000FF
@param font_size: 驗證碼字型大小
@param font_type: 驗證碼字型,預設為 ae_AlArabiya.ttf
@param length: 驗證碼字元個數
@param draw_lines: 是否劃干擾線
@param n_lines: 干擾線的條數範圍,格式元組,預設為(1, 2),只有draw_lines為True時有效
@param draw_points: 是否畫干擾點
@param point_chance: 干擾點出現的概率,大小範圍[0, 100]
@return: [0]: PIL Image例項
@return: [1]: 驗證碼圖片中的字串
''' width, height = size # 寬, 高
img = Image.new(mode, size, bg_color) # 建立圖形
draw = ImageDraw.Draw(img) # 建立畫筆 def get_chars():
'''生成給定長度的字串,返回列表格式'''
return random.sample(chars, length) def create_lines():
'''繪製干擾線'''
line_num = random.randint(*n_line) # 干擾線條數 for i in range(line_num):
# 起始點
begin = (random.randint(0, size[0]), random.randint(0, size[1]))
#結束點
end = (random.randint(0, size[0]), random.randint(0, size[1]))
draw.line([begin, end], fill=(0, 0, 0)) def create_points():
'''繪製干擾點'''
chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100] for w in range(width):
for h in range(height):
tmp = random.randint(0, 100)
if tmp > 100 - chance:
draw.point((w, h), fill=(0, 0, 0)) def create_strs():
'''繪製驗證碼字元'''
c_chars = get_chars()
strs = ' %s ' % ' '.join(c_chars) # 每個字元前後以空格隔開 font = ImageFont.truetype(font_type, font_size)
font_width, font_height = font.getsize(strs) draw.text(((width - font_width) / 3, (height - font_height) / 3),
strs, font=font, fill=fg_color) return ''.join(c_chars) if draw_lines:
create_lines()
if draw_points:
create_points()
strs = create_strs() # 圖形扭曲引數
params = [1 - float(random.randint(1, 2)) / 100,
0,
0,
0,
1 - float(random.randint(1, 10)) / 100,
float(random.randint(1, 2)) / 500,
0.001,
float(random.randint(1, 2)) / 500
]
img = img.transform(size, Image.PERSPECTIVE, params) # 建立扭曲 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 濾鏡,邊界加強(閾值更大) return img, strs
check_code.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
<p><input name="user" placeholder="使用者名稱" type="text"></p>
<p><input name="pwd" placeholder="密碼" type="text"></p>
<p>
<input name="mima" placeholder="驗證碼" type="text" >
<img src="/check_code" onclick='ChangeCode();' id='imgCode'>
</p>
<input type="submit" value="提交"><span style="color: red">{{status}}</span>
</form>
<script>
function ChangeCode() {
var code = document.getElementById('imgCode');
code.src += '?';
}
</script>
</body>
</html>
html
Session全套
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from hashlib import sha1
import os
import time create_session_id = lambda: sha1(bytes('%s%s' % (os.urandom(16), time.time()), encoding='utf-8')).hexdigest() class SessionFactory: @staticmethod
def get_session_obj(handler):
obj = CacheSession(handler)
return obj class CacheSession:
session_container = {}
session_id = "__sessionId__" def __init__(self, handler):
self.handler = handler
client_random_str = handler.get_cookie(CacheSession.session_id, None)
if client_random_str and client_random_str in CacheSession.session_container:
self.random_str = client_random_str
else:
self.random_str = create_session_id()
CacheSession.session_container[self.random_str] = {} expires_time = time.time() + 60 * 20
handler.set_cookie(CacheSession.session_id, self.random_str, expires=expires_time) def __getitem__(self, key):
ret = CacheSession.session_container[self.random_str].get(key, None)
return ret def __setitem__(self, key, value):
CacheSession.session_container[self.random_str][key] = value def __delitem__(self, key):
if key in CacheSession.session_container[self.random_str]:
del CacheSession.session_container[self.random_str][key]
Session.py
所有類的繼承BaseRequestHandler,繼承後就可以用Session class BaseRequestHandler(tornado.web.RequestHandler):
def initialize(self):
self.session = SessionFactory.get_session_obj(self)
通過self.session['xxx'] = xxx可以儲存值
通過self.session['xxx']可以取值
Form驗證
1、驗證規則檔案
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
import os class Field: def __init__(self): self.is_valid = False
self.name = None
self.value = None
self.error = None def match(self, name, value):
self.name = name if not self.required:
self.is_valid = True
self.value = value
else:
if not value:
if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % name
else:
ret = re.match(self.REGULAR, value)
if ret:
self.is_valid = True
self.value = value
else:
if self.custom_error_dict.get('valid', None):
self.error = self.custom_error_dict['valid']
else:
self.error = "%s is invalid" % name class StringField(Field): REGULAR = "^.*$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能為空', 'valid': 'IP格式錯誤'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required super(StringField, self).__init__() class IPField(Field): REGULAR = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能為空', 'valid': 'IP格式錯誤'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required
super(IPField, self).__init__() class EmailField(Field): REGULAR = "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能為空', 'valid': 'IP格式錯誤'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required
super(EmailField, self).__init__() class IntegerField(Field): REGULAR = "^\d+$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能為空', 'valid': 'IP格式錯誤'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required
super(IntegerField, self).__init__() class CheckBoxField(Field): REGULAR = "^\d+$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能為空', 'valid': 'IP格式錯誤'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required
super(CheckBoxField, self).__init__() def match(self, name, value):
self.name = name if not self.required:
self.is_valid = True
self.value = value
else:
if not value:
if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % name
else:
if isinstance(name, list):
self.is_valid = True
self.value = value
else:
if self.custom_error_dict.get('valid', None):
self.error = self.custom_error_dict['valid']
else:
self.error = "%s is invalid" % name class FileField(Field): REGULAR = "^(\w+\.pdf)|(\w+\.mp3)|(\w+\.py)$" def __init__(self, custom_error_dict=None, required=True): self.custom_error_dict = {} # {'required': 'IP不能為空', 'valid': 'IP格式錯誤'}
if custom_error_dict:
self.custom_error_dict.update(custom_error_dict) self.required = required super(FileField, self).__init__() def match(self, name, file_name_list):
flag = True
self.name = name if not self.required:
self.is_valid = True
self.value = file_name_list
else:
if not file_name_list:
if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % name
flag = False
else:
for file_name in file_name_list:
if not file_name or not file_name.strip():
if self.custom_error_dict.get('required', None):
self.error = self.custom_error_dict['required']
else:
self.error = "%s is required" % name
flag = False
break
else:
ret = re.match(self.REGULAR, file_name)
if not ret:
if self.custom_error_dict.get('valid', None):
self.error = self.custom_error_dict['valid']
else:
self.error = "%s is invalid" % name
flag = False
break self.is_valid = flag def save(self, request, upload_to=""): file_metas = request.files[self.name]
for meta in file_metas:
file_name = meta['filename']
file_path_name = os.path.join(upload_to, file_name)
with open(file_path_name, 'wb') as up:
up.write(meta['body']) upload_file_path_list = map(lambda path: os.path.join(upload_to, path), self.value)
self.value = list(upload_file_path_list)
fields.py
2、驗證檔案(繼承fields)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from backend.form import fields class BaseForm: def __init__(self):
self._value_dict = {}
self._error_dict = {}
self._valid_status = True def valid(self, handler): for field_name, field_obj in self.__dict__.items():
if field_name.startswith('_'):
continue if type(field_obj) == fields.CheckBoxField:
post_value = handler.get_arguments(field_name, None)
elif type(field_obj) == fields.FileField:
post_value = []
file_list = handler.request.files.get(field_name, [])
for file_item in file_list:
post_value.append(file_item['filename'])
else:
post_value = handler.get_argument(field_name, None) field_obj.match(field_name, post_value)
if field_obj.is_valid:
self._value_dict[field_name] = field_obj.value
else:
self._error_dict[field_name] = field_obj.error
self._valid_status = False
return self._valid_status
forms
3、自定義類
注意:self.xxx = yyy(),其中xxx為需要驗證的欄位,即你再input中定義的name屬性的值,右邊的為驗證的規則,自定義類必須繼承驗證檔案的類
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from backend.form.forms import BaseForm
from backend.form.fields import StringField
from backend.form.fields import IntegerField class LoginForm(BaseForm): def __init__(self):
self.user = StringField()
self.password = StringField()
self.code = StringField()
super(LoginForm, self).__init__()
form = LoginForm(自定義類)() 得到一個物件
通過 form.valid(self)可以驗證使用者提交的內容是否通過驗證--------必須把self傳進去為了獲取值
通過form._value_dict可以獲取使用者提交的所有內容
通過form._error_dict可以獲取錯誤資訊,用於在前端展示
傳送資料的幾種方式
在一個頁面上也許會有增加,修改,和刪除等功能,這裡可能需要我們需要到一個模板,並提交資料,由於增加和修改的時候,我們所需要的資料大致相同,所以我們可以利用一個模板進行提交資料,而且提交資料的時候我們也可以用同一個ajax進行提交
ajax提交資料常用的幾種方式:
1、Get是向伺服器發索取資料的一種請求
2、Post是向伺服器提交資料的一種請求
3、Put是向伺服器提交修改資料的一種請求
4、Delete是向伺服器提交刪除資料的一種請求
我們可以提前申明一個變數 var METHOD
當用戶點選新增的時候我們把變數賦值為METHOD = 'post';
當用戶點選修改的時候我們把變數賦值為METHOD = 'put';
當用戶點選刪除的時候我們把變數賦值為METHOD = 'delete';
這樣我們就不用重複的寫ajax,提高了程式碼的重用性
ret = JSON.stringify(ret)
$.ajax({
type:METHOD,
url: '/commodity',
data: {'ret':ret},
success:function (arg) {
location.reload()
}
});
ret = JSON.stringify(ret)在JavaScript中用於將字典轉換成字串的格式
ret =JSON.parse(ret)在JavaScript中用於將字串轉換成字典的格式