前言
书接上文, 完成了图片验证码之后, 接下来就是对用户名密码和手机号的校验
相比较而言密码的校验围绕前端代码, 不涉及后台校验, 因此本文密码校验篇幅较少,为的是着重讲解的是用户名和手机号的校验.
V. 用户名校验
判断用户名是否被注册, 提示验证信息到页面
1>接口设计
1.1>接口说明
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /username/(?P<username>\w{5,20})/ |
参数格式 | url路径参数 |
1.2>参数说明
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
username | 字符串 | 是 | 输入的用户名 |
1.3>返回结果
{
"errno": "0",
"errmsg": "OK",
"data": {
"username": "username", # 查询的用户名
"count": 1 # 用户名查询的数量
}
}
2>后端代码
编写用户验证使用已有的verification应用模块, 也就是之前做图片验证码时创建的
如果没有创建该模块,请创建新的app verification专门用来处理验证
cd ~/code/tztz/apps/
python ../manage.py startapp verification
别忘了在settings文件中注册app
2.1>verification/views.py代码
from user.models import User
from utils.json_res import json_response
def check_username_view(request, username):
"""
检测用户名的有效性, 从前端
GET username/(?P<username>\w{5,20})/
"""
# 去数据库查询用户名,通过判断数量可以获知该用户是否存在
data = {
"errno": "0",
"errmsg": "OK",
"data": {
"username": "username", # 查询的用户名
# 用户名查询的数量
"count": User.objects.filter(username=username).count()
}
}
# 将数据传输到路由,使JS代码进行进一步的处理
return JsonResponse(data)
这种写法使代码太过于冗余, 会影响到后续的维护, 为此下文会使用一个解决方法来代替这种写法
2.2>verification/urls.py代码
from django.urls import path, re_path
from . import views
# url的命名空间
app_name = 'verification'
urlpatterns = [
path('image_code/', views.image_code_view, name='image_code'),
# 带有正则表达式的URL路径, 需要使用re_path
re_path('username/(?P<username>\w{5,20})/', views.check_username_view, name='check_username'),
]
配置好后可以尝试在浏览器中打开该url, 看一下是否会返回我们预期的响应
3>前端页面代码
user/register.html代码
{% extends 'base/base.html' %}
{% load static %}
{% block title %}注册{% endblock title %}
{% block link %}
<link rel="stylesheet" href="{% static 'css/user/auth.css' %}">
{% endblock link %}
{% block main_start %}
<main id="container">
<div class="register-contain">
<div class="top-contain">
<h4 class="please-register">请注册</h4>
<a href="javascript:void(0);" class="login">立即登录 ></a>
</div>
<form action="" method="post" class="form-contain">
<div class="form-item">
<input type="text" placeholder="请输入用户名" id="username" name="username" class="form-control" >
</div>
<div class="form-item">
<input type="password" placeholder="请输入密码" name="password" class="form-control">
</div>
<div class="form-item">
<input type="password" placeholder="请输入确认密码" name="password_repeat" class="form-control">
</div>
<div class="form-item">
<input type="tel" placeholder="请输入手机号" name="telephone" class="form-control" autocomplete="off">
</div>
<div class="form-item">
<input type="text" placeholder="请输入图形验证码" name="captcha_graph" class="form-captcha">
<a href="javascript:void(0);" class="captcha-graph-img">
<img src="{% url 'verification:image_code' %}" alt="验证码" title="点击刷新">
</a>
</div>
<div class="form-item">
<input type="text" placeholder="请输入短信验证码" name="sms_captcha" class="form-captcha" autocomplete="off">
<a href="javascript:void(0);" class="sms-captcha" title="发送验证码">获取短信验证码</a>
</div>
<div class="form-item">
<input type="submit" value="立即注册" class="register-btn">
</div>
</form>
</div>
</main>
{% endblock main_start %}
{% block script %}
<script src="{% static 'js/user/auth.js' %}"></script>
{% endblock script %}
4>前端js代码
要提前在base中引用message.js代码, 继续编写regiester.js代码
4.1>用户名校验
// 2. 用户名校验,光标离开,用户名输入框就校验用户名
let $username = $('#user_name');
$username.blur(fnCheckUsername);
function fnCheckUsername() {
isUsernameReady = false;
let sUsername = $username.val(); // 获取前端页面输入框中的值
if (sUsername === ''){
// message为外部引用js代码, 主要是显示提示信息的功能
message.showError('用户名不能为空!');
return // 使用return的目的是为了当满足当前条件的时候就停止执行后续的判断
}
if (!(/^\w{5,20}$/).test(sUsername)){
message.showError('用户名长度必须为5-20位!');
return
}
$.ajax({
// 发送ajax请求,从路由中获取信息,然后进行处理
url:'/username/' + sUsername,
type:'GET',
dataType: 'json',
// 路由中的信息是由后端的视图函数发送到前端的数据:count,username
success: function (data) {
if (data.data.count === 0){
// 判断数量确认该用户是否存在
message.showInfo(sUsername + '可以使用');
isUsernameReady = true;
}else{
message.showError(sUsername + '已存在, 请重新输入!')
}
},
error: function (xhr, msg) {
message.showError('服务器错误请稍后重试!')
}
})
}
5>密码校验
密码校验不涉及后端代码, 主要是对前端的数据进行判断
// 3. 密码校验,判断两次密码是否一致
let $passwordRepeat = $('input[name="password_repeat"]');
$passwordRepeat.blur(fnCheckPassword);
function fnCheckPassword () {
isPasswordReady = false;
let password = $('input[name="password"]').val();
let passwordRepeat = $passwordRepeat.val();
if (password === '' || passwordRepeat === ''){
message.showError('密码不能为空');
return
}
if (!(/^\w{6,18}$/).test(password)){
message.showError('密码长度必须为6-18位!');
return
}
if (password !== passwordRepeat){
message.showError('两次密码输入不一致');
return
}
if (password === passwordRepeat){
isPasswordReady = true
}
}
VI. json响应数据结构设计
用户名与手机号验证的方法非常相似, 这使得大量代码冗余, 可以对其进行优化
目的
- 减少代码冗余,提高复用性,解耦
- 分工协作
1.结构设计
实际项目是多人协同开发,特别是前后端交互,后端返回数据结构要一致。
{"errno": "0", "errmsg": "OK", "data": {...}}
字段 | 类型 | 说明 |
---|---|---|
errno | 字符串 | 错误编码 |
errmsg | 字符串 | 错误信息 |
data | 返回数据 |
在项目根目录中utils文件夹下创建res_code.py文件,用于定义错误编码,代码如下:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
# author: hao 2019/8/10-20:09
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: "未知错误",
}
2.快捷方法
为了方便定义一个快捷方法,在utils目录下创建json_res.py文件代码如下:
from django.http import JsonResponse
from .res_code import Code
def json_response(erron=Code.OK, errmsg='', data=None, kwargs=None):
"""
该方法实现的目的是为了使json数据在传输过程中,能够携带错误代码之类的信息
:param erron: 错误代码
:param errmsg: 错误信息
:param data: 携带的用户信息数据,例如用户名,手机号等
:return: 返回的相当于是我们处理好的json响应
"""
json_dict = {
'erron': erron,
'errmsg': errmsg,
'data': data,
}
if kwargs and isinstance(kwargs, dict):
# 判断kwargs中是否有传输数据信息, 有则更新我们已有的信息
json_dict.update(kwargs)
return JsonResponse(json_dict)
VI. 判断手机号码是否注册功能
1>接口设计
1.1>接口说明:
类目 | 说明 |
---|---|
请求方法 | GET |
url定义 | /mobile/(?P<mobile>1[3-9]\d{9})/ |
参数格式 | url路径参数 |
1.2>参数说明:
参数名 | 类型 | 是否必须 | 描述 |
---|---|---|---|
moblie | 字符串 | 是 | 输入的手机号码 |
1.3>返回结果:
{
"errno": "0",
"errmsg": "OK",
"data": {
"mobile": "13xxxxxxxxx", # 查询的手机号
"count": 1 # 手机号查询的数量
}
}
2>后端代码
2.1>verification/views.py代码
这里正好可以使用我们之前创建的json_response
方法
# ····
def check_mobile_view(request, mobile):
"""
校验手机号是否存在
GET /moblie/(?P<moblie>1[3-9]\d{9})/
"""
data = {
'mobile': mobile,
'count': User.objects.filter(mobile=mobile).count()
}
return json_response(data=data)
2.2>verification/urls.py
from django.urls import path, re_path
from . import views
# url的命名空间
app_name = 'verification'
urlpatterns = [
path('image_code/', views.image_code_view, name='image_code'),
re_path('username/(?P<username>\w{5,20})/', views.check_username_view, name='check_username'),
re_path('mobile/(?P<mobile>1[3-9]\d{9})/', views.check_mobile_view, name='check_mobile'),
]
3. 前端js代码
$(function () {
// 定义状态变量
let isUsernameReady = false,
isPasswordReady = false,
isMobileReady = false,
isSmsCodeReady = false;
// 1.点击刷新图像验证码
let $img = $('.form-contain .form-item .captcha-graph-img img');
$img.click(function () {...});
// 2.鼠标离开用户名输入框校验用户名
let $username = $('#username');
$username.blur(fnCheckUsername);
function fnCheckUsername () {...}
// 3.检测密码是否一致
let $passwordRepeat = $('input[name="password_repeat"]');
$passwordRepeat.blur(fnCheckPassword);
function fnCheckPassword () {...}
// 4.检查手机号码是否可用
let $mobile = $('input[name="mobile"]');
$mobile.blur(fnCheckMobile);
function fnCheckMobile () {
isMobileReady = true;
let sMobile = $mobile.val();
if(sMobile === ''){
message.showError('手机号码不能为空');
return
}
if(!(/^1[3-9]\d{9}$/).test(sMobile)){
message.showError('手机号码格式不正确');
return
}
$.ajax({
url: '/mobile/' + sMobile + '/',
type: 'GET',
dataType: 'json',
success: function (data) {
if(data.data.count !== 0){
message.showError(data.data.mobile + '已经注册,请重新输入!')
}else {
message.showInfo(data.data.mobile + '可以正常使用!');
isMobileReady = true
}
},
error: function (xhr, msg) {
message.showError('服务器超时,请重试!')
}
});
}
});
使用Jquery的这种写法也可以实现同样的功能, 而且相比较而言更简便
$ //使用Jquery验证手机号的方式
.ajax({
// 发送ajax请求,从路由中获取信息,然后进行处理
url: '/mobile/' + sMobile + '/', // 末尾最好加上一个斜杠避免出错
type: 'GET', // 请求类型
dataType: 'json', // 返回的数据类型
})
.done((res)=>{
if (res.data.count === 0) {
message.showInfo(res.data.mobile + '可以使用');
isMobileReady = true;
} else {
message.showError(res.data.mobile + '已注册, 请重新输入!')
}
})
.fail(()=>{
message.showError('服务器错误请稍后重试!')
})