登陆与注册注册功能: 流程: 填写用户名,邮箱,获取邮箱验证码,填入密码 单击<下一步>按钮,完成注册! 1.获取邮箱验证码(具体步骤分析): 1.利用ajax 往后台传入邮箱, 2.后台表单验证,邮箱填写是否正确, => 成功,则继续3, => 错误,写入错误信息,页面输出错误提示! 3.查询sendcode 数据库表,查询该邮箱是否是第一次发送验证码 => 第一次发送: 数据表中插入记录 (邮箱,发送次数1,邮箱验证码,状态1,有效时间:当前时间-1小时) => 否则: 从数据表中查询出该邮箱验证码发送次数, => 如果 >5 则,再判断上次发送时间+1小时 是否大于当前时间! => 大于当前时间,则发送验证码,修改数据表记录 (发送次数+1,邮箱验证码,有效时间) => 小于当前时间,则为多次恶意发送,不操作,写入错误信息,需要等待1小时, => 如果<5 则直接发送验证码,修改数据表记录 (发送次数+1,邮箱验证码,有效时间) 4.json信息返回。 ![]() ![]() ![]() 2.验证码发送过程: 页面倒计时 原理:设计计时器,每1秒修改1次text值, 时间小于0时,取消计时器 ![]() 3.账号注册 1.JQ获取前台输入表单内容 2.ajax传输给后台,建立表单验证 => 正确,继续3 => 错误,返回错误信息,页面显示错误信息 3.数据库中查询用户邮箱是否存在 => 不存在,插入数据库,继续4 => 存在,返回错误信息,页面显示 4.注册账号完成,写入session,注册完成页面刷新实现自动登录 ![]() ![]() 表单错误时,页面信息提示(效果图): 登录功能: 原理:与注册功能类似 1.图片验证码:点击验证码,自动更改 验证码为后台生成的图片,每点击一次,src地址后面 多加?实现切换 <div class="inp-block"> <input type="text" name="phoneregister" placeholder="请输入验证码" id="u-code" class="phonenum" autocomplete="off"/> <img src="/check_code" onclick='ChangeCode();' id='imgCode' class="codeimg"> </div> ![]() ![]() ![]() ![]() ![]() 表单验证设计思想: 无论表单通过form形式,或者ajax形式,发送数据给后端,我们都要先通过:某些规则进行过滤和验证,再对其进行数据的插入,修改等操作 实现思路:1,有form表单数据来临时,初始化一个表单类,传入self; 2,自动获取form上数据字段,self.get_arguments(name),name与前端input标签的name名字一一对应; 3,通过表单类,调用检测方法 check_value(), 4,如果form表单数据,符合自定义的规则,以字典形式返回数据,{ ‘前端input的name值’:‘input的value值’ } =》 存储在表单类的 self._value_dict 中 5,如果form表单数据,不符合自定义的规则,以字典形式返回错误信息,{ ‘前端input的name值’:‘错误信息’ } =》 存储在表单类的 self._error_dict 中
1. 定义一个表单类 LoginForm ,__init__方法中对象名为 前端input标签的name值 required 是否可以为空值, error_dict 定义错误信息输出内容 class LoginForm(BaseForm): def __init__(self): self.username = UsernameField(required=True,error_dict={'required':'用户名不能为空' , 'valid':'用户名错误'}) self.password = PasswordField(required=True,error_dict={'required':'密码不能为空' , 'valid':'用户名或密码错误'}) self.code = CodeField(required=True,error_dict={'required':'验证码不能为空' , 'valid':'验证码错误'}) self.remember = CheckBoxField(required=False,error_dict={'valid':'格式错误'}) super(LoginForm, self).__init__() 2. 继承BaseForm类,该类初始化了,当前Form表单共用的最后返回数据和错误信息的字典对象 class BaseForm(): def __init__(self): self._value_dict = {} self._error_dict = {} self._valid_status = True def check_value(self): .... check_value() 执行获取前端输入的数据,self.get_argument(xxxx) 并且根据每个input标签定义的规则去验证数据的正确性 (上文的UsernameField,PasswordField..等) 通过self.__dict__循环获取LoginForm的成员对象,调用Field的validate()方法,验证Form表单中每一个的值。验证正确,信息存储在self._value_dict 中, 错误信息存储在self._error_dict 中 def check_value(self,handler): for key,regular in self.__dict__.items(): input_value = handler.get_argument(key,None) regular.validate(key,input_value) if regular.is_valid: self._value_dict[key] = regular.value else: self._error_dict[key] = regular.error ![]() 3. Field 自定义的规则类 为前端input标签,定义不同的验证规则(正则表达式),验证用户输入的数据 class PasswordField(Field): REGULAR = "[0-9 | A-Z | a-z]{6,16}" def __init__(self,required=True,error_dict=None): self.error_dict = {} #错误信息 if error_dict: self.error_dict.update(error_dict) #用户自定义的错误信息 self.required = required super(PasswordField, self).__init__() 继承父类Field,初始化存储信息的成员 class Field: def __init__(self): self.is_valid = False # 验证规则是否通过,默认False self.name = None self.value = None # 获取的前端input值 self.error = None def validate(self, name, input_value): ... 执行validate()方法, 1.先判断该值是否允许为空?, => 可以为空,验证通过,self.value = input输入值 => 不可以为空, 判断 input输入值 是否为空? => input输入值为空,self.error = 定义的错误信息(required) => 不为空,继续正则表达式判断,re.match(REGULAR,input_value) => 正则通过,self.value = input输入值, self.is_valid = True => 正则不通过, self.error = 定义的错误信息(valid) ![]() 自定义的Field 供参考: ![]() ![]() ![]() Session设计思想: 利用Cookie 自定义一个Session来存储每个用户信息 实现思路: 1. Session信息设计成一个大字典,key对应用户唯一识别加密串,value对应空字典{}存储用户信息,存放在服务端上。 2. 为用户请求生成一个唯一加密串,写入到Cookie信息中,Session_id = 加密串,用于区分每一个用户。 3. 当用户请求到来时,获取该请求的Cookie信息,判断是否存在Session_id(用户唯一识别加密串)? => 如果存在Session_id 并且在 Session大字典中找到相同的 key,记录Session_id => 其他情况下一律,生成加密串,写入到Cookie中,同时写入到 Session大字典中 class CacheSession(): session_id = "__balabala__" # Cookie中为Session存储的名字 session_container = {} # Session大字典 def __init__(self,handler): self.handler = handler client_random_str = self.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 = self.__container__random__str() CacheSession.session_container[self.random_str] = {} expires_time = time.time() + config.SESSION_EXPIRES self.handler.set_cookie(CacheSession.session_id, self.random_str, expires=expires_time) # 方便后续定义过期时间! def __container__random__str(self): # 生成加密串 hash = hashlib.md5() hash.update(bytes(str(time.time()), encoding='utf-8')) random_str = hash.hexdigest() return random_str 利用方法:1. 当用户请求到达每个Handler时,我们都需要先实例化一个CacheSession(), 2. 此时我们可以定义一个父类BaseHandler,initialize() 方法中写入要执行代码, import tornado.web form session import SessionFactory class BaseHandler(tornado.web.RequestHandler): def initialize(self): self.session = SessionFactory.get_session_obj(self) 可以看到,我们在session.py中定义了一个新的类SessionFactory,用来选择合适的方法,初始化Session, 该类通过读取配置文件config中的SESSION_TYPE选择适合的Session类进行初始化,并且返回一个Session对象,该对象最终存储在 self.session中。 class SessionFactory(): @staticmethod def get_session_obj(handler): if config.SESSION_TYPE == 'cache': obj = CacheSession(handler) elif config.SESSION_TYPE == 'memcached': obj = MemcachedSession(handler) elif config.SESSION_TYPE == 'redis': obj = RedisSession(handler) return obj Handler 中使用Session class LoginUserHandler(BaseHandler): def post(self, *args, **kwargs): self.session['is_login'] = 1 self.write('ok') 1.缓存Session ![]() 2.memcache session ![]() 3.radis session ![]() 需要注意的是:__setitem__,__getitem__和__delitem__ 使用类似字典方式设置,访问,删除成员。 在缓存Session 中,他们的使用方法与字典差别不大。 在memcache 中,键值对key,value 都是以字符串的形式存储的, 在设置值前需要将value值通过json转换成字典形式,再对字典进行操作,操作完毕后,用json转换回字符串,存储回原来位置! 在redis 中,选用hash操作进行存储,如果待存储的value值为字典,需要先把value通过json转换成字符串,再存储在redis中, 获取某个key的value值时,由于hash中value是以bytes存储,需要先转换成str类型,再判断该key存储的是字典,还是普通字符串 Session所有的完整代码: ![]() ![]() ![]() 分页设计思路:与Tornado篇分页同理 前端: ![]() 后台Url配置:
后台Handle: class IndexHandler(BaseHandler): def get(self, page): query = QueryContent() page_obj = pager.Pagiantion(page, all_item=query.queryCounts(), per_num=5) #page 当前页码 , all_item 总数据条数, per_num 每页显示条数 str_page = page_obj.page_str('/index/') self.render("index.html", str_page=str_page ) Pagiantion 分页类: ![]() ![]() 页面登陆验证(装饰器方式实现)1.普通登陆验证
2.ajax提交数据的登陆验证
文件上传为了美观 , 文件上传标签一半由两部分组成 file标签和 button标签
file标签会设置 透明度 和 定位在button上 , 绑定onchange事件 .up-block{ position: relative; } .file-path{ position: absolute; width: ..px; height: ..px; font-size: ..px; opacity: 0; z-index: 10; } 图片上传后,展示在上传页面: 方法一:利用iframe实现 ![]() 抽屉网实现,完整代码: ![]() ![]() ![]() 方法二:ajax实现 通过Ajax的FormData对象来实现。详情参考ajax篇
|
|