我的第一个项目(十四) :完成数据保存功能(前端,增查改接口)
Posted 养肥胖虎
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我的第一个项目(十四) :完成数据保存功能(前端,增查改接口)相关的知识,希望对你有一定的参考价值。
好家伙,天天拖,终于写完了
代码已开源(Gitee)
(前后端放一起了)
怎么说呢,感觉比较简洁,但是问题不大
实现了分数保存的功能
1.效果如下:
1.刷新页面后依旧保存数据
2.重新登录后,依旧保存数据
3.生命值为零后,游戏重置
2.代码如下:
Game.vue
MyLogin.vue
<template>
<div class="login-container">
<div class="login-box">
<!-- 头像区域 -->
<div class="text-center avatar-box">
<img src="../assets/logo.png" class="img-thumbnail avatar" alt="">
</div>
<!-- 表单区域 -->
<div class="form-login p-4">
<!-- 登录名称 -->
<div class="form-group form-inline">
<label for="username">账号:</label>
<input type="text" class="form-control ml-2" id="username" placeholder="请输入账号" autocomplete="off"
v-model.trim="loginForm.loginName" />
</div>
<!-- 登录密码 -->
<div class="form-group form-inline">
<label for="password">密码:</label>
<input type="password" class="form-control ml-2" id="password" placeholder="请输入密码"
v-model.trim="loginForm.password" />
</div>
<!-- 登录和重置按钮 -->
<div class="form-group form-inline d-flex justify-content-end">
<button type="button" class="btn btn-secondary mr-2" @click="writenum">测试</button>
<button type="button" class="btn btn-secondary mr-2" @click="toregister">去注册</button>
<button type="button" class="btn btn-primary" @click="login">登录</button>
</div>
</div>
</div>
</div>
</template>
<script>
import bus from \'../js/eventBus\'
export default
name: \'MyLogin\',
data()
return
loginForm:
id: \'\',
password: \'\',
life: null,
score: null,
loginName: null,
isFirst:true
,
methods:
writenum()
this.loginForm.loginName = 123456;
this.loginForm.password = 123456;
,
login()
// console.log(this.$store.state.count)
// console.log(\'submit!\',this.loginForm);
//表单验证
if (this.loginForm.loginName == "")
this.$message(
message: \'请输入用户名\',
type: \'error\'
);
return;
if (this.loginForm.password == "")
this.$message(
message: \'请输入密码\',
type: \'error\'
);
return;
//发送登陆请求
if (this.loginForm.loginName != "" && this.loginForm.password != "")
this.axios.post(\'http://localhost:3312/sys-user/login\', this.loginForm).then((resp) =>
console.log("this is login", resp);
let data = resp.data;
// console.log(this.$store.state.user)
console.log(resp.data.content)
//es6语法,扩展操作符,找到resp.data.content的每一个属性然后赋值给新的对象
// this.$store.state.user = ...resp.data.content
// console.log(this.$store.state.user)
//localStorage存
localStorage.setItem("insuranceCode", JSON.stringify(resp.data.content));
console.log(this.loginForm.isFirst)
localStorage.setItem("getisFirst", JSON.stringify(this.loginForm.isFirst));
console.log(JSON.parse(localStorage.getItem("getisFirst")))
//localStorage取
console.log(JSON.parse(localStorage.getItem("insuranceCode")))
if (data.success)
this.loginForm = ;
this.$message(
message: \'登陆成功!!!\',
type: \'success\'
);
this.$router.push( path: \'/game\' )
else
this.$message(
message: \'登陆失败,密码错误或用户名未注册\',
type: \'error\'
);
console.log(data)
)
,
toregister()
this.$router.push(\'/register\')
,
,
mounted()
// bus.$emit(\'getLoginName\', this.loginForm)
</script>
<style lang="less" scoped>
.login-container
background-color: #35495e;
height: 100%;
.login-box
width: 400px;
height: 250px;
background-color: #fff;
border-radius: 3px;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 0 6px rgba(255, 255, 255, 0.5);
.form-login
position: absolute;
bottom: 0;
left: 0;
width: 100%;
box-sizing: border-box;
.form-control
flex: 1;
.avatar-box
position: absolute;
width: 100%;
top: -65px;
left: 0;
.avatar
width: 120px;
height: 120px;
border-radius: 50% !important;
box-shadow: 0 0 6px #efefef;
</style>
3.代码解释:
这个怎么说呢,其实整个思路非常简单,就是写的时候会有很多小毛病,小bug
思路:
3.1.登陆验证
首先我们在登陆的时候,拿着用户输入的用户名和密码,发一次登陆请求,
后端验证密码后,将用户的数据返回(包括id,分数,生命...)
前端拿到数据之后,将数据保存到本地localStorage
localStorage.setItem("insuranceCode", JSON.stringify(resp.data.content));
3.2然后跳转到我们的Game.vue中去
3.3.判断是否首次进入
我们在表单数据中添加一个isFirst属性,来判断是否首次进入游戏界面
isFirst:true
localStorage.setItem("getisFirst", JSON.stringify(this.loginForm.isFirst));
3.3.1.若为首次进入游戏界面
if (JSON.parse(localStorage.getItem("getisFirst")) == true)
location.reload();
console.log("已刷新")
localStorage.setItem("getisFirst", JSON.stringify("false"));
将页面刷新
随后将isFirst的状态改为"false"
(解释一下,感觉是资源加载的问题,首次进入游戏界面的时候,需要刷新一下,图片资源才能加载出来,
这也是为什么没有用其他的传值方案.其他的传值方案,刷新一下就没了)
3.4.随后拿到数据并赋值给this.player
//ES6对象的拓展运算符...Object
//拓展运算符(...)用于取出参数对象所有可遍历属性然后拷贝到当前对象
this.player = ...JSON.parse(localStorage.getItem("insuranceCode")) ;
window.life = this.player.life
window.score = this.player.score
3.5.为游戏状态赋值
window.life和window.score是我们的游戏参数
3.6.使用计时器
随后就是我们的关键计时器了
setInterval(() =>
//当生命值小于1,即为零时,游戏重置
if (window.life < 1)
// window.life = 3
// window.score = 0;
console.log("已重置")
this.player.life = 3;
this.player.score = 0;
localStorage.setItem("insuranceCode", JSON.stringify(this.player));
this.axios.post(\'http://localhost:3312/sys-user/update\', this.player)
.then((resp) =>
console.log("this is update", resp);
let data = resp.data;
//
if (data.success)
console.log(
message: \'修改成功\',
type: \'success\'
);
)
window.life = 3
window.score = 0
this.player.life = window.life
this.player.score = window.score
console.log(this.player)
localStorage.setItem("insuranceCode", JSON.stringify(this.player));
console.log(this.player.life, this.player.score,window.life,window.score)
this.axios.post(\'http://localhost:3312/sys-user/update\', this.player)
.then((resp) =>
console.log("this is update", resp);
let data = resp.data;
//
if (data.success)
console.log(
message: \'修改成功\',
type: \'success\'
);
)
, 1000)
这里是一个每秒(1000毫秒)执行一次的计时器
此处进行判断,
3.6.1.若生命值为零了,对游戏数据进行初始化(分数归零,生命值为3)
随后发一次请求,保存数据
3.6.2.若生命值不为0,则
this.player.life = window.life
this.player.score = window.score
更新分数和生命值,然后发请求,将数据保存
解释完毕
我的第三十四篇博客---flask-cookie-sessionsqlchemary
cookie、session
获取cookie request.get.cookie(‘‘)
获取session session.get(‘‘)
cookie:指某些网站为了辨别用户身份、进行会话跟踪而储存在用户本地的数据(通常经过加密)
复数形式Cookies
cookie是由服务器生成,发送给客户端浏览器,浏览器会将Cookie的Key/value保存,下次请求同一网站时就发送该cookie给服务器(前提是浏览器设置为启用cookie)
cookie的Key/value可以由服务器端自己定义
Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
Cookie基于域名安全,不同域名的Cookie是不能互相访问的
如访问itcast.cn时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到itcast.cn写的Cookie信息
浏览器的同源策略
当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息
设置cookie
from flask import Flask,Response
@app.route(‘/cookie‘)
def set_cookie():
resp=Response("this is to set cookie")
resp.set_cookie(‘username‘,‘itcast‘)
return resp
设置过期时间
@app.route(‘/cookie‘)
def set_cookie():
response=Response(‘hello world‘)
response.set_cookie(‘username‘,‘itheima‘,3600) #单位是秒
return response
获取cookie
from flask import Flask,request
#获取cookie
@app.route(‘/request‘)
def resp_cookie():
resp=request.cookies.get(‘username‘)
return resp
Session
对于敏感重要的信息,建议储存在服务器端,在服务器端进行状态保持的方案就是session
session依赖于cookie
session数据的获取
session:请求上下文对象,用于处理http请求中的一些数据内容
@app.route(‘/index1‘)
def index1():
session[‘username‘]=‘itcast‘
return reddirect(url_for(‘index‘))
@app.route(‘/‘)
def index():
return session.get(‘username‘)
记得设置secretz-key=‘itcast‘ 这个里面的值自己可以随意设置
删除session
session.pop(‘‘)
app.config[‘PERMANENT_SESSION_LIFETIME‘]=20 #设置session的时效
连接mysql:
在Flask_SQLAlchemy中,插入、修改、删除操作,均由数据库会话管理
会话用db.session表示,在准备把数据写入数据库前,要先将数据添加到会话中,然后调用commit()方法提交会话
在Flask-SQLAlchemy中、查询操作是通过query对象操作数据
最基本的查询是返回表中所有数据,可以通过过滤器进行更精确的数据查询
db.session.add(role) 添加到数据库的session中
db.session.add_all([user1,user2]) 添加多个信息到session中
db.session.commit() 提交数据库的修改(包括增、删、改)
db.session.rollback() 数据库的回滚操作
db.session.delete(user) 删除数据库(需要跟上commit)
类型名 python中类型 说明
Integer int 普通整数,一般是32位
SmallInteger int 取值范围小的整数,一般是16位
BigInteger int或long 不限制精度的整数
Float float 浮点数
Numeric decimal.Decimal 普通整数,一般是32位
String str 变长字符串
Text str 变长字符串,对较长或不限长度的字符串做了优化
Unicode unicode 变长Unicode字符串
UnicodeText unicode 变长Unicode字符串,对较长或不限长度的字符串做了优化
Boolean bool 布尔值
Date datetime.date 时间
Time datetime.datetime 日期和时间
LargeBinary str 二进制文件
常用的SQLAlchemy列选项
选项名 说明
primary_key 如果为True,代表表的主键
unique 如果为True,代表这列不允许出现重复的值
index 如果为True,为这列创建索引,提高查询效率
nullable 如果为True,允许有空值,如果为False,不允许有空值
default 为这列定义默认值
常用的SQLAlchemy
选项名 说明
backref 在关系的另一模型中添加反向引用
primary join 明确指定两个模型之间使用的联结条件
uselist 如果为False,不使用列表,而使用标量值
order_by 指定关系中记录排序方式
secondary 指定多对多中记录的排序方式
数据库连接设置
在Flask-SQLAlchemy中,数据库使用URL指定,而且程序使用的数据库必须保存到Flask配置对象的SQLALCHEMY_DATABASE_URL键中
app.config[‘SQLALCHEMY_DATABASE_URL‘]=‘mysql://root:[email protected]:3306/数据库名‘
其他设置:
#动态追踪修改设置,如未设置只会提示警告
app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS‘]=True
#查询时会显示原始SQL语句
app.config[‘SQLALCHEMY_ECHO‘]=True
配置完成需要去MySQL中创建项目所使用的数据库
其他配置
名字 备注
SQLALCHEMY_DATABASE_URL 用于连接的数据库URL
常用的SQLAlchemy查询过滤器
过滤器 说明
filter() 把过滤器添加到原查询上,返回一个新查询
filter_by() 把等值过滤器添加到原查询上,返回一个新查询
limit 使用指定的值限定原查询返回的结果
offset() 偏移原查询返回的结果,返回一个新查询
order_by() 根据指定条件对原查询结果进行排序,返回一个新查询
group_by() 根据指定条件对原查询结果进行分组,返回一个新查询
常用的SQLAlchemy查询执行器
方法 说明
all() 以列表的形式返回查询的所有结果
first() 返回查询的第一个结果,如果未查到,返回None
first_or_404() 返回查询的第一个结果,如果未查到,返回404
get() 返回指定主键对应的行,如不存在,返回None
get_or_404() 返回指定主键对应的行,如不存在,返回404
count() 返回查询结果的数量
paginate() 返回一个Paginate对象,它包含指定范围内的结果
例如:
有两个模型Role 和 User
查询Role模型里的所有数据: Role.query.all()
查询User模型里的主键id为3数据: User.query.get(3)
查询User模型里id为4的数据: User.query.filter(User.id==4).all()
查询User模型里id不为4的数据的第一条:User.query.filter(User.id!=4).first()
查询名字等于wang的所有人:
User.query.filter(User.name==‘wang‘).all()
first()返回查询到的第一个对象
User.query.first()
all()返回查询到的所有对象
User.query.all()
filter模糊查询,返回名字结尾字符为g的所有数据
User.query.fliter(User.name.endswith(‘g‘)).all()
get():参数为主键,如果主键不存在没有返回内容
User.query.get()
逻辑非,返回名字不等于wang的所有数据
User.query.filter(User.name!=‘wang‘).all()
not_相当于取反
from sqlalchemy import not_
User.query.fliter(not_(User.name==‘chen‘)).all()
逻辑与,需要导入and_,返回and()条件满足的所有数据
from sqlalchemy import and_
User.query.fliter(and_(User.name!=‘wang‘,User.email.endswith(‘163.com‘))).all()
逻辑或,需要导入or_
from sqlalchemy import or_
User.query.filter(or_(User.name!=‘wang‘,User.email.endswith(‘163.com‘))).all()
查询数据后删除
user=User.query.first()
db.session.delete(user)
db.session.commit()
User.query.all()
更新数据
user=User.query.first()
user.name=‘dong‘
db.session.commit()
User.query.first()
关联查询示例:
角色和用户的关系是一对多的关系,一个角色可以有多个用户,一个用户只能属于一个角色
查询角色的所有用户
l=User.query.filter(User.name==‘钱‘).first() #查询User模型里姓名为钱的数据
r=Role.query.filter(Role.id==l.role_id).first() #查询Role模型里id与l.role_id相等的数据
print(r.name) #输出r.name
以上是关于我的第一个项目(十四) :完成数据保存功能(前端,增查改接口)的主要内容,如果未能解决你的问题,请参考以下文章
手把手教你实现Java权限管理系统 前端篇(十四):菜单功能实现
我的第三十四篇博客---flask-cookie-sessionsqlchemary
Go Web编程(无框架,自带 net/http 包)六创建订单和订单项结构及对应的表创建保存订单和订单项的函数完成去结账功能获取订单详情完成获取我的订单的函数