Flask学习笔记_异步论坛(四)

Flask学习笔记_异步论坛(四)

  • 1.配置和数据库链接
    • 1.exts.py里面实例化sqlalchemy数据库
    • 2.config.py配置app和数据库信息
    • 3.app.py导入exts和config并初始化到app上
  • 2.创建用户模型并映射到数据库
    • 1.models/auth.py创建用户模型
    • 2.app.py导入模型并用flask-migrate管理数据库
    • 3.命令行migrate三部曲将模型映射到数据库
  • 3.登录与注册页面的get请求
    • 1.首先写登录和注册的前端页面
    • 2.写它们的view蓝图并导入到__init__中
    • 3.蓝图注册到app
  • 4.邮箱验证功能
    • 1.邮箱验证
    • 2.使用celery异步发送邮箱验证网络请求
    • 3.使用flask-caching缓存验证码并验证
    • 4.重构restful API
  • 5.注册页面的post请求
    • 5.1注册页面邮箱验证码的ajax请求
    • 5.2注册页面的图形验证码功能
    • 5.3注册页面的post提交
  • 6.登录页面的post请求
  • 7.首页

1.配置和数据库链接

1.exts.py里面实例化sqlalchemy数据库

from flask_sqlalchemy import SQLAlchemy
db=SQLAlchemy()

2.config.py配置app和数据库信息

#1.app配置
DEBUG=True
#2.数据库配置
DB_USERNAME="root"
DB_PASSWORD="1xxxx"
DB_HOST="127.0.0.1"
DB_PORT="3306"
DB_NAME="aforum"
DB_URI="mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8mb4" % (DB_USERNAME,DB_PASSWORD,DB_HOST,DB_PORT,DB_NAME)
SQLALCHEMY_DATABASE_URI=DB_URI
SQLALCHEMY_TRACK_MODIFIER=False

3.app.py导入exts和config并初始化到app上

from flask import Flask
import config
from exts import db
app=Flask(__name__)#1.实例化app
app.config.from_object(config)#2.config配置文件绑定到app
db.init_app(app)#3.数据库绑定到app
@app.route('/')
def index():return "hello"
if __name__=="__main__":app.run()

2.创建用户模型并映射到数据库

1.models/auth.py创建用户模型

from exts import db
import shortuuid
from datetime import datetime
from werkzeug.security import generate_password_hash,check_password_hashclass UserModel(db.Model):__tablename__ = "user"id = db.Column(db.String(100), primary_key=True, default=shortuuid.uuid)email = db.Column(db.String(50), unique=True, nullable=False)username = db.Column(db.String(50), nullable=False)_password = db.Column(db.String(200), nullable=False)avatar = db.Column(db.String(100))signature = db.Column(db.String(100))join_time = db.Column(db.DateTime, default=datetime.now)is_staff = db.Column(db.Boolean, default=False)is_active = db.Column(db.Boolean, default=True)def __init__(self, *args, **kwargs):if "password" in kwargs:self.password = kwargs.get('password')kwargs.pop("password")super(UserModel, self).__init__(*args, **kwargs)@propertydef password(self):return self._password@password.setterdef password(self, newpwd):self._password = generate_password_hash(newpwd)def check_password(self,rawpwd):return check_password_hash(self.password, rawpwd)

2.app.py导入模型并用flask-migrate管理数据库

from flask_migrate import Migrate
from models import auth
migrate=Migrate(app,db)

3.命令行migrate三部曲将模型映射到数据库

在app.py文件的目录下

flask db init
flask db migrate
flask db upgrade

3.登录与注册页面的get请求

1.首先写登录和注册的前端页面

#1。首先抽出base.html文件
<html>
<head><meta charset="utf-8"><script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script><link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"><script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script><script src="{{ url_for('static', filename='front/js/zlajax.js') }}"></script><script src="{{ url_for('static', filename='front/js/zlparam.js') }}"></script><link rel="stylesheet" href="{{ url_for('static', filename='front/css/front_base.css') }}"><meta name="viewport" content="width=device-width, initial-scale=1"><title>{% block title %}{% endblock %}</title>{% block head %}{% endblock %}
</head><body><nav class="navbar navbar-default"><div class="container"><div class="navbar-header"><button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a class="navbar-brand" href="/">论坛</a></div><!-- Collect the nav links, forms, and other content for toggling --><div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"><ul class="nav navbar-nav"><li class="active"><a href="/">首页<span class="sr-only">(current)</span></a></li></ul><form class="navbar-form navbar-left"><div class="form-group"><input type="text" class="form-control" placeholder="请输入关键字"></div><button type="submit" class="btn btn-default">搜索</button></form><ul class="nav navbar-nav navbar-right">{% if user %}<li class="dropdown"><a href="#" class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">{{ user.username }}<span class="caret"></span></a><ul class="dropdown-menu" aria-labelledby="dropdownMenu1"><li><a href="{{ url_for('front.cms') }}">后台管理</a></li><li><a href="{{ url_for('front.setting') }}">设置</a></li><li><a href="{{ url_for('front.logout') }}">注销</a></li></ul></li>{% else %}<li><a href="{{ url_for('front.login') }}">登录</a></li><li><a href="{{ url_for('front.register') }}">注册</a></li>{% endif %}</ul></div><!-- /.navbar-collapse --></div><!-- /.container-fluid --></nav><div class="main-container">{% block body %}{% endblock %}</div>
</body></html>
#2.login.html文件
{% extends "front/base.html" %}{% block title %}登录
{% endblock %}{% block head %}<link rel="stylesheet" href="{{ url_for('static', filename='front/css/signbase.css') }}"><script src="{{ url_for('static', filename='front/js/login.js') }}"></script>
{% endblock %}
{% block body %}<div class="outer-box"><div class="logo-box"><a href="/"><img src="{{ url_for('static', filename='front/images/logo.png') }}" alt=""></a></div><h2 class="page-title">登录</h2><div class="sign-box"><div class="form-group"><input type="text" class="form-control" name="email" placeholder="邮箱"></div><div class="form-group"><input type="password" class="form-control" name="password" placeholder="密码"></div><div class="checkbox"><label><input type="checkbox" name="remember" value="1">记住我</label></div><div class="form-group"><button class="btn btn-warning btn-block" id="submit-btn">立即登录</button></div><div class="form-group"><a href="#" class="signup-link">没有账号?立即注册</a><a href="#" class="resetpwd-link" style="float:right;">找回密码</a></div></div></div>
{% endblock %}
#3.register.html文件
{% extends "front/base.html" %}{% block title %}注册
{% endblock %}{% block head %}<link rel="stylesheet" href="{{ url_for('static', filename='front/css/signbase.css') }}"><script src="{{ url_for('static', filename='front/js/register.js') }}"></script>
{% endblock %}{% block body %}<div class="outer-box"><div class="logo-box"><a href="/"><img src="{{ url_for('static', filename='front/images/logo.png') }}" alt=""></a></div><h2 class="page-title">注册</h2><div class="sign-box"><div class="form-group"><div class="input-group"><input type="email" class="form-control" name="email" placeholder="邮箱"><span class="input-group-btn"><button id="email-captcha-btn" class="btn btn-default">发送验证码</button></span></div></div><div class="form-group"><input type="text" class="form-control" name="email-captcha" placeholder="邮箱验证码"></div><div class="form-group"><input type="text" class="form-control" name="username" placeholder="用户名"></div><div class="form-group"><input type="password" class="form-control" name="password" placeholder="密码"></div><div class="form-group"><input type="password" class="form-control" name="repeat-password" placeholder="确认密码"></div><div class="form-group"><div class="input-group"><input type="text" class="form-control" name="graph-captcha" placeholder="图形验证码"><span class="input-group-addon captcha-addon"><img id="captcha-img" class="captcha-img" src="#" alt=""></span></div></div><div class="form-group"><button class="btn btn-warning btn-block" id="submit-btn">立即注册</button></div></div></div>
{% endblock %}

2.写它们的view蓝图并导入到__init__中

#1.在apps/front/views.py里面写蓝图的视图函数
from flask import Blueprint,request,render_template
bp=Blueprint("front",__name__,url_prefix="/")@bp.route('/login/', methods=['GET', 'POST'])
def login():if request.method == 'GET':return render_template('front/login.html')@bp.route('/register/', methods=['GET', 'POST'])
def register():if request.method == 'GET':return render_template('front/register.html')
#2.在apps/front/__init__.py里面导入蓝图
from .views import bp as front_bp                             

3.蓝图注册到app

#在app.py里面导入蓝图并注册到app上
from apps.front import front_bp
app.register_blueprint(front_bp)

4.邮箱验证功能

1.邮箱验证

#1.在config里面配置邮箱第三方服务商来发送邮件
MAIL_SERVER="smtp.qq.com"#发送验证码的邮箱服务器,这里是自己公司的邮箱服务器
MAIL_PORT='587'#587是tls协议,465是ssl协议
MAIL_USE_TLS=True
#MAIL_USE_SSL
MAIL_USERNAME="1xxxc9@qq.com"
MAIL_PASSWORD="wxxbe"
MAIL_DEFAULT_SENDER="11xx@qq.com"
#2.exts里面导入mail
from flask_mail import Mail
mail=Mail()
#3.在app里面把exts里面的mail导入进来并绑定到app
from exts import db,mail
mail.init_app(app)
#4.开始在views里面写发送邮箱验证码的视图函数
from exts import mail
from flask_mail import Message
from flask importjsonify
import string,random
@bp.get("/email/captcha/")
def email_captcha():email=request.args.get('email')if not email:return jsonify({"code":400,"message":"请先传入邮箱"})source=list(string.digits)captcha="".join(random.sample(source,6))message=Message(subject="注册验证码",recipients=[email],body="您的注册验证码是:%s" % captcha)try:mail.send(message)except Exception as e:print("邮件发送失败")print(e)return jsonify({"code":500,"message":"邮件发送失败"})return jsonify({"code":200,"message":"邮件发送成功"})

2.使用celery异步发送邮箱验证网络请求

celery(分布式任务队列/任务调度器)和redis(内存数据库)的教程和安装步骤可以参考学习。Broker和Backend都用redis存储。

pip install gevent
pip install redis
pip install hiredis
启动celery

redis-cli

在这里插入图片描述

#1.在config中设置reids的相关信息
CELERY_BROKER_URL="redis://127.0.0.1:6379/0"#broker
CELERY_RESULT_BACKEND="redis://127.0.0.1:6379/0"#backend
#2.mycelery.py里面定义并添加任务
from flask_mail import Message
from exts import mail
from celery import Celery# 定义任务函数
def send_mail(recipient,subject,body):message = Message(subject=subject,recipients=[recipient],body=body)try:mail.send(message)return {"status": "SUCCESS"}except Exception :return {"status": "FAILURE"}# 创建celery对象
def make_celery(app):celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'],broker=app.config['CELERY_BROKER_URL'])TaskBase = celery.Taskclass ContextTask(TaskBase):abstract = Truedef __call__(self, *args, **kwargs):with app.app_context():return TaskBase.__call__(self, *args, **kwargs)celery.Task = ContextTaskapp.celery = celery# 添加任务celery.task(name="send_mail")(send_mail)return celery
#3.在app.py里面将celery绑定到app
from mycelery import make_celery
mycelery=make_celery(app)
#4.在views.py里面利用current_app调用celery里面的task任务
from flask import current_app
@bp.get("/email/captcha/")
def email_captcha():email=request.args.get('email')if not email:return jsonify({"code":400,"message":"请先传入邮箱"})source=list(string.digits)captcha="".join(random.sample(source,6))subject="注册验证码"body="您的注册验证码是:%s"%captchacurrent_app.celery.send_task("send_mail",(email,subject,body))return jsonify({"code":200,"message":"邮件发送成功"})
#5.在工程目录下运行这个celery
celery -A app.mycelery worker --loglevel=info -P gevent
#6.访问这个视图函数就可以成功利用celery进行异步任务调取

3.使用flask-caching缓存验证码并验证

flask-caching的相关教程可以查看博文。

#1.安装:pip install flask-caching
#2.在config里面写flask-caching相关的配置
CACHE_TYPE="RedisCache"
CACHE_DEFAULT_TIMEOUT=300
CACHE_REDIS_HOST="127.0.0.1"
CACHE_REDIS_PORT=6379
#3.在exts里面引入caching
from flask_caching import Cache
cache=Cache()
#4.在app.py里面init
from exts import cache
cache.init_app(app)
#5.在view的视图函数里面缓存验证码
from exts import cache
cache.set(email,captcha)#cache缓存是键值对的形式

4.重构restful API

#1.在utils/restful.py里面
# Restful API
from flask import jsonifyclass HttpCode(object):# 响应正常ok = 200# 没有登陆错误unloginerror = 401# 没有权限错误permissionerror = 403# 客户端参数错误paramserror = 400# 服务器错误servererror = 500def _restful_result(code, message, data):return jsonify({ "code": code,"message": message or "", "data": data or {}})def ok(message=None, data=None):return _restful_result(code=HttpCode.ok, message=message, data=data)def unlogin_error(message="没有登录!"):return _restful_result(code=HttpCode.unloginerror, message=message, data=None)def permission_error(message="没有权限访问!"):return _restful_result(code=HttpCode.paramserror, message=message, data=None)def params_error(message="参数错误!"):return _restful_result(code=HttpCode.paramserror, message=message, data=None)def server_error(message="服务器开小差啦!"):return _restful_result(code=HttpCode.servererror, message=message or '服务器内部错误', data=None)
#2.在view视图函数里
from utils import restful
return restful.params_error(message="请先传入邮箱")
return restful.ok(message="邮件发送成功")

5.注册页面的post请求

5.1注册页面邮箱验证码的ajax请求

#1.在register.html里面引入js文件
<script src="{{ url_for('static', filename='front/js/register.js') }}"></script>
#2.在register.js里面监听(4步),这里引用zlajax是因为它自动给了csrf-token
var RegisterHandler = function (){\\1.定义了一个JavaScript对象}RegisterHandler.prototype.listenSendCaptchaEvent = function (){\\2.包含一个方法var callback = function (event){// 原生的JS对象:this => jQuery对象var $this = $(this);// 阻止默认的点击事件event.preventDefault();var email = $("input[name='email']").val();var reg = /^\w+((.\w+)|(-\w+))@[A-Za-z0-9]+((.|-)[A-Za-z0-9]+).[A-Za-z0-9]+$/;if(!email || !reg.test(email)){alert("请输入正确格式的邮箱!");return;}zlajax.get({url: "/email/captcha?email=" + email,success: function (result){if(result['code'] == 200){console.log("邮件发送成功!");// 取消按钮的点击事件$this.off("click");// 添加禁用状态$this.attr("disabled", "disabled");// 开始倒计时var countdown = 60;var interval = setInterval(function (){if(countdown > 0){$this.text(countdown);}else{$this.text("发送验证码");$this.attr("disabled", false);$this.on("click", callback);// 清理定时器clearInterval(interval);}countdown--;}, 1000);}else{var message = result['message'];alert(message);}}})}$("#email-captcha-btn").on("click", callback);
}
RegisterHandler.prototype.run = function (){\\3.方法在run函数里调用this.listenSendCaptchaEvent();
}// $(function(){})
$(function (){\\4.实例化并运行var handler = new RegisterHandler();handler.run();
})#3.post请求要用csrf-token,所以在base.html里面引入
<meta name="csrf-token" content="{{csrf_token()}}">
#4.csrf-token需要先安装:
pip install flask-wtf
#5.在config里面设置secretkey
SECRET_KEY="FASDFNMLKSDF"
#6.在exts里面引入
from flask_wtf import CSRFProtect
csrf=CSRFProtect()
#6.在app上绑定init
from exts import csrf
csrf.init_app(app)

5.2注册页面的图形验证码功能

#1.在config里面获取工程的base目录
import os
BASE_DIR=os.path.dirname(__file__)
#2.在utils目录下的captcha的init文件里生成图形验证码
import random
import string
# Image:一个画布
# ImageDraw:一个画笔
# ImageFont:画笔的字体
from PIL import Image,ImageDraw,ImageFontfrom flask import current_app
import os# pip install pillow# Captcha验证码class Captcha(object):# 生成几位数的验证码number = 4# 验证码图片的宽度和高度size = (100,30)# 验证码字体大小fontsize = 25# 加入干扰线的条数line_number = 2# 构建一个验证码源文本SOURCE = list(string.ascii_letters)for index in range(0, 10):SOURCE.append(str(index))#用来绘制干扰线@classmethoddef __gene_line(cls,draw,width,height):begin = (random.randint(0, width), random.randint(0, height))end = (random.randint(0, width), random.randint(0, height))draw.line([begin, end], fill = cls.__gene_random_color(),width=2)# 用来绘制干扰点@classmethoddef __gene_points(cls,draw,point_chance,width,height):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=cls.__gene_random_color())# 生成随机的颜色@classmethoddef __gene_random_color(cls,start=0,end=255):random.seed()return (random.randint(start,end),random.randint(start,end),random.randint(start,end))# 随机选择一个字体@classmethoddef __gene_random_font(cls):fonts = ['Courgette-Regular.ttf','LHANDW.TTF','Lobster-Regular.ttf','verdana.ttf']font = random.choice(fonts)fontpath = os.path.join(current_app.config['BASE_DIR'],'utils','captcha',font)# return 'utils/captcha/'+fontreturn fontpath# 用来随机生成一个字符串(包括英文和数字)@classmethoddef gene_text(cls, number):# number是生成验证码的位数return ''.join(random.sample(cls.SOURCE, number))#生成验证码@classmethoddef gene_graph_captcha(cls):# 验证码图片的宽和高width,height = cls.size# 创建图片# R:Red(红色)0-255# G:G(绿色)0-255# B:B(蓝色)0-255# A:Alpha(透明度)image = Image.new('RGBA',(width,height),cls.__gene_random_color(0,100))# 验证码的字体font = ImageFont.truetype(cls.__gene_random_font(),cls.fontsize)# 创建画笔draw = ImageDraw.Draw(image)# 生成字符串text = cls.gene_text(cls.number)# 获取字体的尺寸font_width, font_height = font.getsize(text)# 填充字符串draw.text(((width - font_width) / 2, (height - font_height) / 2),text,font= font,fill=cls.__gene_random_color(150,255))# 绘制干扰线for x in range(0, cls.line_number):cls.__gene_line(draw, width, height)# 绘制噪点cls.__gene_points(draw, 10, width, height)return (text,image)
#3.在views里面写视图函数
from utils.captcha import Captcha
import time
from hashlib import md5
from io import BytesIO
from flask import make_response
@bp.route("/graph/captcha/")
def graph_captcha():captcha,image=Captcha.gene_graph_captcha()key=md5((captcha+str(time.time())).encode('utf-8')).hexdigest()cache.set(key,captcha)#cache里面缓存这个captchabuffer=BytesIO()image.save(buffer,"png")buffer.seek(0)#buffer文件指针指向最开始的位置resp=make_response(buffer.read())resp.content_type="image/png"resp.set_cookie("_graph_captcha_key",key,max_age=3600)#将key值保存到cookie1个小时return resp
#4.在register.html里面写图片验证码的src
<img id="captcha-img" class="captcha-img" src="{{url_for('front.graph_captcha')}}" alt="">
#5.实现点击图片重新生成,所以在regist.js里面监听
RegisterHandler.prototype.listenGraphCaptchaEvent = function (){$("#captcha-img").on("click", function (){console.log("点击了图形验证码");var $this = $(this);var src = $this.attr("src");// /graph/captcha// /graph/captcha?sign=Math.random()// 防止一些老的浏览器,在两次url相同的情况下,不会重新发送请求,导致图形验证码不会更新let new_src = zlparam.setParam(src, "sign", Math.random())$this.attr("src",new_src);});
}
RegisterHandler.prototype.run = function (){this.listenSendCaptchaEvent();this.listenGraphCaptchaEvent();
}

5.3注册页面的post提交

#1.在front/forms.py里面进行表单验证
from wtforms import Form,ValidationError
from wtforms.fields import StringField
from wtforms.validators import Email,Length,EqualTo
from models.auth import UserModel#对表单进行二次验证
from exts import cache
from flask import request
class BaseForm(Form):@propertydef messages(self):message_list = []if self.errors:for error in self.errors.values():message_list.extend(error)return message_list
class RegisterForm(BaseForm):email=StringField(validators=[Email(message="请输入正确的邮箱")])email_captcha=StringField(validators=[Length(6,6,message="请输入6位验证码")])username=StringField(validators=[Length(3,20,message="请输入3-20位的用户名")])password=StringField(validators=[Length(6,20,message="请输入6-20位的密码")])    repeat_password=StringField(validators=[EqualTo("password",message="两次密码不一致")])graph_captcha=StringField(validators=[Length(4,4,message="请输入4位图形验证码")])def validate_email(self,field):email=field.datauser=UserModel.query.filter_by(email=email).first()if user:raise ValidationError(message="邮箱已经被注册")def validate_email_captcha(self,field):email_captcha=field.dataemail=self.email.datacache_captcha=cache.get(email)if not cache_captcha or cache_captcha!=email_captcha:raise ValidationError(message="邮箱验证码错误")def validate_graph_captcha(self,field):graph_captcha=field.datakey=request.cookies.get("_graph_captcha_key")cache_captcha=cache.get(key)if not cache_captcha or cache_captcha.lower()!=graph_captcha.lower():raise ValidationError(message="图形验证码错误")
#2.在front/views.py里面写post视图函数
from .forms import RegisterForm
from models.auth import UserModel
from exts import db
@bp.route('/register/', methods=['GET', 'POST'])
def register():if request.method == 'GET':return render_template('front/register.html')else:form=RegisterForm(request.form)if form.validate():email=form.email.datausername=form.username.datapassword=form.password.datauser=UserModel(email=email,username=username,password=password)db.session.add(user)db.session.commit()return restful.ok()else:message=form.messages[0]return restful.params_error(message=message)
#3.在js里面绑定点击事件,跳到上面的视图函数
RegisterHandler.prototype.listenSubmitEvent = function (){$("#submit-btn").on("click", function (event){event.preventDefault();var email = $("input[name='email']").val();var email_captcha = $("input[name='email-captcha']").val();var username = $("input[name='username']").val();var password = $("input[name='password']").val();var repeat_password = $("input[name='repeat-password']").val();var graph_captcha = $("input[name='graph-captcha']").val();// 如果是商业项目,一定要先验证这些数据是否正确zlajax.post({url: "/register",data: {"email": email,"email_captcha": email_captcha,"username": username,password, // "password": passwordrepeat_password,graph_captcha},success: function (result){if(result['code'] == 200){window.location = "/login";}else{alert(result['message']);}}})});
}RegisterHandler.prototype.run = function (){this.listenSendCaptchaEvent();this.listenGraphCaptchaEvent();this.listenSubmitEvent();
}

6.登录页面的post请求

#1.首先表单验证
from wtforms.fields import IntegerField
class LoginForm(BaseForm):email=StringField(validators=[Email(message="请输入正确的邮箱")])password=StringField(validators=[Length(6,20,message="请输入6-20位的密码")]) remember=IntegerField()
#2.视图函数
from flask import session
from .forms import LoginForm
@bp.route('/login/', methods=['GET', 'POST'])
def login():if request.method == 'GET':return render_template('front/login.html')else:form=LoginForm(request.form)if form.validate():email=form.email.datapassword=form.password.dataremember=form.remember.datauser=UserModel.query.filter_by(email=email).first()if not user:return restful.params_error("此邮箱没有注册")if not user.check_password(password):return restful.params_error("邮箱或密码错误")session['user_id']=user.idif remember ==1:session.permanent=Truereturn restful.ok()else:return restful.params_error(message=form.messages[0])
#3.在config里面设置permanent时间
from datetime import timedelta
PERMANENT_SESSION_LIFETIME=timedelta(days=7)
#4.登录的post提交的前端监听,在login.js中,并加载到html中
var LoginHandler = function (){}LoginHandler.prototype.listenSubmitEvent = function (){$("#submit-btn").on("click", function (event){event.preventDefault();var email = $("input[name='email']").val();var password = $("input[name='password']").val();var remember = $("input[name='remember']").prop("checked");zlajax.post({url: "/login",data: {email,password,remember: remember?1:0},success: function (result){if(result['code'] == 200){var token = result['data']['token'];var user = result['data']['user'];localStorage.setItem("JWT_TOKEN_KEY", token);localStorage.setItem("USER_KEY", JSON.stringify(user));window.location = "/"}else{alert(result['message']);}}})});
}LoginHandler.prototype.run = function (){this.listenSubmitEvent();
}$(function (){var handler = new LoginHandler();handler.run();
});

7.首页

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/18015.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

教师工作量管理系统Springmvc+Spring+Mybatis课程工作量教室java源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 教师工作量管理系统SpringmvcSpringMybatis 系统有1权…

快速开发人脸识别系统Java版本

简介&#xff1a; 先说下什么是人脸识别系统&#xff1a;举个例子&#xff0c;公司门口有个人脸识别系统&#xff0c;员工站到门口&#xff0c;看着摄像头&#xff0c;大屏幕上会抓拍到你的人脸&#xff0c;然后和公司的员工照片库里的照片比对&#xff0c;比对成功就提示&…

ThreadLocal原理

ThreadLocal原理 ThreadLocal对象new出来存放到堆中&#xff0c;ThreadLocal引用是存放在栈里 Thread 类有个 ThreadLocalMap 成员变量&#xff0c;Map的key是Threadlocal 对象&#xff0c;value是你要存放的线程局部变量。 public void set(T value) {//获取当前线程Thread&…

python爬虫(四)_urllib2库的基本使用

本篇我们将开始学习如何进行网页抓取&#xff0c;更多内容请参考:python学习指南 urllib2库的基本使用 所谓网页抓取&#xff0c;就是把URL地址中指定的网络资源从网络流中读取出来&#xff0c;保存到本地。在Python中有很多库可以用来抓取网页&#xff0c;我们先学习urllib2。…

从零开始学python(十三)爬虫工程师自动化和抓包

前言 回顾之前讲述了python语法编程 必修入门基础和网络编程&#xff0c;多线程/多进程/协程等方面的内容&#xff0c;后续讲到了数据库编程篇MySQL&#xff0c;Redis&#xff0c;MongoDB篇&#xff0c;和机器学习&#xff0c;全栈开发&#xff0c;数据分析&#xff0c;爬虫数…

Go项目实现日志按时间及文件大小切割并压缩

关于日志的一些问题: 单个文件过大会影响写入效率&#xff0c;所以会做拆分&#xff0c;但是到多大拆分? 最多保留几个日志文件&#xff1f;最多保留多少天&#xff0c;要不要做压缩处理&#xff1f; 一般都使用 lumberjack[1]这个库完成上述这些操作 lumberjack //info文件wr…

uniapp实现地图点聚合

点聚合的最重要的一个地方是在 markers 中添加 joinCluster true 这个重要的属性&#xff0c;否则将无法开启点聚合功能。 其实在uniapp的官方文档里体现的不是那么清楚&#xff0c;但是在小程序文档提示的就相当清楚。 实现效果如下&#xff1a; 重点&#xff1a;需要编译在小…

【密码学】四、SM4分组密码算法

SM4分组密码算法 1、概述1.1初始变量算法1.2密钥扩展算法1.3轮函数F1.3.1合成置换T1.3.2S盒 2、算法设计原理2.1非平衡Feistel网络2.2T变换2.2.1非线性变换τ2.2.2线性变换L2.2.3基础置换 2.3密钥扩展算法的设计 1、概述 SM4分组密码算法是一种迭代分组密码算法&#xff0c;采…

SERDES关键技术

目录 一、SERDES介绍 二、SERDES关键技术 2.1 多重相位技术 2.2 线路编解码技术 2.2.1 8B/10B编解码 2.2.2 控制字符&#xff08;Control Characters&#xff09; 2.2.3 Comma检测 2.2.4 扰码&#xff08;Scrambling&#xff09; 2.2.5 4B/5B与64B/66B编解码技术 2.3 包传…

【C++】-二叉搜索树的详解(递归和非递归版本以及巧用引用)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

LAXCUS分布式操作系统引领科技潮流,进入百度首页

信息源自某家网络平台&#xff0c;以下原样摘抄贴出。 随着科技的飞速发展&#xff0c;分布式操作系统做为通用基础平台&#xff0c;为大数据、高性能计算、人工智能提供了强大的数据和算力支持&#xff0c;已经成为了当今计算机领域的研究热点。近日&#xff0c;一款名为LAXCU…

一起学算法(栈篇)

1.栈的概念 1.栈的定义 栈是仅限在表尾进行插入和删除的线性表&#xff0c;栈又被称为先进后出的线性表&#xff0c;简称“LIFO” 我们这次用数组作为我们栈的底层数据结构&#xff0c;代码会放到结尾供大家参考使用 2.栈顶的定义 栈是一个线性表&#xff0c;我们允许插入…

Coremail中睿天下|2023年第二季度企业邮箱安全态势观察

7月24日&#xff0c;Coremail邮件安全联合中睿天下发布《2023第二季度企业邮箱安全性研究报告》&#xff0c;对2023第二季度和2023上半年的企业邮箱的安全风险进行了分析。 一、垃圾邮件同比下降16.38% 根据Coremail邮件安全人工智能实验室&#xff08;以下简称AI实验室&#…

【云原生-制品管理】制品管理的优势

制品介绍制品管理-DevOps制品管理优势总结 制品介绍 制品管理指的是存储、版本控制和跟踪在软件开发过程中产生的二进制文件或“制品”的过程。这些制品可以包括编译后的源代码、库和文档&#xff0c;包括操作包、NPM 和 Maven 包&#xff08;或像 Docker 这样的容器镜像&…

机器学习(一)---概述

文章目录 1.人工智能、机器学习、深度学习2.机器学习的工作流程2.1 获取数据集2.2 数据基本处理2.3 特征工程2.3.1 特征提取2.3.2 特征预处理2.3.3 特征降维 2.4 机器学习2.5 模型评估 3.机器学习的算法分类3.1 监督学习3.1.1 回归问题3.1.2 分类问题 3.2 无监督学习 1.人工智能…

【高级数据结构】并查集

目录 修复公路&#xff08;带扩展域的并查集&#xff09; 食物链&#xff08;带边权的并查集&#xff09; 修复公路&#xff08;带扩展域的并查集&#xff09; 洛谷&#xff1a;修复公路https://www.luogu.com.cn/problem/P1111 题目背景 A 地区在地震过后&#xff0c;连接…

数控机床主轴品牌选择及选型,如何维护和保养?

数控机床主轴品牌选择及选型&#xff0c;如何维护和保养&#xff1f; 数控机床是一种高精度、高效率、高自动化的机床。其中&#xff0c;主轴是数控机床的核心部件&#xff0c;承担着转动工件、切削加工的任务&#xff0c;决定了加工的转速、切削力度和加工效率。因此&#xff…

深空物联网通信中视频流的智能多路TCP拥塞控制|文献阅读|文献分析和学习|拥塞控制|MPTCP|SVC

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总https://blog.csdn.net/yu_cblog/categ…

前端构建(打包)工具发展史

大多同学的前端学习路线&#xff1a;三件套框架慢慢延伸到其他&#xff0c;在这个过程中&#xff0c;有一个词出现的频率很高&#xff1a;webpack 。 作为一个很出名的前端构建工具我们在网上随便一搜&#xff0c;就会有各种教程&#xff1a;loader plugin entry吧啦吧啦。 但…

企业可以申请DV https证书吗

DV https证书是有基础认证的数字证书&#xff0c;所以DV https证书也可以叫DV基础型https证书。DV基础型https证书是众多https证书中既支持个人&#xff0c;也支持企事业单位申请的https证书&#xff0c;所以企事业单位都可以申请DV基础型https证书&#xff0c;不论是企业门户网…