若是你作的項目是偏向中小型的話,MTV或者MVC已經足夠支撐起整個項目,而若是你作的項目比較大大話,或者說可能之後的業務量很大的話,那你就須要用到四層架構的思想了,那麼咱們就各自分析下倆框架的結構。html
一、MVC前端
MVC是衆所周知的模式,即:將應用程序分解成三個組成部分:model(模型),view(視圖),和 controller(控制 器)。其中:
M 管理應用程序的狀態(一般存儲到數據庫中),並約束改變狀態的行爲(或者叫作「業務規則」)。
C 接受外部用戶的操做,根據操做訪問模型獲取數據,並調用「視圖」顯示這些數據。控制器是將「模型」和「視圖」隔離,併成爲兩者之間的聯繫紐帶。
V 負責把數據格式化後呈現給用戶。python
二、四層框架web
咱們一般所說的四層框架,其實是DAO層、Service層、Controller層、View層這四層的相互組合造成。ajax
DAO層:DAO層主要是作數據持久層的工做,負責與數據庫進行聯絡的一些任務都封裝在此,DAO層的設計首先是設計DAO的接口數據庫
Service層:Service層主要負責業務模塊的邏輯應用設計。一樣是首先設計接口,再設計其實現的類服務器
Controller層:Controller層負責具體的業務模塊流程的控制,在此層裏面要調用Serice層的接口來控制業務流程cookie
View層 : 此層與控制層結合比較緊密,須要兩者結合起來協同工發。View層主要負責前臺jsp頁面的表示session
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 == "123" 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()
#!/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
<!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>
#!/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]
全部類的繼承BaseRequestHandler,繼承後就能夠用Session class BaseRequestHandler(tornado.web.RequestHandler): def initialize(self): self.session = SessionFactory.get_session_obj(self)
經過self.session['xxx'] = xxx能夠儲存值
經過self.session['xxx']能夠取值
一、驗證規則文件
#!/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)
#!/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
三、自定義類
注意: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提交數據經常使用的幾種方式:
一、Get是向服務器發索取數據的一種請求
二、Post是向服務器提交數據的一種請求
三、Put是向服務器提交修改數據的一種請求
四、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中用於將字符串轉換成字典的格式