五、用户名校验是否注册
1. 接口设计
1)接口说明
(?pgroup)这个格式的意思,在正则中是指给匹配到的group组名命名一个名称,且该名称是唯一的
例如:(?p\d{4}) 是匹配带有4个数字的,
(?p\w{4}) 是匹配带有4个字母的。
\w{5,20} 则代表我们输入的字母需要是5~20位数字的。
2)返回数据
返回结果为json数据:
{ "errno": 0 , "errmsg": "OK", "data": { "username":"username", # 查询用户名 "count": 1 # 用户查询数量 }, }
2. 后端代码
1)检查用户名是否注册的后端视图(first_project------>apps----->verivication----->view.py)
# 一、系统模块 import logging # 记录日志我们需要导入日志模块 # 二、django模块 from django.shortcuts import render # django渲染页面模块 from django.http import HttpResponse, JsonResponse # django的响应模块(本视图由于我们返回图片验证码需要使用它) # 三、自己的库 from untils.captcha.captcha import captcha # 导入生成图形验证码的第三方模块 from . import constants # 导入我们创建的用来存放常量的py文件 from user.models import User # 导入我们写好的用户模型类 # 日志器 logger = logging.getLogger('django') # 生成一个名叫django的日志器 # 检查用户名是否注册(由于该方法只使用get访问,所以我们使用函数视图即可) def check_username_view(request, username): """ username 用来获取路径参数username,所以该username需要与url中设置的username名称相同 函数功能:校验用户名 url: /username/(?P\w{5,20})/ :param request: :param username: :return: """ # 到数据库查询数据并返回 data = { "errno": 0, "errmsg": "OK", "data": { "username": username , # 查询用户名 "count": User.objects.filter(username=username).count() # 用户查询数量 }, } # 返回json数据 return JsonResponse(data)
2)url设置
3. 前端代码
1)前端用户名是否注册js验证
壹:首先导入一个写好的js文件,该文件用来提示各种信息
"use strict"; // 消息提示框 function Message() { // 判断是否加载 this.isAppended = false; // 提示框的宽度 this.wrapperWidth = 400; // 提示框的高度 this.wrapperHeight = 48; // 提示框初始化样式 this.initStyle(); // 提示框初始化元素 this.initElement(); // 提示框监听关闭按钮 this.listenCloseEvent(); } // 初始化样式 Message.prototype.initStyle = function () { // 错误消息文字和背景样式 this.errorStyle = { "wrapper": { "background": "#f8d7da", "color": "#dc3545" }, "close": { "color": "#993d3d" } }; // 成功消息文字和背景样式 this.successStyle = { "wrapper": { "background": "#d4edda", "color": "#28a745" }, "close": { "color": "#468847" } }; // 描述信息文字和背景样式 this.infoStyle = { "wrapper": { "background": "#d1ecf1", "color": "#17a2b8" }, "close": { "color": "#5bc0de" } }; }; // 初始化元素 Message.prototype.initElement = function () { // 设置提示框元素 this.wrapper = $(""); // 设置提示框整体样式 this.wrapper.css({ 'padding': '10px', 'font-size': '14px', 'width': this.wrapperWidth, 'position': 'fixed', 'z-index': 99999, 'left': 'calc(50% - ' + this.wrapperWidth / 2 + 'px)', 'top': -this.wrapperHeight, 'height': this.wrapperHeight, 'box-sizing': 'border-box', 'border': '1px solid #ddd', 'border-radius': '5px', 'line-height': 'calc(' + this.wrapperHeight / 2 + 'px)', 'font-weight': 600 }); // 生成关闭按钮 this.closeBtn = $("×"); // 关闭按钮的样式 this.closeBtn.css({ 'float': 'right', 'cursor': 'pointer', 'font-size': '24px', 'font-weight': 500 }); // 提示文字的元素生成 this.messageSpan = $(""); // 将提示文字的元素和关闭按钮添加到提示框中 this.wrapper.append(this.messageSpan); this.wrapper.append(this.closeBtn); }; // 关闭按钮的事件 Message.prototype.listenCloseEvent = function () { var _this = this; // 点击关闭 this.closeBtn.click(function () { _this.wrapper.animate({ "top": -_this.wrapperHeight }); }); }; // 显示异常 Message.prototype.showError = function (message) { this.show(message, "error"); }; Message.prototype.showSuccess = function (message) { this.show(message, "success"); }; Message.prototype.showInfo = function (message) { this.show(message, "info"); }; // 提示框的显示 Message.prototype.show = function (message, type) { var _this2 = this; // 如果没有添加 则添加 if (!this.isAppended) { $(document.body).append(this.wrapper); this.isAppended = true; } // 将各种提示的文字添加对应不同的样式 this.messageSpan.text(message); if (type === "error") { this.wrapper.css(this.errorStyle['wrapper']); this.closeBtn.css(this.errorStyle['close']); } else if (type === "info") { this.wrapper.css(this.infoStyle['wrapper']); this.closeBtn.css(this.infoStyle['close']); } else if (type === "success") { this.wrapper.css(this.successStyle['wrapper']); this.closeBtn.css(this.successStyle['close']); } // 设置两秒后自动关闭 this.wrapper.animate({ "top": 0 }, function () { setTimeout(function () { _this2.wrapper.animate({ "top": -_this2.wrapperHeight }); }, 2500); }); }; // 将对象绑定到 window 上 window.message = new Message();
该文件需要放在静态文件的js中的目录下:(文件路径:first_project--->static---->js----->base----->message.js)
贰:在register.js文件中写入验证用户是否注册的js(文件路径:first_project--->static---->js----->user----->register.js)
$(()=>{ //es6中的用法 // 1. 点击刷新我们的图片验证码 $('.captcha-graph-img img').click(function () { // 重新加载一下图片验证码的src即可 $(this).attr('src','../verification/image_code/?rand=' + Math.random()); }); // 2. 校验功能 // 定义一些状态变量 let isUsernameReady = false, // 用户名是否准备好 isPasswordReady = false, // 密码是否准备好 isMobileReady = false, // 手机号是否准备好 isSmsCodeReady = false; // 短信验证码是否准备好 // 3. 用户名校验(光标离开用户名输入框就校验用户名) let $form_msg = $('.form-control'); let $username = $form_msg.eq(0); //1. 获得用户名输入的对象 $username.blur(fnCheckUsername); //2. 当焦点离开用户名输入框时执行fnCheckUsername这个函数 function fnCheckUsername() { //3. 该函数用来校验用户名是否注册过,并响应结果给我们 // 默认未经校验的用户名为假,不通过校验 isUsernameReady = false; // 获得我们输入的用户名 let sUsername = $username.val(); // 判断用户输入的用户名格式是否正确 if(sUsername === ""){ message.showError("用户名不能为空!"); }else if(!(/^\w{5,20}$/).test(sUsername)){ message.showError("请输入5-20个字符的用户名"); }else{ // 格式正确且不为空则发送ajax到后台(ajax是依赖于浏览器的一种技术) $.ajax({ url: '../verification/username/'+ sUsername + '/', type: 'GET', dataType: 'json', success: function (res) { if(res.data.count!==0){ message.showError(res.data.username+"已经注册,请重新输入!"); }else{ isUsernameReady = True; message.showInfo(res.data.username+"可以正常使用!"); } }, error: function () { message.showError("服务器超时,请重试!"); } }); } } });
六、密码校验是否成功
1. 前端js代码(first_project--->static---->js----->user----->register.js)
$(()=>{ //es6中的用法 // 1. 点击刷新我们的图片验证码 $('.captcha-graph-img img').click(function () { // 重新加载一下图片验证码的src即可 $(this).attr('src','../verification/image_code/?rand=' + Math.random()); }); // 2. 校验功能 // 定义一些状态变量 let isUsernameReady = false, // 用户名是否准备好 isPasswordReady = false, // 密码是否准备好 isMobileReady = false, // 手机号是否准备好 isSmsCodeReady = false; // 短信验证码是否准备好 // 3. 用户名校验(光标离开用户名输入框就校验用户名) let $form_msg = $('.form-control'); let $username = $form_msg.eq(0); //1. 获得用户名输入的对象 $username.blur(fnCheckUsername); //2. 当焦点离开用户名输入框时执行fnCheckUsername这个函数 function fnCheckUsername() { //3. 该函数用来校验用户名是否注册过,并响应结果给我们 // 默认未经校验的用户名为假,不通过校验 isUsernameReady = false; // 获得我们输入的用户名 let sUsername = $username.val(); // 判断用户输入的用户名格式是否正确 if(sUsername === ""){ message.showError("用户名不能为空!"); }else if(!(/^\w{5,20}$/).test(sUsername)){ message.showError("请输入5-20个字符的用户名"); }else{ // 格式正确且不为空则发送ajax到后台(ajax是依赖于浏览器的一种技术) $.ajax({ url: '../verification/username/'+ sUsername + '/', type: 'GET', dataType: 'json', success: function (res) { if(res.data.count!==0){ message.showError(res.data.username+"已经注册,请重新输入!"); }else{ isUsernameReady = true; message.showInfo(res.data.username+"可以正常使用!"); } }, error: function () { message.showError("服务器超时,请重试!"); } }); } } // 4. 密码校验 // 获得用户输入的两次密码的对象 let $password1 = $form_msg.eq(1), $password2 = $form_msg.eq(2); // 当焦点离开第二次输入的密码框的时候触发函数 $password2.blur(fnCheckPassword); // 该函数检查用户两次输入的密码是否一样 function fnCheckPassword() { if($password1.val() === ""){ message.showError("密码不能为空"); }else if($password1.val() !== $password2.val()){ message.showError("两次密码输入不一致,请重新输入"); }else{ isPasswordReady = true; message.showInfo("密码可以正常使用!"); } } });
七、电话号码校验
1. 接口设计
1)接口说明
2)返回数据
返回结果为json数据:
{ "errno": 0 , "errmsg": "OK", "data": { "mobile":"mobile", # 查询手机号码 "count": 1 # 手机号查询数量 }, }
2. 后端代码
1)检查手机号是否注册的视图(first_project------>apps----->verivication----->view.py)
# 一、系统模块 import logging # 记录日志我们需要导入日志模块 # 二、django模块 from django.shortcuts import render # django渲染页面模块 from django.http import HttpResponse, JsonResponse # django的响应模块(本视图由于我们返回图片验证码需要使用它) # 三、自己的库 from untils.captcha.captcha import captcha # 导入生成图形验证码的第三方模块 from . import constants # 导入我们创建的用来存放常量的py文件 from user.models import User # 导入我们写好的用户模型类 # 日志器 logger = logging.getLogger('django') # 生成一个名叫django的日志器 # 1.生成图形验证码 def image_code_view(request): """ 功能:生成验证码 url : /image_code/ :param request: :return: """ # 1. 生成验证码(随机生成字符和图片) text, image = captcha.generate_captcha() # 调用该方法会给我们返回两个值,一个是验证码的文字内容,一个是验证码的图片 # 2. 在后端保存验证码(为了之后校验验证码是否正确,所以现在我们需要保存验证码) request.session['image_code'] = text # 将验证码文字部分存放在session中 # 给验证码一个过期时间,为了方便日后修改,我们在校验app中创建一个constants.py的文件,用来存放常量 # 导入方式为 from . import constants request.session.set_expiry(constants.IMAGE_CODE_EXPIRES) # 设置session过期时间 # 3. 记录一个日志 logger.info('Image_code:{}'.format(text)) # 4. 返回验证码图片 # image存储的是图片的二进制数据,content指定了返回的数据内容, # content_type指定了返回数据的类型,告诉浏览器我们返回的是一张图片 return HttpResponse(content=image, content_type='image/jpg') # 2.检查用户名是否注册(由于该方法只使用get访问,所以我们使用函数视图即可) def check_username_view(request, username): """ username 用来获取路径参数username,所以该username需要与url中设置的username名称相同 函数功能:校验用户名 url: /username/(?P\w{5,20})/ :param request: :param username: :return: """ # 到数据库查询数据并返回 data = { "errno": 0, "errmsg": "OK", "data": { "username": username , # 查询用户名 "count": User.objects.filter(username=username).count() # 用户查询数量 }, } # 返回json数据 return JsonResponse(data) # 3.检查手机号码是否注册(由于该方法只使用get访问,所以我们使用函数视图即可) def check_mobile_view(request, mobile): """ 函数功能:校验手机号码 url: /mobile/(?P1[3-9]\d{9})/ :param request: :param username: :return: """ # 到数据库查询数据并返回 data = { "errno": 0, "errmsg": "OK", "data": { "mobile": mobile , # 查询手机号码 "count": User.objects.filter(mobile=mobile).count() # 手机号码查询数量 }, } # 返回json数据 return JsonResponse(data)
2) 设置该视图的路由
from django.urls import path,re_path from . import views urlpatterns = [ path('image_code/', views.image_code_view, name='image_code'), # 图形验证码路由 re_path('username/(?P\w{5,20})/ ',views.check_username_view, name='check_username'), # 检查用户名是否注册路由 re_path('mobile/(?P1[3-9]\d{9})/ ',views.check_mobile_view, name='check_mobile'), # 检查手机号码是否注册路由 ]
3. 前端代码(文件路径:first_project--->static---->js----->user----->register.js)
$(()=>{ //es6中的用法 // 1. 点击刷新我们的图片验证码 $('.captcha-graph-img img').click(function () { // 重新加载一下图片验证码的src即可 $(this).attr('src','../verification/image_code/?rand=' + Math.random()); }); // 2. 校验功能 // 定义一些状态变量 let isUsernameReady = false, // 用户名是否准备好 isPasswordReady = false, // 密码是否准备好 isMobileReady = false, // 手机号是否准备好 isSmsCodeReady = false; // 短信验证码是否准备好 // 3. 用户名校验(光标离开用户名输入框就校验用户名) let $form_msg = $('.form-control'); // 获得表单对象 let $username = $form_msg.eq(0); //1. 获得表单中的第一个,用户名输入框的对象 $username.blur(fnCheckUsername); //2. 当焦点离开用户名输入框时执行fnCheckUsername这个函数 function fnCheckUsername() { //3. 该函数用来校验用户名是否注册过,并响应结果给我们 isUsernameReady = false; // 默认未经校验的用户名为假,不通过校验 let sUsername = $username.val(); // 获得我们输入的用户名 if(sUsername === ""){ // 判断用户输入的用户名格式是否正确 message.showError("用户名不能为空!"); }else if(!(/^\w{5,20}$/).test(sUsername)){ message.showError("请输入5-20个字符的用户名"); }else{ $.ajax({ // 格式正确且不为空则发送ajax到后台(ajax是依赖于浏览器的一种技术) url: '../verification/username/'+ sUsername + '/', type: 'GET', dataType: 'json', success: function (res) { if(res.data.count!==0){ message.showError(res.data.username+"已经注册,请重新输入!"); }else{ isUsernameReady = true; message.showInfo(res.data.username+"可以正常使用!"); } }, error: function () { message.showError("服务器超时,请重试!"); } }); } } // 4. 密码校验 // 获得用户输入的两次密码的对象 let $password1 = $form_msg.eq(1), $password2 = $form_msg.eq(2); // 当焦点离开第二次输入的密码框的时候触发函数 $password2.blur(fnCheckPassword); // 该函数检查用户两次输入的密码是否一样 function fnCheckPassword() { isPasswordReady = false; // 默认密码错误 if($password1.val() === ""){ message.showError("密码不能为空"); }else if($password1.val() !== $password2.val()){ message.showError("两次密码输入不一致,请重新输入"); }else{ isPasswordReady = true; // 校验成功后我们设置密码正确 message.showInfo("密码可以正常使用!"); } } // 5. 手机号码校验 // 获得用户手机号输入框对象 let $mobile = $form_msg.eq(3); // 1. 获得表单中的第四个,手机号码输入框的对象 $mobile.blur(fnCheckMobile); // 2. 当焦点离开手机号输入框时触发函数 function fnCheckMobile() { // 3. 该函数校验手机号码是否正确 isMobileReady = false; // 3.1 默认手机号输入错误 let sMobile = $mobile.val(); // 3.2 获得用户输入的手机号 if(sMobile === ""){ message.showError("手机号不能为空"); }else if(!(/^1[3-9]\d{9}$/).test(sMobile)){ message.showError("手机号格式不正确"); }else{ $ // 3.3 发送ajax(新的方式写ajax) .ajax({ // 3.3.1.发送的ajax信息 url: '../verification/mobile/'+ sMobile + '/', type: 'GET', dataType: 'json', }) .done((res)=>{ // 3.3.2. 返回成功执行ajax信息,相当于success if(res.data.count!==0){ message.showError(res.data.mobile+"已经注册,请重新输入!"); }else{ isMobileReady = true; // 3.3.3 符合校验条件设置手机正确 message.showInfo(res.data.mobile+"可以正常使用!"); } }) .fail(()=>{ // 3.3.4. 返回失败执行ajax信息,相当于error message.showError("服务器超时!"); }) } } });
八、Json响应结构设计
1. 目的
1)减少代码冗余,提高复用性,还可以解耦
2)便于分工协作
2. 结构设计
1)结构代码
data = { "errno": 0, "errmsg": "OK", "data": {...}, }
2)参数说明
3)错误信息和错误编码的集合类(为了统一方便管理,一般会由你的项目总监发给你)
(该集合类的文件位置为:first_project----->untils---->res_code.py , 注意res_code这个名字可随意起)
class Code: OK = "0" DBERR = "4001" NODATA = "4002" DATAEXIST = "4003" DATAERR = "4004" METHERR = "4005" SMSERROR = "4006" SMSFAIL = "4007" SESSIONERR = "4101" LOGINERR = "4102" PARAMERR = "4103" USERERR = "4104" ROLEERR = "4105" PWDERR = "4106" SERVERERR = "4500" UNKOWNERR = "4501" error_map = { Code.OK: "成功", Code.DBERR: "数据库查询错误", Code.NODATA: "无数据", Code.DATAEXIST: "数据已存在", Code.DATAERR: "数据错误", Code.METHERR: "方法错误", Code.SMSERROR: "发送短信验证码异常", Code.SMSFAIL: "发送短信验证码失败", Code.SESSIONERR: "用户未登录", Code.LOGINERR: "用户登录失败", Code.PARAMERR: "参数错误", Code.USERERR: "用户不存在或未激活", Code.ROLEERR: "用户身份错误", Code.PWDERR: "密码错误", Code.SERVERERR: "内部错误", Code.UNKOWNERR: "未知错误", }
3. 函数设计(由于我们一个项目中可能会发送很多个json,为了减少代码冗余,我们设计一个函数,为了方便调用我们就将该函数同样的写照res_code.py这个文件中了)
from django.http import JsonResponse # 错误编码集合 class Code: OK = "0" DBERR = "4001" NODATA = "4002" DATAEXIST = "4003" DATAERR = "4004" METHERR = "4005" SMSERROR = "4006" SMSFAIL = "4007" SESSIONERR = "4101" LOGINERR = "4102" PARAMERR = "4103" USERERR = "4104" ROLEERR = "4105" PWDERR = "4106" SERVERERR = "4500" UNKOWNERR = "4501" # 错误编码对应的错误信息集合 error_map = { Code.OK: "成功", Code.DBERR: "数据库查询错误", Code.NODATA: "无数据", Code.DATAEXIST: "数据已存在", Code.DATAERR: "数据错误", Code.METHERR: "方法错误", Code.SMSERROR: "发送短信验证码异常", Code.SMSFAIL: "发送短信验证码失败", Code.SESSIONERR: "用户未登录", Code.LOGINERR: "用户登录失败", Code.PARAMERR: "参数错误", Code.USERERR: "用户不存在或未激活", Code.ROLEERR: "用户身份错误", Code.PWDERR: "密码错误", Code.SERVERERR: "内部错误", Code.UNKOWNERR: "未知错误", } # json结构化函数(之后我们凡事需要返回json数据的时候均调用这个快捷方法) def json_response(error=Code.OK, errmsg='', data=None, kwargs=None): json_dict = { 'error': error, 'errmg': errmsg, 'data' : data } if kwargs and isinstance(kwargs, dict) : # 判断kwargs是否不为空,且它是否是个字典 json_dict.update(kwargs) # 如果是,则将kwargs扩展添加到json_dict这个字典中 return JsonResponse(json_dict) # 返回我们获得的字典
4. 修改我们之前返回的json数据函数(调用我们的快捷方式来返回,文件位置:first_project------>apps----->verivication----->view.py)
文件位置:
# 一、系统模块 import logging # 记录日志我们需要导入日志模块 # 二、django模块 from django.shortcuts import render # django渲染页面模块 from django.http import HttpResponse, JsonResponse # django的响应模块(本视图由于我们返回图片验证码需要使用它) # 三、自己的库 from untils.captcha.captcha import captcha # 导入生成图形验证码的第三方模块 from . import constants # 导入我们创建的用来存放常量的py文件 from user.models import User # 导入我们写好的用户模型类 from untils.res_code import json_response # 导入我们写好的json快捷函数 # 日志器 logger = logging.getLogger('django') # 生成一个名叫django的日志器 # 1.生成图形验证码 def image_code_view(request): """ 功能:生成验证码 url : /image_code/ :param request: :return: """ # 1. 生成验证码(随机生成字符和图片) text, image = captcha.generate_captcha() # 调用该方法会给我们返回两个值,一个是验证码的文字内容,一个是验证码的图片 # 2. 在后端保存验证码(为了之后校验验证码是否正确,所以现在我们需要保存验证码) request.session['image_code'] = text # 将验证码文字部分存放在session中 # 给验证码一个过期时间,为了方便日后修改,我们在校验app中创建一个constants.py的文件,用来存放常量 # 导入方式为 from . import constants request.session.set_expiry(constants.IMAGE_CODE_EXPIRES) # 设置session过期时间 # 3. 记录一个日志 logger.info('Image_code:{}'.format(text)) # 4. 返回验证码图片 # image存储的是图片的二进制数据,content指定了返回的数据内容, # content_type指定了返回数据的类型,告诉浏览器我们返回的是一张图片 return HttpResponse(content=image, content_type='image/jpg') # 2.检查用户名是否注册(由于该方法只使用get访问,所以我们使用函数视图即可) def check_username_view(request, username): """ username 用来获取路径参数username,所以该username需要与url中设置的username名称相同 函数功能:校验用户名 url: /username/(?P\w{5,20})/ :param request: :param username: :return: """ # # 到数据库查询数据并返回 # data = { # "errno": 0, # "errmsg": "OK", # "data": { # "username": username , # 查询用户名 # "count": User.objects.filter(username=username).count() # 用户查询数量 # }, # } # # 返回json数据 # return JsonResponse(data) data = { "username": username , # 查询用户名 "count": User.objects.filter(username=username).count() # 用户查询数量 } # 返回json数据 return json_response(data=data) # 3.检查手机号码是否注册(由于该方法只使用get访问,所以我们使用函数视图即可) def check_mobile_view(request, mobile): """ 函数功能:校验手机号码 url: /mobile/(?P1[3-9]\d{9})/ :param request: :param username: :return: """ # # 到数据库查询数据并返回 # data = { # "errno": 0, # "errmsg": "OK", # "data": { # "mobile": mobile , # 查询手机号码 # "count": User.objects.filter(mobile=mobile).count() # 手机号码查询数量 # }, # } # # 返回json数据 # return JsonResponse(data) # 到数据库查询数据并返回 data = { "mobile": mobile, # 查询手机号码 "count": User.objects.filter(mobile=mobile).count() # 手机号码查询数量 } # 返回json数据 return json_response(data=data)