tornado項目注意點

大致框架思想

若是你作的項目是偏向中小型的話,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()
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驗證

一、驗證規則文件

#!/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

二、驗證文件(繼承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

三、自定義類

注意: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中用於將字符串轉換成字典的格式

相關文章
相關標籤/搜索