templates/register.html
前端注册界面
{# templates/register.html 前端注册界面 #}
{% load static %}
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>LG商城-注册title>
<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}">
head>
<body>
<div id="app">
<div class="register_con">
<div class="l_con fl">
<a href="index.html" class="reg_logo"><img src="{% static 'images/1.png' %}">a>
<div class="reg_slogan">商品美 · 种类多 · 欢迎光临div>
<div class="reg_banner">div>
div>
<div class="r_con fr">
<div class="reg_title clearfix">
<h1>用户注册h1>
<a href="login.html">登录a>
div>
<div class="reg_form clearfix">
<form method="post" class="register_form" v-cloak @submit="on_submit">
{% csrf_token %}
<ul>
<li>
<label>用户名:label>
<input type="text" name="username" v-model="username" @blur="check_username" id="user_name">
<span class="error_tip" v-show="error_name">[[ error_name_message ]]span>
li>
<li>
<label>密码:label>
<input type="password" name="password" v-model="password" @blur="check_password" id="pwd">
<span class="error_tip" v-show="error_password">请输入8-20位的密码span>
li>
<li>
<label>确认密码:label>
<input type="password" name="password2" v-model="password2" @blur="check_password2" id="cpwd">
<span class="error_tip" v-show="error_password2">两次输入的密码不一致span>
li>
<li>
<label>手机号:label>
<input type="text" name="mobile" v-model="mobile" @blur="check_mobile" id="phone">
<span class="error_tip" v-show="error_mobile">[[ error_mobile_message ]]span>
li>
<li>
<label>图形验证码:label>
{# v-model="image_code" @blur="check_image_code"绑定验证码的格式 #}
<input type="text" name="image_code" id="pic_code" class="msg_input" v-model="image_code" @blur="check_image_code" >
{# 图形验证码路径进行绑定 :src="image_code_url" 点击变换@click="generate_image_code" #}
<img :src="image_code_url" @click="generate_image_code" alt="图形验证码" class="pic_code">
{# 错误信息显示error_image_code_message 绑定js文件中的错误信息名称v-show="error_image_code" #}
<span class="error_tip" v-show="error_image_code">[[ error_image_code_message ]]span>
li>
<li>
<label>短信验证码:label>
{# v-model="sms_code"绑定, @blur="check_sms_code"绑定短信验证码的格式 #}
<input type="text" name="sms_code" id="msg_code" class="msg_input" v-model="sms_code" @blur="check_sms_code">
{# 点击触发获取短信验证码方法 #}
<a @click="send_sms_code" class="get_msg_code">[[ sms_code_tip ]]a>
{# 绑定v-show,用于控制显示错误信息;error_sms_code_message错误信息 #}
<span class="error_tip" v-show="error_sms_code">[[ error_sms_code_message ]]span>
li>
<li class="agreement">
<input type="checkbox" name="allow" v-model="allow" @change="check_allow" id="allow">
<label>同意”LG商城用户使用协议“label>
<span class="error_tip" v-show="error_allow">请勾选用户协议span>
{# 这部分传注册错误信息到前端界面是用的Django自带的,前端验证form表单信息我们采用的是 @submit="on_submit" 中的ajax进行验证,这是两种方式,选择一种就可以 #}
{# 将apps/users/views.py文件中的注册错误信息context进行循环 #}
<span class="error_tip">
{% if form_errors %}
{% for key,error in form_errors.items %}
{{ error }}
{% endfor %}
{% endif %}
{# 保存用户注册数据失败的信息apps/users/views.py中传递的register_error_message #}
{% if register_error_message %}
{{ register_error_message }}
{% endif %}
span>
li>
<li class="reg_sub">
<input type="submit" value="注 册">
li>
ul>
form>
div>
div>
div>
<div class="footer no-mp">
<div class="foot_link">
<a href="#">关于我们a>
<span>|span>
<a href="#">联系我们a>
<span>|span>
<a href="#">招聘人才a>
<span>|span>
<a href="#">友情链接a>
div>
<p>CopyRight © 2016 北京LG商业股份有限公司 All Rights Reservedp>
<p>电话:010-****888 京ICP备*******8号p>
div>
div>
<script src="{% static 'js/vue-2.5.16.js' %}">script>
<script src="{% static 'js/axios-0.18.0.min.js' %}">script>
{# 生成uuid的文件 需要先加载common.js文件,再加载注册界面js #}
<script src="{% static 'js/common.js' %}">script>
<script src="{% static 'js/register.js' %}">script>
body>
html>
static/js/register.js
文件,验证注册界面的逻辑
// 实例化Vue的对象 static/js/register.js文件,验证注册界面的逻辑
let vm = new Vue({
el:"#app",
// 修改Vue读取变量的语法 {{}} [[]],Vue中可能不识别Django的{{}}语法形式
delimiters: ['[[', ']]'],
data: {
// v-model绑定名称
username:"", //绑定前端界面的username标签
password:"",
password2:"",
mobile:"",
allow:"",
image_code_url:"", // 验证码绑定的路由
uuid:"", // 采用common.js文件方法生成的uuid
image_code:"", // 检测验证码的格式
sms_code:"", // 短信验证码名称
sms_code_tip:"获取短信验证码",
// v-show绑定的名称,默认false不显示
error_name: false,
error_password: false,
error_password2: false,
error_mobile: false,
error_allow: false,
error_image_code: false,
error_sms_code:false,
// 绑定的错误信息
error_name_message:"",
error_mobile_message:"",
error_image_code_message:"", // 图形验证码错误信息
error_sms_code_message:"", // 短信验证码错误信息
},
// Vue的生命周期,页面加载完成后被调用该方法,验证码生成
mounted(){
this.generate_image_code();
},
methods: {
// 验证码点击更换方法,且需要在页面加载完成时候,该方法已经执行
generate_image_code(){
// 生成uuid,调用common.js方法
this.uuid = generateUUID()
// 验证码路由拼接
this.image_code_url = "/image_codes/"+ this.uuid + "/"
},
// 检验短信验证码,和图形验证码的方法逻辑相同
check_sms_code(){
if(this.sms_code.length != 6){
this.error_sms_code_message = '短信验证码长度不正确'
this.error_sms_code = true // 前端界面v-show=true,展示错误信息
}else{
this.error_sms_code = false // 不显示信息
}
},
// 定义发送短信验证码方法
send_sms_code(){
// 校验数据是否填写,手机号,短信验证码
this.check_mobile();
this.check_image_code();
if (this.error_mobile == true || this.error_image_code == true) {
return;
}
// 'sms_codes/(?P1[3-9]\d{9})/' 需要拼接这样的路由:sms_codes/132xxx/?image_code='xxxx'&uuid='xxxxx'
let url = 'sms_codes/' + this.mobile + '/?image_code=' + this.image_code + '&uuid=' + this.uuid
// 路由拼接完成,发送请求
axios.get(url, {
responseType: 'json'
})
.then(response => { // 请求成功
// 返回数据:JsonResponse({"code": RETCODE.OK, 'errmsg': "发送短信验证码成功"})
if (response.data.code == '0'){ // 后端返回的状态码为'0',即代表获取短信验证码成功
// 60s倒计时显示验证码有效期 需要用到定时器
let num = 60
let t = setInterval(() => { // 定时器,匿名函数
if(num == 1){
// 定时器停止
clearInterval(t)
this.sms_code_tip = '获取短信验证码'
this.generate_image_code(); // 重新生成图形验证码
}else{
num -= 1 // 继续读秒
this.sms_code_tip = num + '秒'
}
}, 1000) // 1000毫秒
}else{ // 后端返回的状态码不为'0',即代表获取短信验证码失败
if (response.data.code == '4001'){
// 图形验证码输入有误,apps/verifications/views.py中的JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码输入有误!"})
this.error_image_code_message = response.data.errmsg
this.error_image_code = true // 显示错误信息
}
}
})
.catch(error => { // 请求错误
console.log(error.response)
})
},
// 定义方法 定义标签失去焦点的方法
// check_username:function () {
// }
// @blur="check_username"方法
check_username(){
// 正则表达式 5-20位字符数字组成
let re = /^[a-zA-Z0-9_-]{5,20}$/;
if(re.test(this.username)){
// 匹配成功 错误信息不展示
this.error_name = false
}else{
this.error_name = true // v-show为true,显示信息
this.error_name_message = "请输入5-20个字符的用户"
}
// 使用Vue的ajax进行表单验证
if(this.error_name == false){ // 用户名正确情况
// http://127.0.0.1:8000/users/usernames/用户名/count 路由格式
let url = '/users/usernames/'+ this.username + '/count' // url拼接
// Vue发送ajax请求
axios.get(url, {
responseType:'json'
})
// 请求成功
.then(response=> { // .then(function(response))
// 从apps/users/views.py文件返回的JsonResponse({"code": 0, "errmsg": "OK", "count": count})
if(response.data.count == 1 ){ // 用户名已经存在 count数据就是在views.py文件中传出的
this.error_name_message = '用户名已经存在'
this.error_name = true
}else{
this.error_name = false //可以继续注册其他的字段
}
})
// 请求失败
.catch(error =>{
console.log(error.response) // 前端界面打印error.response
})
}
},
// @blur="check_password"
check_password(){
let re = /^[a-zA-Z0-9]{8,20}$/;
if(re.test(this.password)){
this.error_password = false
}else{
this.error_password = true
}
},
// @blur="check_password2"
check_password2(){
// 保持一致就行
if(this.password2 != this.password){
this.error_password2 = true
}else{
this.error_password2 = false
}
},
// @blur="check_mobile"
check_mobile(){
let re = /^1[3456789]\d{9}$/;
if(re.test(this.mobile)){
this.error_mobile = false
}else{
this.error_mobile = true
this.error_mobile_message = "请输入正确格式手机号!"
}
},
// @change="check_allow"
check_allow(){ // checkbox的选中状态
if(!this.allow){ // allow是个空的bool类型值
this.error_allow = true
}else{
this.error_allow = false
}
},
// on_submit 表单提交
on_submit(){
// 如果表单验证中有true就说明有错误信息,不能提交
if(this.error_name == true || this.error_password == true || this.error_password2 ==true ||
this.error_mobile == true || this.error_allow == true){
// 禁止表单提交
window.event.returnValue=false
}
},
// 检测验证码格式方法
check_image_code(){
if(this.image_code.length != 4){
this.error_image_code_message = '图形验证码长度不正确'
this.error_image_code = true // 前端界面v-show=true,展示错误信息
}else{
this.error_image_code = false // 不显示信息
}
},
},
});
apps/verifications/views.py
验证码视图文件
"""
apps/verifications/views.py 验证码视图文件
"""
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
from .libs.captcha.captcha import captcha # 调用实例化对象captcha
from django_redis import get_redis_connection # 连接redis
import random
from verifications.libs.ronglianyun.ccp_sms import CCP # 导入发送短信验证码类
from verifications import constants # 导入定义软编码文件
from utils.response_code import RETCODE # 导入定义状态码文件
# 图形验证码
class ImageCodeView(View):
"""图像验证码"""
def get(self, request, uuid):
"""
:param uuid:用于标识该验证码属于哪个用户,用户注册时期没有id标识,用uuid不会产生重复的id
:return:
"""
# 生成验证码,从生成验证码文件中调用实例化对象的方法
text, image = captcha.generate_captcha()
# 先连接redis,再保存到redis
redis_conn = get_redis_connection('verify_code') # verify_code是dev.py配置文件中的redis配置参数
# redis_conn.set('img_%s' % uuid, text) # set(key,value), 这种保存redis数据,无法设置保存时效
redis_conn.setex('img_%s' % uuid, constants.IMAGE_CODE_REDIS_EXPIRES, text) # set(key,expries,value),expries是时效,以秒s为单位
# 响应图形验证码
# return HttpResponse('image/jpg')
return HttpResponse(image, content_type='image/jpg')
# 手机验证码
class SMSCodeView(View):
"""短信验证码"""
def get(self, request, mobile):
"""
:param mobile: 手机号
:return: json数据类型
"""
# 接收参数
image_code_client = request.GET.get('image_code') # image_code_client是字符串数据类型
uuid = request.GET.get('uuid')
# 校验参数 image_code_client, uuid必须都存在
if not all([image_code_client, uuid]):
return HttpResponseForbidden('缺少必传参数')
# 创建连接到redis的对象
# 提取图形验证码
redis_conn = get_redis_connection('verify_code')
image_code_server = redis_conn.get('img_%s' % uuid) # 此时的image_code_server是字节数据类型
# print(type(image_code_server))
# print(type(image_code_client))
# 判断图形验证码的有无
if image_code_server is None:
return JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码已经失效了"})
# 删除图形验证码,避免恶意测试图形验证码
redis_conn.delete('img_%s' % uuid)
# 对比图形验证码 .lower()都转成小写
if image_code_client.lower() != image_code_server.decode().lower(): # decode()方法将字节数据转换成str
return JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码输入有误!"}) # RETCODE.IMAGECODEERR定义的状态码
# 随机生成短信验证码:生成6位数验证码
sms_code = "%06d" % random.randint(0, 999999) # 06d代表前几位可以用0补充
# print(sms_code)
# 生成验证码的另一种写法
# for i in range(6):
# sms_code += str(random.randint(0, 9))
# 保存短信验证码
redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) # 保存300s
# 发送短信验证码send_message(mobile, datas, tid)中tid是模板,默认为1,datas是数据和保存时效;constants.SMS_CODE_REDIS_EXPIRES//60 双//为了得到整数
CCP().send_message(mobile, (sms_code, constants.SMS_CODE_REDIS_EXPIRES//60), 1)
# 响应结果
return JsonResponse({"code": RETCODE.OK, 'errmsg': "发送短信验证码成功"}) # RETCODE.OK定义状态码
存在的问题:
避免频繁发送短信验证码逻辑分析
避免频繁发送短信验证码逻辑实现
apps/verifications/views.py
验证码视图文件
"""
apps/verifications/views.py 验证码视图文件
"""
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
from .libs.captcha.captcha import captcha # 调用实例化对象captcha
from django_redis import get_redis_connection # 连接redis
import random
from verifications.libs.ronglianyun.ccp_sms import CCP # 导入发送短信验证码类
from verifications import constants # 导入定义软编码文件
from utils.response_code import RETCODE # 导入定义状态码文件
# 图形验证码
class ImageCodeView(View):
"""图像验证码"""
def get(self, request, uuid):
"""
:param uuid:用于标识该验证码属于哪个用户,用户注册时期没有id标识,用uuid不会产生重复的id
:return:
"""
# 生成验证码,从生成验证码文件中调用实例化对象的方法
text, image = captcha.generate_captcha()
# 先连接redis,再保存到redis
redis_conn = get_redis_connection('verify_code') # verify_code是dev.py配置文件中的redis配置参数
# redis_conn.set('img_%s' % uuid, text) # set(key,value), 这种保存redis数据,无法设置保存时效
redis_conn.setex('img_%s' % uuid, constants.IMAGE_CODE_REDIS_EXPIRES, text) # set(key,expries,value),expries是时效,以秒s为单位
# 响应图形验证码
# return HttpResponse('image/jpg')
return HttpResponse(image, content_type='image/jpg')
# 手机验证码
class SMSCodeView(View):
"""短信验证码"""
def get(self, request, mobile):
"""
:param mobile: 手机号
:return: json数据类型
"""
# 接收参数
image_code_client = request.GET.get('image_code') # image_code_client是字符串数据类型
uuid = request.GET.get('uuid')
# 校验参数 image_code_client, uuid必须都存在
if not all([image_code_client, uuid]):
return HttpResponseForbidden('缺少必传参数')
# 创建连接到redis的对象
# 提取图形验证码
redis_conn = get_redis_connection('verify_code')
# 判断短信验证码是否已经发送
send_flag = redis_conn.get("send_flag_%s" % mobile)
if send_flag:
return JsonResponse({"code":111, 'errmsg': "短信验证码发送频繁"})
image_code_server = redis_conn.get('img_%s' % uuid) # 此时的image_code_server是字节数据类型
# print(type(image_code_server))
# print(type(image_code_client))
# 判断图形验证码的有无
if image_code_server is None:
return JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码已经失效了"})
# 删除图形验证码,避免恶意测试图形验证码
redis_conn.delete('img_%s' % uuid)
# 对比图形验证码 .lower()都转成小写
if image_code_client.lower() != image_code_server.decode().lower(): # decode()方法将字节数据转换成str
return JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码输入有误!"}) # RETCODE.IMAGECODEERR定义的状态码
# 随机生成短信验证码:生成6位数验证码
sms_code = "%06d" % random.randint(0, 999999) # 06d代表前几位可以用0补充
# print(sms_code)
# 生成验证码的另一种写法
# for i in range(6):
# sms_code += str(random.randint(0, 9))
# 保存短信验证码
redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) # 保存300s
# 保存短信验证码是否已经发送,constants.SEND_SMS_CODE_FLAG保存时效60s 1是value,随意取,"send_flag_%s" % mobile是key
redis_conn.setex("send_flag_%s" % mobile, constants.SEND_SMS_CODE_FLAG, 1)
# 发送短信验证码send_message(mobile, datas, tid)中tid是模板,默认为1,datas是数据和保存时效;constants.SMS_CODE_REDIS_EXPIRES//60 双//为了得到整数
CCP().send_message(mobile, (sms_code, constants.SMS_CODE_REDIS_EXPIRES//60), 1)
# 响应结果
return JsonResponse({"code": RETCODE.OK, 'errmsg': "发送短信验证码成功"}) # RETCODE.OK定义状态码
static/js/register.js
文件,验证注册界面的逻辑
// 实例化Vue的对象 static/js/register.js文件,验证注册界面的逻辑
let vm = new Vue({
el:"#app",
// 修改Vue读取变量的语法 {{}} [[]],Vue中可能不识别Django的{{}}语法形式
delimiters: ['[[', ']]'],
data: {
// v-model绑定名称
username:"", //绑定前端界面的username标签
password:"",
password2:"",
mobile:"",
allow:"",
image_code_url:"", // 验证码绑定的路由
uuid:"", // 采用common.js文件方法生成的uuid
image_code:"", // 检测验证码的格式
sms_code:"", // 短信验证码名称
sms_code_tip:"获取短信验证码",
send_flag:false, // 是否发送短信验证码标志
// v-show绑定的名称,默认false不显示
error_name: false,
error_password: false,
error_password2: false,
error_mobile: false,
error_allow: false,
error_image_code: false,
error_sms_code:false,
// 绑定的错误信息
error_name_message:"",
error_mobile_message:"",
error_image_code_message:"", // 图形验证码错误信息
error_sms_code_message:"", // 短信验证码错误信息
},
// Vue的生命周期,页面加载完成后被调用该方法,验证码生成
mounted(){
this.generate_image_code();
},
methods: {
// 验证码点击更换方法,且需要在页面加载完成时候,该方法已经执行
generate_image_code(){
// 生成uuid,调用common.js方法
this.uuid = generateUUID()
// 验证码路由拼接
this.image_code_url = "/image_codes/"+ this.uuid + "/"
},
// 检验短信验证码,和图形验证码的方法逻辑相同
check_sms_code(){
if(this.sms_code.length != 6){
this.error_sms_code_message = '短信验证码长度不正确'
this.error_sms_code = true // 前端界面v-show=true,展示错误信息
}else{
this.error_sms_code = false // 不显示信息
}
},
// 定义发送短信验证码方法
send_sms_code(){
// send_flag:false 是否已经发送短信验证码标志
if (this.send_flag == true){
return; // 当send_flag = true会跳出方法,不会调用
}
this.send_flag = true
// 校验数据是否填写,手机号,短信验证码
this.check_mobile();
this.check_image_code();
if (this.error_mobile == true || this.error_image_code == true) {
return;
}
// 'sms_codes/(?P1[3-9]\d{9})/' 需要拼接这样的路由:sms_codes/132xxx/?image_code='xxxx'&uuid='xxxxx'
let url = 'sms_codes/' + this.mobile + '/?image_code=' + this.image_code + '&uuid=' + this.uuid
// 路由拼接完成,发送请求
axios.get(url, {
responseType: 'json'
})
.then(response => { // 请求成功
// 返回数据:JsonResponse({"code": RETCODE.OK, 'errmsg': "发送短信验证码成功"})
if (response.data.code == '0'){ // 后端返回的状态码为'0',即代表获取短信验证码成功
// 60s倒计时显示验证码有效期 需要用到定时器
let num = 60
let t = setInterval(() => { // 定时器,匿名函数
if(num == 1){
// 定时器停止
clearInterval(t)
this.sms_code_tip = '获取短信验证码'
this.generate_image_code(); // 重新生成图形验证码
this.send_flag = false // 需要重新发送
}else{
num -= 1 // 继续读秒
this.sms_code_tip = num + '秒'
}
}, 1000) // 1000毫秒
}else{ // 后端返回的状态码不为'0',即代表获取短信验证码失败
if (response.data.code == '4001'){
// 图形验证码输入有误,apps/verifications/views.py中的JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码输入有误!"})
this.error_image_code_message = response.data.errmsg
this.error_image_code = true // 显示错误信息
}
this.send_flag = false // 需要重新发送
}
})
.catch(error => { // 请求错误
console.log(error.response)
})
},
// 定义方法 定义标签失去焦点的方法
// check_username:function () {
// }
// @blur="check_username"方法
check_username(){
// 正则表达式 5-20位字符数字组成
let re = /^[a-zA-Z0-9_-]{5,20}$/;
if(re.test(this.username)){
// 匹配成功 错误信息不展示
this.error_name = false
}else{
this.error_name = true // v-show为true,显示信息
this.error_name_message = "请输入5-20个字符的用户"
}
// 使用Vue的ajax进行表单验证
if(this.error_name == false){ // 用户名正确情况
// http://127.0.0.1:8000/users/usernames/用户名/count 路由格式
let url = '/users/usernames/'+ this.username + '/count' // url拼接
// Vue发送ajax请求
axios.get(url, {
responseType:'json'
})
// 请求成功
.then(response=> { // .then(function(response))
// 从apps/users/views.py文件返回的JsonResponse({"code": 0, "errmsg": "OK", "count": count})
if(response.data.count == 1 ){ // 用户名已经存在 count数据就是在views.py文件中传出的
this.error_name_message = '用户名已经存在'
this.error_name = true
}else{
this.error_name = false //可以继续注册其他的字段
}
})
// 请求失败
.catch(error =>{
console.log(error.response) // 前端界面打印error.response
})
}
},
// @blur="check_password"
check_password(){
let re = /^[a-zA-Z0-9]{8,20}$/;
if(re.test(this.password)){
this.error_password = false
}else{
this.error_password = true
}
},
// @blur="check_password2"
check_password2(){
// 保持一致就行
if(this.password2 != this.password){
this.error_password2 = true
}else{
this.error_password2 = false
}
},
// @blur="check_mobile"
check_mobile(){
let re = /^1[3456789]\d{9}$/;
if(re.test(this.mobile)){
this.error_mobile = false
}else{
this.error_mobile = true
this.error_mobile_message = "请输入正确格式手机号!"
}
},
// @change="check_allow"
check_allow(){ // checkbox的选中状态
if(!this.allow){ // allow是个空的bool类型值
this.error_allow = true
}else{
this.error_allow = false
}
},
// on_submit 表单提交
on_submit(){
// 如果表单验证中有true就说明有错误信息,不能提交
if(this.error_name == true || this.error_password == true || this.error_password2 ==true ||
this.error_mobile == true || this.error_allow == true){
// 禁止表单提交
window.event.returnValue=false
}
},
// 检测验证码格式方法
check_image_code(){
if(this.image_code.length != 4){
this.error_image_code_message = '图形验证码长度不正确'
this.error_image_code = true // 前端界面v-show=true,展示错误信息
}else{
this.error_image_code = false // 不显示信息
}
},
},
});
定义软编码文件:apps/verifications/constants.py
# -*- encoding: utf-8 -*-
"""
@File : constants.py
@Time : 2020/8/4 16:44
@Author : chen
定义软编码文件:apps/verifications/constants.py
"""
# 图形验证码有效期 单位:s秒
IMAGE_CODE_REDIS_EXPIRES = 300
# 短信验证码有效期 单位:s秒
SMS_CODE_REDIS_EXPIRES = 300
# 短信模板
SEND_SMS_TEMPLATE_ID = 1
# 短信验证码是否重复发送
SEND_SMS_CODE_FLAG = 60
补充注册时短信验证后端逻辑
后端表单验证文件:apps/users/forms.py
# -*- encoding: utf-8 -*-
"""
@File : forms.py
@Time : 2020/7/28 16:16
@Author : chen
后端表单验证文件:apps/users/forms.py
"""
from django import forms
from .models import User
class RegisterForm(forms.Form): # 继承自forms.Form是只需要验证个别字段的信息,而继承自model.Form是需要验证所有的字段
username = forms.CharField(max_length=20, min_length=5, error_messages={"min_length": "用户名长度不对",
"max_length": "用户名长度不对"})
password = forms.CharField(max_length=20, min_length=8, error_messages={"min_length": "密码长度不对",
"max_length": "密码长度不对",
"required": "密码必须填写"})
password2 = forms.CharField(max_length=20, min_length=8, error_messages={"min_length": "密码长度不对",
"max_length": "密码长度不对",
"required": "密码必须填写"})
allow = forms.BooleanField()
mobile = forms.CharField(max_length=11, min_length=11, required=True, error_messages={"min_length": "手机号长度不对",
"max_length": "手机号长度不对",
"required": "手机号必须填写"})
sms_code = forms.CharField(max_length=6, min_length=6, required=True)
# 检测用户名是否已经在数据库中
def clean_username(self):
username = self.cleaned_data.get('username')
username_exists = User.objects.filter(username=username).exists() # 检查数据库中username是否存在
if username_exists:
raise forms.ValidationError('用户名已经存在')
return username
# 检测手机号是否已经在数据库中
def clean_mobile(self):
mobile = self.cleaned_data.get('mobile')
mobile_exists = User.objects.filter(mobile=mobile).exists() # 检查数据库中手机号是否存在
if mobile_exists:
raise forms.ValidationError('手机号已经存在')
return mobile
# 验证两次密码是否一致
def clean(self):
cleaned_data = super().clean() # 调用父类的clean方法
password = cleaned_data.get('password')
password2 = cleaned_data.get('password2')
if password != password2:
raise forms.ValidationError("两次密码不一致")
return cleaned_data # 可以不返回值,建议使用返回值
apps/users/views.py
文件,用户后端验证视图文件
"""
视图文件
apps/users/views.py文件,用户后端验证视图文件
"""
from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse, JsonResponse
from django.views import View
from .forms import RegisterForm
from .models import User
from django.contrib.auth import login
from django_redis import get_redis_connection
class RegisterView(View):
"""用户注册"""
def get(self, request):
"""提供用户的注册界面"""
return render(request, "register.html")
def post(self, request):
"""提供用户的注册逻辑"""
# 前端用户提交数据
form = RegisterForm(request.POST)
if form.is_valid():
# 接收参数
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
mobile = form.cleaned_data.get('mobile')
sms_code_client = request.POST.get('sms_code') # 验证短信验证码 sms_code是register.html 文件中命名的
# 判断用户输入的短信验证码是否正确
redis_conn = get_redis_connection('verify_code') # 链接redis中配置的数据库
sms_code_server = redis_conn.get('sms_%s' % mobile) # 根据存储时候的格式写
if sms_code_server is None:
return render(request, 'register.html', {'sms_code_errmsg': '短信验证码已经失效'}) # 错误信息渲染到前端界面
if sms_code_server.decode() != sms_code_client: # sms_code_server数据类型需要转换
return render(request, 'register.html', {'sms_code_errmsg': '短信验证码填写错误'})
try:
# user = User(username=username, password=password, mobile=mobile)
# 下面的添加数据的方法是封装了加密等功能的函数,更安全
users = User.objects.create_user(username=username, password=password, mobile=mobile)
except: # 如果保存数据失败
return render(request, 'register.html', {'register_error_message': '注册失败'})
# 保持用户登录的状态
login(request, users)
# 返回响应
# return HttpResponse('success')
return redirect(reverse('contents:index')) # 注册成功,跳转到首页
else:
print(form.errors.get_json_data())
# return HttpResponse("fail")
# 返回注册错误信息到前端界面
context = {
'form_error': form.errors,
}
return render(request, 'register.html', context=context)
class UsernameExists(View):
""" 判断用户名是否已经存在"""
def get(self, request, username): # username用户名
count = User.objects.filter(username=username).count() # 查询数据库中信息
return JsonResponse({"code": 0, "errmsg": "OK", "count": count}) # 返回给前端界面
templates/register.html
前端注册界面
{# templates/register.html 前端注册界面 #}
{% load static %}
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>LG商城-注册title>
<link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}">
head>
<body>
<div id="app">
<div class="register_con">
<div class="l_con fl">
<a href="index.html" class="reg_logo"><img src="{% static 'images/1.png' %}">a>
<div class="reg_slogan">商品美 · 种类多 · 欢迎光临div>
<div class="reg_banner">div>
div>
<div class="r_con fr">
<div class="reg_title clearfix">
<h1>用户注册h1>
<a href="login.html">登录a>
div>
<div class="reg_form clearfix">
<form method="post" class="register_form" v-cloak @submit="on_submit">
{% csrf_token %}
<ul>
<li>
<label>用户名:label>
<input type="text" name="username" v-model="username" @blur="check_username" id="user_name">
<span class="error_tip" v-show="error_name">[[ error_name_message ]]span>
li>
<li>
<label>密码:label>
<input type="password" name="password" v-model="password" @blur="check_password" id="pwd">
<span class="error_tip" v-show="error_password">请输入8-20位的密码span>
li>
<li>
<label>确认密码:label>
<input type="password" name="password2" v-model="password2" @blur="check_password2" id="cpwd">
<span class="error_tip" v-show="error_password2">两次输入的密码不一致span>
li>
<li>
<label>手机号:label>
<input type="text" name="mobile" v-model="mobile" @blur="check_mobile" id="phone">
<span class="error_tip" v-show="error_mobile">[[ error_mobile_message ]]span>
li>
<li>
<label>图形验证码:label>
{# v-model="image_code" @blur="check_image_code"绑定验证码的格式 #}
<input type="text" name="image_code" id="pic_code" class="msg_input" v-model="image_code" @blur="check_image_code" >
{# 图形验证码路径进行绑定 :src="image_code_url" 点击变换@click="generate_image_code" #}
<img :src="image_code_url" @click="generate_image_code" alt="图形验证码" class="pic_code">
{# 错误信息显示error_image_code_message 绑定js文件中的错误信息名称v-show="error_image_code" #}
<span class="error_tip" v-show="error_image_code">[[ error_image_code_message ]]span>
li>
<li>
<label>短信验证码:label>
{# v-model="sms_code"绑定, @blur="check_sms_code"绑定短信验证码的格式 #}
<input type="text" name="sms_code" id="msg_code" class="msg_input" v-model="sms_code" @blur="check_sms_code">
{# 点击触发获取短信验证码方法 #}
<a @click="send_sms_code" class="get_msg_code">[[ sms_code_tip ]]a>
{# 绑定v-show,用于控制显示错误信息;error_sms_code_message错误信息 #}
{# <span class="error_tip" v-show="error_sms_code">[[ error_sms_code_message ]]span>#}
{# 短信验证码错误信息显示 #}
{% if sms_code_errmsg %}
<span class="error_tip" >{{ sms_code_errmsg }}span>
{% endif %}
li>
<li class="agreement">
<input type="checkbox" name="allow" v-model="allow" @change="check_allow" id="allow">
<label>同意”LG商城用户使用协议“label>
<span class="error_tip" v-show="error_allow">请勾选用户协议span>
{# 这部分传注册错误信息到前端界面是用的Django自带的,前端验证form表单信息我们采用的是 @submit="on_submit" 中的ajax进行验证,这是两种方式,选择一种就可以 #}
{# 将apps/users/views.py文件中的注册错误信息context进行循环 #}
<span class="error_tip">
{% if form_errors %}
{% for key,error in form_errors.items %}
{{ error }}
{% endfor %}
{% endif %}
{# 保存用户注册数据失败的信息apps/users/views.py中传递的register_error_message #}
{% if register_error_message %}
{{ register_error_message }}
{% endif %}
span>
li>
<li class="reg_sub">
<input type="submit" value="注 册">
li>
ul>
form>
div>
div>
div>
<div class="footer no-mp">
<div class="foot_link">
<a href="#">关于我们a>
<span>|span>
<a href="#">联系我们a>
<span>|span>
<a href="#">招聘人才a>
<span>|span>
<a href="#">友情链接a>
div>
<p>CopyRight © 2016 北京商业股份有限公司 All Rights Reservedp>
<p>电话:010-****888 京ICP备*******8号p>
div>
div>
<script src="{% static 'js/vue-2.5.16.js' %}">script>
<script src="{% static 'js/axios-0.18.0.min.js' %}">script>
{# 生成uuid的文件 需要先加载common.js文件,再加载注册界面js #}
<script src="{% static 'js/common.js' %}">script>
<script src="{% static 'js/register.js' %}">script>
body>
html>
至此,所有的注册逻辑和界面都完成了,开启数据库MySQL 5.7
和Redis 3.5.3
之后,就可以进行注册了,注册成功后能够自动跳转到首页界面就是成功。
注意:还可以将验证码信息保存在log日志中,apps/verifications/views.py
验证码视图文件
"""
apps/verifications/views.py 验证码视图文件
"""
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
from .libs.captcha.captcha import captcha # 调用实例化对象captcha
from django_redis import get_redis_connection # 连接redis
import random
from verifications.libs.ronglianyun.ccp_sms import CCP # 导入发送短信验证码类
from verifications import constants # 导入定义软编码文件
from utils.response_code import RETCODE # 导入定义状态码文件
import logging
logger = logging.getLogger('django') # 创建日志,配置文件中名称为django
# 图形验证码
class ImageCodeView(View):
"""图像验证码"""
def get(self, request, uuid):
"""
:param uuid:用于标识该验证码属于哪个用户,用户注册时期没有id标识,用uuid不会产生重复的id
:return:
"""
# 生成验证码,从生成验证码文件中调用实例化对象的方法
text, image = captcha.generate_captcha()
# 先连接redis,再保存到redis
redis_conn = get_redis_connection('verify_code') # verify_code是dev.py配置文件中的redis配置参数
# redis_conn.set('img_%s' % uuid, text) # set(key,value), 这种保存redis数据,无法设置保存时效
redis_conn.setex('img_%s' % uuid, constants.IMAGE_CODE_REDIS_EXPIRES, text) # set(key,expries,value),expries是时效,以秒s为单位
# 响应图形验证码
# return HttpResponse('image/jpg')
return HttpResponse(image, content_type='image/jpg')
# 手机验证码
class SMSCodeView(View):
"""短信验证码"""
def get(self, request, mobile):
"""
:param mobile: 手机号
:return: json数据类型
"""
# 接收参数
image_code_client = request.GET.get('image_code') # image_code_client是字符串数据类型
uuid = request.GET.get('uuid')
# 校验参数 image_code_client, uuid必须都存在
if not all([image_code_client, uuid]):
return HttpResponseForbidden('缺少必传参数')
# 创建连接到redis的对象
# 提取图形验证码
redis_conn = get_redis_connection('verify_code')
# 判断短信验证码是否已经发送
send_flag = redis_conn.get("send_flag_%s" % mobile)
if send_flag:
return JsonResponse({"code":111, 'errmsg': "短信验证码发送频繁"})
image_code_server = redis_conn.get('img_%s' % uuid) # 此时的image_code_server是字节数据类型
# print(type(image_code_server))
# print(type(image_code_client))
# 判断图形验证码的有无
if image_code_server is None:
return JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码已经失效了"})
# 删除图形验证码,避免恶意测试图形验证码
redis_conn.delete('img_%s' % uuid)
# 对比图形验证码 .lower()都转成小写
if image_code_client.lower() != image_code_server.decode().lower(): # decode()方法将字节数据转换成str
return JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码输入有误!"}) # RETCODE.IMAGECODEERR定义的状态码
# 随机生成短信验证码:生成6位数验证码
sms_code = "%06d" % random.randint(0, 999999) # 06d代表前几位可以用0补充
# print(sms_code)
# 生成验证码的另一种写法
# for i in range(6):
# sms_code += str(random.randint(0, 9))
# 验证码保存到log日志中
logger.info(sms_code)
# 保存短信验证码
redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) # 保存300s
# 保存短信验证码是否已经发送,constants.SEND_SMS_CODE_FLAG保存时效60s 1是value,随意取,"send_flag_%s" % mobile是key
redis_conn.setex("send_flag_%s" % mobile, constants.SEND_SMS_CODE_FLAG, 1)
# 发送短信验证码send_message(mobile, datas, tid)中tid是模板,默认为1,datas是数据和保存时效;constants.SMS_CODE_REDIS_EXPIRES//60 双//为了得到整数
CCP().send_message(mobile, (sms_code, constants.SMS_CODE_REDIS_EXPIRES//60), 1)
# 响应结果
return JsonResponse({"code": RETCODE.OK, 'errmsg': "发送短信验证码成功"}) # RETCODE.OK定义状态码
管道pipeline
实现的原理
实现步骤
代码实现:apps/verifications/views.py
验证码视图文件
"""
apps/verifications/views.py 验证码视图文件
"""
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
from .libs.captcha.captcha import captcha # 调用实例化对象captcha
from django_redis import get_redis_connection # 连接redis
import random
from verifications.libs.ronglianyun.ccp_sms import CCP # 导入发送短信验证码类
from verifications import constants # 导入定义软编码文件
from utils.response_code import RETCODE # 导入定义状态码文件
import logging
logger = logging.getLogger('django') # 创建日志,配置文件中名称为django
# 图形验证码
class ImageCodeView(View):
"""图像验证码"""
def get(self, request, uuid):
"""
:param uuid:用于标识该验证码属于哪个用户,用户注册时期没有id标识,用uuid不会产生重复的id
:return:
"""
# 生成验证码,从生成验证码文件中调用实例化对象的方法
text, image = captcha.generate_captcha()
# 先连接redis,再保存到redis
redis_conn = get_redis_connection('verify_code') # verify_code是dev.py配置文件中的redis配置参数
# redis_conn.set('img_%s' % uuid, text) # set(key,value), 这种保存redis数据,无法设置保存时效
redis_conn.setex('img_%s' % uuid, constants.IMAGE_CODE_REDIS_EXPIRES, text) # set(key,expries,value),expries是时效,以秒s为单位
# 响应图形验证码
# return HttpResponse('image/jpg')
return HttpResponse(image, content_type='image/jpg')
# 手机验证码
class SMSCodeView(View):
"""短信验证码"""
def get(self, request, mobile):
"""
:param mobile: 手机号
:return: json数据类型
"""
# 接收参数
image_code_client = request.GET.get('image_code') # image_code_client是字符串数据类型
uuid = request.GET.get('uuid')
# 校验参数 image_code_client, uuid必须都存在
if not all([image_code_client, uuid]):
return HttpResponseForbidden('缺少必传参数')
# 创建连接到redis的对象
# 提取图形验证码
redis_conn = get_redis_connection('verify_code')
# 判断短信验证码是否已经发送
send_flag = redis_conn.get("send_flag_%s" % mobile)
if send_flag:
return JsonResponse({"code":111, 'errmsg': "短信验证码发送频繁"})
image_code_server = redis_conn.get('img_%s' % uuid) # 此时的image_code_server是字节数据类型
# print(type(image_code_server))
# print(type(image_code_client))
# 判断图形验证码的有无
if image_code_server is None:
return JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码已经失效了"})
# 删除图形验证码,避免恶意测试图形验证码
redis_conn.delete('img_%s' % uuid)
# 对比图形验证码 .lower()都转成小写
if image_code_client.lower() != image_code_server.decode().lower(): # decode()方法将字节数据转换成str
return JsonResponse({"code": RETCODE.IMAGECODEERR, 'errmsg': "图形验证码输入有误!"}) # RETCODE.IMAGECODEERR定义的状态码
# 随机生成短信验证码:生成6位数验证码
sms_code = "%06d" % random.randint(0, 999999) # 06d代表前几位可以用0补充
# print(sms_code)
# 生成验证码的另一种写法
# for i in range(6):
# sms_code += str(random.randint(0, 9))
# 验证码保存到log日志中
logger.info(sms_code)
"""
# 保存短信验证码
redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code) # 保存300s
# 保存短信验证码是否已经发送,constants.SEND_SMS_CODE_FLAG保存时效60s 1是value,随意取,"send_flag_%s" % mobile是key
redis_conn.setex("send_flag_%s" % mobile, constants.SEND_SMS_CODE_FLAG, 1)
""" # 采用管道pipeline实现redis请求
# 创建redis管道
pl = redis_conn.pipeline()
# 将命令添加到队列中
pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
pl.setex("send_flag_%s" % mobile, constants.SEND_SMS_CODE_FLAG, 1)
# 执行
pl.execute()
# 发送短信验证码send_message(mobile, datas, tid)中tid是模板,
# 默认为1,datas是数据和保存时效;constants.SMS_CODE_REDIS_EXPIRES//60 双//为了得到整数
CCP().send_message(mobile, (sms_code, constants.SMS_CODE_REDIS_EXPIRES//60), 1)
# 响应结果
return JsonResponse({"code": RETCODE.OK, 'errmsg': "发送短信验证码成功"}) # RETCODE.OK定义状态码
问题:
解决:
在这个项目中: 解耦
结论:
安装Celery
虚拟环境中安装
pip install Celery
celery_tasks.main.py
# celery启动文件
from celery import Celery
# 创建celery实例
celery_app = Celery('meiduo')
加载Celery配置
celery_tasks.config.py
# 指定消息队列的位置
broker_url = "redis://127.0.0.1/10"
celery_tasks.main.py
# celery启动文件
from celery import Celery
# 创建celery实例
celery_app = Celery('meiduo')
# 加载celery配置
celery_app.config_from_object('celery_tasks.config')
定义发送短信任务
注册任务:celery_tasks.main.py
# celery启动文件
from celery import Celery
# 创建celery实例
celery_app = Celery('meiduo')
# 加载celery配置
celery_app.config_from_object('celery_tasks.config')
# 自动注册celery任务
celery_app.autodiscover_tasks(['celery_tasks.sms'])
定义任务:celery_tasks.sms.tasks.py
@celery_app.task(bind=True, name='ccp_send_sms_code', retry_backoff=3)
def ccp_send_sms_code(self, mobile, sms_code):
"""
发送短信异步任务
:param mobile: 手机号
:param sms_code: 短信验证码
:return: 成功0 或 失败-1
"""
try:
send_ret = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)
except Exception as e:
logger.error(e)
# 有异常自动重试三次
raise self.retry(exc=e, max_retries=3)
if send_ret != 0:
# 有异常自动重试三次
raise self.retry(exc=Exception('发送短信失败'), max_retries=3)
return send_ret
启动Celery服务
# Linux系统中
celery -A celery_tasks.main worker -l info
# Windows系统中
celery -A celery_tasks.main worker -l info --pool=solo
调用发送短信任务
# 发送短信验证码
# CCP().send_template_sms(mobile,[sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)
# Celery异步发送短信验证码
ccp_send_sms_code.delay(mobile, sms_code)
celery主文件:celery_tasks/main.py
# -*- encoding: utf-8 -*-
"""
@File : main.py
@Time : 2020/8/7 14:23
@Author : chen
celery主文件:/celery_tasks/main.py
"""
# celery启动文件
from celery import Celery
# 创建celery实例 'shop'名称
celery_app = Celery('shop')
# 加载配置文件
celery_app.config_from_object('celery_tasks.config')
# 自动注册celery任务
celery_app.autodiscover_tasks(['celery_tasks.sms']) # 自动去查找tasks.py文件并执行
"""
celery -A celery_tasks.main worker -l info
• -A指对应的应用程序, 其参数是项目中 Celery实例的位置。
• worker指这里要启动的worker。
• -l指日志等级,比如info等级。
"""
定义任务文件:shop/celery_tasks/sms/tasks.py
# -*- encoding: utf-8 -*-
"""
@File : tasks.py
@Time : 2020/8/7 17:09
@Author : chen
定义任务文件:shop/celery_tasks/sms/tasks.py
"""
from celery_tasks.sms.ronglianyun.ccp_sms import CCP # 将容联云的代码复制放到celery_tasks/sms文件内
from celery_tasks.sms import constants
from celery_tasks.main import celery_app
# 使用装饰器,celery识别任务,name是任务名称
@celery_app.task(name="send_sms_code")
def send_sms_code(mobile, sms_code):
"""
发送短信的异步任务
:param mobile:收集
:param sms_code:短信验证码
:return:成功0;失败-1
"""
# 发送短信验证码send_message(mobile, datas, tid)中tid是模板,
# 默认为1,datas是数据和保存时效;constants.SMS_CODE_REDIS_EXPIRES//60 双//为了得到整数
result = CCP().send_message(mobile, (sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60), 1)
return result
celery配置文件:celery_tasks/config.py
# -*- encoding: utf-8 -*-
"""
@File : config.py
@Time : 2020/8/7 17:03
@Author : chen
celery配置文件:celery_tasks/config.py
"""
# 指定中间人,消息队列,任务队列 redis 指定消息队列的位置
broker_url = "redis://127.0.0.1/10" # 使用redis第10个数据库
发送短信验证码文件:shop\celery_tasks\sms\ronglianyun/ccp_sms.py
# -*- encoding: utf-8 -*-
"""
@File : ccp_sms.py
@Time : 2020/8/2 17:23
@Author : chen
发送短信验证码文件:shop\celery_tasks\sms\ronglianyun/ccp_sms.py
"""
from ronglian_sms_sdk import SmsSDK
import json
accId = '8a216da873a33a500173a407c9bf010c' # 容联云通讯分配的主账号ID
accToken = '3e0d6a4bbe884ad9889d8d9a16c3747a' # 容联云通讯分配的主账号TOKEN
appId = '8a216da873a33a500173a407cab00113' # 容联云的APP ID
# 单例类的实例化能够节省内存空间,无论实例化多少次,内存空间只有一个
class CCP(object):
# __new__方法是__init__方法之上被调用的,__init__方法会在实例化时候调用,__new__方法是生成类的方法
def __new__(cls, *args, **kwargs): # 这里的cls代表CCP这个类
if not hasattr(cls, '_instance'): # 当不具有_instance这个属性的时候
cls._instance = super().__new__(cls, *args, **kwargs)
# print(type(cls._instance)) # cls._instance相当于CCP这个类
cls._instance.sdk = SmsSDK(accId, accToken, appId) # 给CCP这个类添加sdk这个属性,相当于实例化了SmsSDK这个类
return cls._instance
# 发送短信验证码
def send_message(self, mobile, datas, tid):
resp = self._instance.sdk.sendMessage(tid, mobile, datas)
# print(type(resp)) # str 需要转换成字典
result = json.loads(resp) # 转换数据类型
# sdk = SmsSDK(accId, accToken, appId)
# tid = '容联云通讯创建的模板ID'
# mobile = '15210438734'
# datas = ('变量1', '变量2')
# resp = sdk.sendMessage(tid, mobile, datas)
# print(resp)
if result['statusCode'] == '000000': # 当传输状态码为000000时候,代表发送信息成功
return 0
else:
return -1
# if __name__ == '__main__':
# a = CCP()
# res = a.send_message('13316551764', ('123456', 5), 1)
# print(res)