Python操作MySQL实战
文章导读
本文用于巩固Pymysql操作MySQL与MySQL操作的知识点,实现一个简易的音乐播放器,拟实现的功能包括:用户登录,窗口显示,加载本地音乐,加入和删除播放列表,播放音乐。
点击此处获取参考源码https://pan.baidu.com/s/1HNLc7tCVBjoBMpnezzm7_g?pwd=vqr4
1、创建数据库和表
概述:本章的操作均在navicat的查询中实现。
1.1、创建数据库
实操:通过navicat创建一个名为db_music的数据库,用于存储本实战中所有的表。
CREATE DATABASE db_music DEFAULT CHARACTER SET="utf8";
运行结果如下:
1.2、创建用户表
实操前准备:通过navicat切换到我们创建的数据库db_music,这里直接关闭之前打开的查询,然后按如下图所示的步骤操作。
实操:在db_music数据库下创建一个名为user_info的用户表,包含的字段如下:id,用户名(uname),密码(password),并将id设置为主键。
CREATE TABLE user_info(
id int PRIMARY KEY,
uname VARCHAR(20),
password VARCHAR(30)
)
运行后的结果为(也可以刷新数据库,查看db_music数据库下的表):
1.3、创建音乐列表
实操:在db_music数据库下创建一个用于保存本地音乐的表,取名为music_info,包含以下字段:id,歌曲名(name),歌手(singer)和存放路径(path),并将id设置为主键自增长。
CREATE TABLE music_info(
id int PRIMARY KEY auto_increment,
name varchar(30),
singer varchar(20),
path varchar(80)
);
运行结果如下:
1.4、创建播放列表
实操:在db_music数据库下创建一个用于播放本地音乐的表,取名为play_info,包含以下字段:歌单唯一标识(id),用于关联用户唯一标识id,通过该字段知道这是谁的播放列表(u_id),用于关联本地音乐的唯一标识id,通过该字段知道播放哪首音乐(m_id),并将id设置为主键自增长,正确的设置u_id和m_id的外键。
CREATE TABLE play_info(
id int PRIMARY KEY auto_increment,
u_id int,
m_id int,
FOREIGN KEY(u_id) REFERENCES user_info(id),
FOREIGN KEY(m_id) REFERENCES music_info(id)
);
运行结果如下:
此时,数据库db_music下就创建了三张表:
2、实现用户登录
2.1、插入数据
概述:为了能实现用户登录,首先得为user_info表中插入用户数据用于验证后续程序的可行性。
INSERT INTO user_info VALUES(1,"muxikeqi","123321");
运行后的user_info表数据如下:
2.2、引入链接数据库的工具类
概述:新建一个名为tools.py的文件,然后将学习Python操作MySQL时写的工具类拷贝过来并加以修改(这里主要是修改链接的数据库),用于简化后续对数据库操作。
import pymysqlclass DBUtil:"""工具类用于简化链接和关闭数据库的操作以及对数据的操作"""# 单独保存链接的参数,可以将其保存到特定文件中,直接调用文件获取也可config = {'host': "localhost",'user': "root",'passwd': "root",'db': "db_music",'charset': "utf8",'port': 3306}def __init__(self) -> None:"""构造函数用于获取链接和游标"""# **指字典对象self.con = pymysql.connect(**DBUtil.config)self.cursor = self.con.cursor()def close(self) -> None:"""该函数用于关闭链接和游标(关闭前需要判断是否存在)"""# 存在游标就关闭if self.cursor:self.cursor.close()# 存在链接就关闭if self.con:self.con.close()def dml(self, sql, args):"""本函数用于封装Mysql的DML语句,用于实现数据的增删改"""# 进行DML语句操作时一定要注意报错导致无法正常关闭链接try:# 执行sql中的DML语句self.cursor.execute(sql, args)# DML操作一定要通过链接对象提交事务self.con.commit()except Exception as e:print("存在错误,错误信息如下:", e)# 回滚前先判断链接还是否存在if self.con:# 回滚到原状态self.con.rollback()# 使用try...except...finally...最重要的作用就是保证链接正常关闭finally:print("即将关闭链接")self.close()def query_one(self, sql, args):"""本函数用于查询单条数据"""try:self.cursor.execute(sql, args)re = self.cursor.fetchone()return reexcept Exception as e:print("存在错误,错误信息如下:", e)finally:print("即将关闭链接")self.close()def query_many(self, sql):"""本函数用于查询所有数据"""try:self.cursor.execute(sql)# 获取结果并返回数据return self.cursor.fetchall()except Exception as e:print("存在错误,错误信息如下:", e)finally:print("即将关闭链接")self.close()if __name__ == "__main__":# 获取链接对象db = DBUtil()# 准备sql语句及其对应的参数sql = "select * from user_info where uname=%s and password=%s;"args =["muxikeqi","123321"]# 运行sql语句并关闭链接re = db.query_one(sql,args)print(re)pass
2.3、实现用户登录
概述:创建一个名为service.py的文件(与前面引入的tools.py文件放在同一目录),该文件用于写后端逻辑类代码,首先在service.py文件中写一个名为login的函数用于连接数据库并判断用户是否能登录成功。
from tools import DBUtilclass Music:def login(self, uname: str, password: str) -> bool:""":param uname:用户名:param password:密码:return: 登录成功返回True,登录失败返回False"""# 准备要执行的sql语句sql = "select * from user_info where uname=%s and password=%s"# 准备sql语句需要的参数args = (uname, password)# 创建工具对象(实际时获取数据库的链接对象和游标对象)db = DBUtil()# 利用游标对象调用对应的单条查询方法re = db.query_one(sql, args)# 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户if re:print("登录成功")return Trueelse:print("登录失败")return False# 测试代码
if __name__ == "__main__":# 创建Music类的实例对象service = Music()# 利用实例对象调用实例方法re = service.login("muxikeqi", "123321")print(re)
运行结果如下:
3、实现窗口(了解)
3.1、实现显示窗口
概述:窗口的实现将采用Tkinter实现,通过菜鸟教程可以查看其用法。
实操:创建一个名为ui.py的文件放在前面创建的.py文件的同级目录,该文件主要写前端页面的代码,文件中用一个名为Ui的类承载显示窗口的内容,为了让程序进入Ui类就能显示窗口所以推荐将显示窗口的内容直接放进构造函数中。
import tkinter
class Ui:def __init__(self):# 主窗口top = tkinter.Tk()# 创建按钮对象,第一个参数是父容器,text表示显示的内容b1 = tkinter.Button(top, text="播放")b2 = tkinter.Button(top, text="导入音乐")b3 = tkinter.Button(top, text="删除音乐")# 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)b1.grid(row=1,column=1,padx=10,pady=10)b2.grid(row=1,column=2,padx=10,pady=10)b3.grid(row=1,column=3,padx=10,pady=10)# 创建播放列表lisbox = tkinter.Listbox(top)# 设置播放列表位置,columnspan表示垮了多少列lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)# 进入消息循环top.mainloop()if __name__=="__main__":ui = Ui()
运行结果如下:
3.2、实现登陆后显示窗口
概述:前面已经实现了用户登录和窗口的显示,如果要实现登陆后显示窗口只需在ui.py文件中做出修改即可。
import tkinter
from service import Musicclass Ui:def __init__(self):# 主窗口top = tkinter.Tk()# 创建按钮对象,第一个参数是父容器,text表示显示的内容b1 = tkinter.Button(top, text="播放")b2 = tkinter.Button(top, text="导入音乐")b3 = tkinter.Button(top, text="删除音乐")# 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)b1.grid(row=1,column=1,padx=10,pady=10)b2.grid(row=1,column=2,padx=10,pady=10)b3.grid(row=1,column=3,padx=10,pady=10)# 创建播放列表lisbox = tkinter.Listbox(top)# 设置播放列表位置,columnspan表示垮了多少列lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)# 进入消息循环top.mainloop()if __name__=="__main__":# 获取用户名和密码uname = input("请输入用户名:")password = input("请输入密码:")# 创建Music类的实例对象ser = Music()# 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)if ser.login(uname,password):ui = Ui()else:print("用户名或密码错误!")
运行结果如下:
弹出的窗口如下:
4、实现播放音乐
概述:播放音乐将使用pygame模块实现。
实操前准备1:进入终端通过如下命令下载pygame模块。
pip install pygame
运行结果如下:
实操前准备2:去任意音乐网站下载任意首歌曲放在music项目目录中的任意文件夹中(这里我放在了名为music的文件夹中)
实操:利用pygame模块实现任意一首音乐的播放。
import pygame
import time
# 初始化加载音乐的混合器
pygame.mixer.init()
# 加载音乐(路径可以是相对路径也可以是绝对路径)
pygame.mixer.music.load(f".\music\c.flac")
# 播放音乐
pygame.mixer.music.play()
# 程序进入等待(不要立即关闭程序),单位为秒
time. Sleep(20)
20秒后程序运行结果如下:
5、为UI界面设置导入音乐的事件
概述:首先需要为导入音乐的按钮添加一个点击事件,点击事件用于打开文件夹让用户选择音乐文件。(只需要对ui.py文件做修改即可)
import tkinter
from service import Music
import tkinter.filedialogclass Ui:def __init__(self):# 主窗口top = tkinter.Tk()# 创建按钮对象,第一个参数是父容器,text表示显示的内容b1 = tkinter.Button(top, text="播放")b2 = tkinter.Button(top, text="导入音乐")b3 = tkinter.Button(top, text="删除音乐")# 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)b1.grid(row=1,column=1,padx=10,pady=10)b2.grid(row=1,column=2,padx=10,pady=10)b3.grid(row=1,column=3,padx=10,pady=10)# 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称(写法固定,不能修改),第二个参数是点击事件(点击按钮后触发的函数)b2.bind("<Button-1>",self.importMusic)# 创建播放列表lisbox = tkinter.Listbox(top)# 设置播放列表位置,columnspan表示垮了多少列lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)# 进入消息循环top.mainloop()# 导入音乐的点击事件def importMusic(self,event):# 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac")])if __name__=="__main__":# 获取用户名和密码uname = input("请输入用户名:")password = input("请输入密码:")# 创建Music类的实例对象ser = Music()# 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)if ser.login(uname,password):ui = Ui()else:print("用户名或密码错误!")
运行结果如下:
点击导入音乐按钮后的效果如下:
6、为后台添加导入音乐的逻辑
概述:本章节将实现前端选择音乐,后端将音乐名和音乐存放在本地的路径导入到db_music数据库下的music_info表的对应字段中。
首先,在service.py文件中的Music类中添加一个名为add_music的实例方法,用于将前端的数据添加到db_music数据库下music_info表中:
def add_music(self,files:tuple[str]) -> None:"""该函数用于将前台返回的文件路径存储到数据库中:param file:音乐文件的路径,默认是多个,元素类型为字符串:return: None"""# 编写sql语句sql = "insert into music_info(name,path) values(%s,%s)"# 遍历数据for f in files:print(f)# 根据路径获取歌曲名name = f[f.rfind("/")+1:f.rfind(".")]print(name)# 创建数据库链接对象db = DBUtil()# 准备参数args=(name,f)# 执行插入语句db.dml(sql,args)
接下来修改ui.py文件的内容,用于将tkinter.filedialog.askopenfilenames返回的歌曲路径(返回类型是元组,返回的是歌曲在本地的绝对路径)传入前面写的add_music函数中进行处理,而add_music又属于Music类,所以要先创建一个实例对象,再通过实例对象调用add_music方法:
def importMusic(self,event):# 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])# 创建服务对象ser = Music()# 调用增加音乐的功能(将前端的数据发送给后端处理)ser.add_music(filenames)
运行后的结果如下:
加入歌曲后db_music数据库下music_info表的数据如下:
完整ui.py文件如下:
import tkinter
from service import Music
import tkinter.filedialogclass Ui:def __init__(self):# 主窗口top = tkinter.Tk()# 创建按钮对象,第一个参数是父容器,text表示显示的内容b1 = tkinter.Button(top, text="播放")b2 = tkinter.Button(top, text="导入音乐")b3 = tkinter.Button(top, text="删除音乐")# 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)b1.grid(row=1,column=1,padx=10,pady=10)b2.grid(row=1,column=2,padx=10,pady=10)b3.grid(row=1,column=3,padx=10,pady=10)# 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)b2.bind("<Button-1>",self.importMusic)# 创建播放列表lisbox = tkinter.Listbox(top)# 设置播放列表位置,columnspan表示垮了多少列lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)# 进入消息循环top.mainloop()# 导入音乐的点击事件def importMusic(self,event):# 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])# 创建服务对象ser = Music()# 调用增加音乐的功能(将前端的数据发送给后端处理)ser.add_music(filenames)if __name__=="__main__":# 获取用户名和密码uname = input("请输入用户名:")password = input("请输入密码:")# 创建Music类的实例对象ser = Music()# 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)if ser.login(uname,password):Ui()else:print("用户名或密码错误!")
完整service.py文件如下:
from tools import DBUtilclass Music:def login(self, uname: str, password: str) -> bool:""":param uname:用户名:param password:密码:return: 登录成功返回True,登录失败返回False"""# 准备要执行的sql语句sql = "select * from user_info where uname=%s and password=%s"# 准备sql语句需要的参数args = (uname, password)# 创建工具对象(实际时获取数据库的链接对象和游标对象)db = DBUtil()# 利用游标对象调用对应的单条查询方法re = db.query_one(sql, args)# 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户if re:print("登录成功")return Trueelse:print("登录失败")return Falsedef add_music(self,files:tuple[str]) -> None:"""该函数用于将前台返回的文件路径存储到数据库中:param file:音乐文件的路径,默认是多个,元素类型为字符串:return: None"""# 编写sql语句sql = "insert into music_info(name,path) values(%s,%s)"# 遍历数据for f in files:print(f)# 根据路径获取歌曲名name = f[f.rfind("/")+1:f.rfind(".")]print(name)# 创建数据库链接对象db = DBUtil()# 准备参数args=(name,f)# 执行插入语句db.dml(sql,args)# 测试代码
if __name__ == "__main__":# 创建Music类的实例对象service = Music()# 利用实例对象调用实例方法re = service.login("muxikeqi", "123321")print(re)
7、实现音乐列表和用户绑定
概述:实现音乐列表和用户的绑定主要是为play_info表添加数据即可,play_info表包含了数据库id和用户id,契合用户和音乐的对应关系。
7.1、获取用户id
思路:为service.py文件下的Music类添加一个构造方法,构造方法用于放置一个user变量,用于保存用户id,默认为空。结合login函数中变量re是数据库进行查询后的返回的查询结果,通过判断re是否为空来判断用户是否登录。当用户不为空时(用户登录成功),我们将返回的结果re赋值给构造方法中的user变量,此时,user就拿到返回的用户信息,然后获取用户id在user_info表中对应位置的值就拿到了用户id。
def __init__(self):# 用户默认为空self. User = Nonedef login(self, uname: str, password: str) -> bool:""":param uname:用户名:param password:密码:return: 登录成功返回True,登录失败返回False"""# 准备要执行的sql语句sql = "select * from user_info where uname=%s and password=%s"# 准备sql语句需要的参数args = (uname, password)# 创建工具对象(实际时获取数据库的链接对象和游标对象)db = DBUtil()# 利用游标对象调用对应的单条查询方法re = db.query_one(sql, args)# 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户if re:print("登录成功")self.user=re# 查看内容是否包含u_id对应的内容# print(self.user)return Trueelse:print("登录失败")return False
7.2、获取音乐id
思路:在service.py文件中的有一个add_music函数,我们可以在修改music_info表的同时为play_info表添加数据,而add_music函数中通过db.dml(sql,args)对music_info表添加了数据,如果我们能让dml方法告诉我们它添加的id为多少那么获取音乐id的问题就解决了,因此这里可以直接将工具类中的dml函数重写一份,添加一个获取添加id的方法并返回,这里我为这个函数取名为dml_back_id。(写完本小节还是存在问题的,需要看下一小节)
工具类重写的dml_back_id函数如下:
# 重写上面的dml函数,增加返回id的操作def dml_back_id(self, sql, args):"""本函数用于封装Mysql的DML语句,用于实现数据的增删改"""# 进行DML语句操作时一定要注意报错导致无法正常关闭链接try:# 执行sql中的DML语句self.cursor.execute(sql, args)# 获取添加的idid = self.con.insert_id()# DML操作一定要通过链接对象提交事务self.con.commit()# 返回idreturn idexcept Exception as e:print("存在错误,错误信息如下:", e)# 回滚前先判断链接还是否存在if self.con:# 回滚到原状态self.con.rollback()# 使用try...except...finally...最重要的作用就是保证链接正常关闭finally:print("即将关闭链接")self.close()
service.py文件的add_music函数修改如下:
def add_music(self,files:tuple[str]) -> None:"""该函数用于将前台返回的文件路径存储到数据库中:param file:音乐文件的路径,默认是多个,元素类型为字符串:return: None"""# 编写sql语句sql = "insert into music_info(name,path) values(%s,%s)"# 遍历数据for f in files:print(f)# 根据路径获取歌曲名name = f[f.rfind("/")+1:f.rfind(".")]print(name)# 创建数据库链接对象db = DBUtil()# 准备参数args=(name,f)# 将音乐信息添加到music_info表中m_id = db.dml_back_id(sql,args)# 实现音乐与用户绑定musicBindId_sql = "insert into play_info(u_id,m_id) values(%s,%s)"args=(self.user[0],m_id)db.dml(musicBindId_sql,args)
7.3、问题解决
问题1:无法获取到用户id。
原因分析:用户是从前端文件进行登录的,在ui.py文件的测试内容中我们创建了一个实例对象,用于调用service.py文件中的login函数,判断用户能否登录成功,但登录成功后就进入了Ui类的构造方法,构造方法为导入音乐按钮添加了一个名为importMusic的点击事件,在importMusic函数中又创建了一个实例对象,用于调用service.py文件中的add_music方法,我们是通过第二个对象去获取用户id,但用户id保存到了第一个实例对象。
解决办法:将第二个实例对象删除,再用第一个实例对象调用add_music函数即可。
import tkinter
from service import Music
import tkinter.filedialogclass Ui:def __init__(self):# 主窗口top = tkinter.Tk()# 创建按钮对象,第一个参数是父容器,text表示显示的内容b1 = tkinter.Button(top, text="播放")b2 = tkinter.Button(top, text="导入音乐")b3 = tkinter.Button(top, text="删除音乐")# 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)b1.grid(row=1,column=1,padx=10,pady=10)b2.grid(row=1,column=2,padx=10,pady=10)b3.grid(row=1,column=3,padx=10,pady=10)# 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)b2.bind("<Button-1>",self.importMusic)# 创建播放列表lisbox = tkinter.Listbox(top)# 设置播放列表位置,columnspan表示垮了多少列lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)# 进入消息循环top.mainloop()# 导入音乐的点击事件def importMusic(self,event):# 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])# 创建服务对象(这里如果不干掉,绑定用户和音乐时就拿不到u_id,因为创建了两个实例对象)# ser = Music()# 调用增加音乐的功能(将前端的数据发送给后端处理)ser.add_music(filenames)if __name__=="__main__":# 获取用户名和密码uname = input("请输入用户名:")password = input("请输入密码:")# 创建Music类的实例对象ser = Music()# 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)if ser.login(uname,password):Ui()else:print("用户名或密码错误!")
问题2:报错说数据库已经关闭。
问题分析:在获取音乐id时,我们通过重构工具类中dml函数使其返回新加的id,但执行完sql语句并提交事务后就返回了数据,返回数据后就直接运行了finally中关闭数据库的语句。
解决办法:重新链接一下数据库即可。
def add_music(self,files:tuple[str]) -> None:"""该函数用于将前台返回的文件路径存储到数据库中:param file:音乐文件的路径,默认是多个,元素类型为字符串:return: None"""# 编写sql语句sql = "insert into music_info(name,path) values(%s,%s)"# 遍历数据for f in files:print(f)# 根据路径获取歌曲名name = f[f.rfind("/")+1:f.rfind(".")]print(name)# 创建数据库链接对象db = DBUtil()# 准备参数args=(name,f)# 将音乐信息添加到music_info表中m_id = db.dml_back_id(sql,args)# 上一句调用的函数中由于需要执行return语句,所以会直接执行finally语句中关闭数据库的操作,因此需要重新链接数据库db = DBUtil()# 实现音乐与用户绑定musicBindId_sql = "insert into play_info(u_id,m_id) values(%s,%s)"args=(self.user[0],m_id)db.dml(musicBindId_sql,args)
完整service.py文件内容如下:
from tools import DBUtilclass Music:def __init__(self):# 用户默认为空self.user = Nonedef login(self, uname: str, password: str) -> bool:""":param uname:用户名:param password:密码:return: 登录成功返回True,登录失败返回False"""# 准备要执行的sql语句sql = "select * from user_info where uname=%s and password=%s"# 准备sql语句需要的参数args = (uname, password)# 创建工具对象(实际时获取数据库的链接对象和游标对象)db = DBUtil()# 利用游标对象调用对应的单条查询方法re = db.query_one(sql, args)# 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户if re:print("登录成功")self.user=re# 查看内容是否包含u_id对应的内容print(self.user)print(self.user[0])return Trueelse:print("登录失败")return Falsedef add_music(self,files:tuple[str]) -> None:"""该函数用于将前台返回的文件路径存储到数据库中:param file:音乐文件的路径,默认是多个,元素类型为字符串:return: None"""# 编写sql语句sql = "insert into music_info(name,path) values(%s,%s)"# 遍历数据for f in files:print(f)# 根据路径获取歌曲名name = f[f.rfind("/")+1:f.rfind(".")]print(name)# 创建数据库链接对象db = DBUtil()# 准备参数args=(name,f)# 将音乐信息添加到music_info表中m_id = db.dml_back_id(sql,args)# 上一句调用的函数中由于需要执行return语句,所以会直接执行finally语句中关闭数据库的操作,因此需要重新链接数据库db = DBUtil()# 实现音乐与用户绑定musicBindId_sql = "insert into play_info(u_id,m_id) values(%s,%s)"args=(self.user[0],m_id)db.dml(musicBindId_sql,args)# 测试代码
if __name__ == "__main__":# 创建Music类的实例对象service = Music()# 利用实例对象调用实例方法re = service.login("muxikeqi", "123321")print(re)
完整ui.py文件内容如下:
import tkinter
from service import Music
import tkinter.filedialogclass Ui:def __init__(self):# 主窗口top = tkinter.Tk()# 创建按钮对象,第一个参数是父容器,text表示显示的内容b1 = tkinter.Button(top, text="播放")b2 = tkinter.Button(top, text="导入音乐")b3 = tkinter.Button(top, text="删除音乐")# 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)b1.grid(row=1,column=1,padx=10,pady=10)b2.grid(row=1,column=2,padx=10,pady=10)b3.grid(row=1,column=3,padx=10,pady=10)# 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)b2.bind("<Button-1>",self.importMusic)# 创建播放列表lisbox = tkinter.Listbox(top)# 设置播放列表位置,columnspan表示垮了多少列lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)# 进入消息循环top.mainloop()# 导入音乐的点击事件def importMusic(self,event):# 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])# 创建服务对象(这里如果不干掉,绑定用户和音乐时就拿不到u_id,因为创建了两个实例对象)# ser = Music()# 调用增加音乐的功能(将前端的数据发送给后端处理)ser.add_music(filenames)if __name__=="__main__":# 获取用户名和密码uname = input("请输入用户名:")password = input("请输入密码:")# 创建Music类的实例对象ser = Music()# 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)if ser.login(uname,password):ui=Ui()else:print("用户名或密码错误!")
运行结果如下:
运行后的play_info表数据如下:
8、实现加载播放列表
概述:为了后续顺利的完成功能开发,先通过navicat的查询窗口尝试写出一个查询语句,通过play_info表的u_id找出其对应的音乐名(即music_info表中m_id对应的name)(既然涉及到两个表之间不相关列的查询就可以考虑sql99标准下的左(右)外连接查询)。
SELECT name FROM play_info p LEFT JOIN music_info m ON p.m_id=m.id WHERE u_id=1;
运行结果如下:
接下来为后端的service.py文件添加一个函数用于查询用户对应的歌曲列表。
def find_user_music(self) -> list[str]:"""本函数用于查询特定用户id对应的音乐列表"""# 准备sql语句(前面已经准备好了)sql = "SELECT name FROM play_info p LEFT JOIN music_info m ON p.m_id=m.id WHERE u_id=%s;"# 创建工具类对象db = DBUtil();# 执行sql语句(这里使用和上一章同样的方法获取用户id)music_list = db.query_many(sql,self.user[0])# 将结果返回return music_list
然后参考菜鸟教程中关于Tkinter的教程,了解添加列表的玩法:
最后,为前端的ui.py文件调用find_user_music函数,只要有歌曲被添加或进入窗口都会显示该用户对应的歌曲列表。
import tkinter
from service import Music
import tkinter.filedialogclass Ui:def __init__(self):# 主窗口top = tkinter.Tk()# 创建按钮对象,第一个参数是父容器,text表示显示的内容b1 = tkinter.Button(top, text="播放")b2 = tkinter.Button(top, text="导入音乐")b3 = tkinter.Button(top, text="删除音乐")# 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)b1.grid(row=1,column=1,padx=10,pady=10)b2.grid(row=1,column=2,padx=10,pady=10)b3.grid(row=1,column=3,padx=10,pady=10)# 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)b2.bind("<Button-1>",self.importMusic)# 创建播放列表(为了让importMusic函数能够使用,所有为变量传入了对象self)self.lisbox = tkinter.Listbox(top)# 设置播放列表位置,columnspan表示垮了多少列self.lisbox.grid(row=2,column=0,columnspan=4,padx=10,pady=10)self.music_list()# 进入消息循环top.mainloop()# 导入音乐的点击事件def importMusic(self,event):# 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac"),("mgg",".mgg")])# 创建服务对象(这里如果不干掉,绑定用户和音乐时就拿不到u_id,因为创建了两个实例对象)# ser = Music()# 调用增加音乐的功能(将前端的数据发送给后端处理)ser.add_music(filenames)# 获取用户的音乐列表self.music_list()def music_list(self) -> list[str]:# 调用获取列表的函数m_lis = ser.find_user_music()print(m_lis)for m in m_lis:self.lisbox.insert(0, m[0])if __name__=="__main__":# 获取用户名和密码uname = input("请输入用户名:")password = input("请输入密码:")# 创建Music类的实例对象ser = Music()# 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)if ser.login(uname,password):ui=Ui()else:print("用户名或密码错误!")
运行后的窗口显示如下:
运行结果如下:
9、实现通过列表播放音乐
概述:本章就做两件事,首先确定用户点击的是列表中哪一首歌曲,其次,用户点击播放按钮后能播放对应的歌曲。
9.1、前端获取歌名
①、首先为播放按钮添加点击事件
b1.bind("<ButtonRelease-1>", self.play_music)
②、书写对应的点击事件
def play_music(self,event):# 获取当前列表中选中音乐的索引index = self.lisbox.curselection()# 根据索引索取音乐的名称music_name = self.lisbox.get(index)print(music_name)
运行程序后,点击列表中的任意歌曲再点击播放就能顺利的打印歌曲信息,此时,已经正确地拿到了音乐名。
9.2、后端逻辑实现
①、将获取的歌曲名传给后端service.py文件中play_music函数
def play_music(self,event):# 获取当前列表中选中音乐的索引index = self.lisbox.curselection()# 根据索引索取音乐的名称music_name = self.lisbox.get(index)# print(music_name)# 将音乐名称传递给服务对象ser.play_music(music_name)
②、实现play_music函数中的sql语句(这里采用左外连接,关联了music_info表和play_info表,关联的字段是m表的id和p表的m_id,条件同时限制p表中的用户名和m表的歌曲名)
select path from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s
③、补全play_music函数
def play_music(self,music_name:str) -> None:"""播放音乐:param music_name:音乐名称:return: None"""print("进入play_music函数")# 编写sqlsql = "select path from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s;"# 创建工具类(链接数据库)db = DBUtil()# 运行sql并将返回的结果保存到变量path中args=(music_name,self.user[0])path = db.query_one(sql,args)[0]print(path)print(len(path))# 调用播放器播放音乐(拷贝play.py文件的代码)# 初始化加载音乐的混合器pygame.mixer.init()# 加载音乐(路径可以是相对路径也可以是绝对路径)pygame.mixer.music.load(path)# 播放音乐pygame.mixer.music.play()
运行结果如下:
注意:Pygame不支持播放.mgg格式的音乐文件。
9.3、修改bug
问题描述:只要点击了导入音乐,就会将重新获取的列表添加到旧列表的下面。
为ui.py文件中的music_list函数清空原有列表m_lis
def music_list(self) -> list[str]:"""本函数用于获取音乐列表"""# 调用获取列表的函数m_lis = ser.find_user_music()# 清空列表self.lisbox.delete(0,tkinter.END)# 重新加载列表for m in m_lis:self.lisbox.insert(0, m[0])
10、实现删除音乐
①、为ui.py文件中的删除按钮添加点击事件
b3.bind("<ButtonRelease-1>", self.delete_music)
②、实现点击事件
def delete_music(self,event):"""本函数用于删除用户指定的音乐"""# 获取当前列表中选中音乐的索引index = self.lisbox.curselection()# 根据索引索取音乐的名称music_name = self.lisbox.get(index)# 调用删除功能ser.delete_music(music_name);# 重新加载播放列表self.music_list()
③、实现delete_music函数
def delete_music(self,music_name:str) -> None:# 编写SQLsql_query_m_id = "select m.id from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s;"sql_delete_music = "delete from music_info where id=%s"sql_delete_play = "delete from play_info where m_id=%s and u_id=%s"# 创建工具类(链接数据库)db = DBUtil()args = (music_name, self.user[0])# 运行sqlm_id = db.query_one(sql_query_m_id, args)[0]# 准备参数args2 = (m_id,self.user[0])DBUtil().dml(sql_delete_play,args2)# 注意:有外键约束的列,要先删除有外键关联列的数据,再删除其他数据DBUtil().dml(sql_delete_music,m_id)
运行结果如下:
附件:完整文件源码(需要自己创建数据库和表)
完整工具类tools.py文件如下:
import pymysqlclass DBUtil:"""工具类用于简化链接和关闭数据库的操作以及对数据的操作"""# 单独保存链接的参数,可以将其保存到特定文件中,直接调用文件获取也可config = {'host': "localhost",'user': "root",'passwd': "root",'db': "db_music",'charset': "utf8",'port': 3306}def __init__(self) -> None:"""构造函数用于获取链接和游标"""# **指字典对象self.con = pymysql.connect(**DBUtil.config)self.cursor = self.con.cursor()def close(self) -> None:"""该函数用于关闭链接和游标(关闭前需要判断是否存在)"""# 存在游标就关闭if self.cursor:self.cursor.close()# 存在链接就关闭if self.con:self.con.close()def dml(self, sql, args):"""本函数用于封装Mysql的DML语句,用于实现数据的增删改"""# 进行DML语句操作时一定要注意报错导致无法正常关闭链接try:# 执行sql中的DML语句self.cursor.execute(sql, args)# DML操作一定要通过链接对象提交事务self.con.commit()except Exception as e:print("存在错误,错误信息如下:", e)# 回滚前先判断链接还是否存在if self.con:# 回滚到原状态self.con.rollback()# 使用try...except...finally...最重要的作用就是保证链接正常关闭finally:print("即将关闭链接")self.close()# 重写上面的dml函数,增加返回id的操作def dml_back_id(self, sql, args):"""本函数用于封装Mysql的DML语句,用于实现数据的增删改"""# 进行DML语句操作时一定要注意报错导致无法正常关闭链接try:# 执行sql中的DML语句self.cursor.execute(sql, args)# 获取添加的idid = self.con.insert_id()print(id)# DML操作一定要通过链接对象提交事务self.con.commit()# 返回idreturn idexcept Exception as e:print("存在错误,错误信息如下:", e)# 回滚前先判断链接还是否存在if self.con:# 回滚到原状态self.con.rollback()# 使用try...except...finally...最重要的作用就是保证链接正常关闭finally:print("即将关闭链接")self.close()def query_one(self, sql, args):"""本函数用于查询单条数据"""try:self.cursor.execute(sql, args)re = self.cursor.fetchone()return reexcept Exception as e:print("存在错误,错误信息如下:", e)finally:print("即将关闭链接")self.close()def query_many(self, sql, args):"""本函数用于查询所有数据"""try:self.cursor.execute(sql,args)# 获取结果并返回数据return self.cursor.fetchall()except Exception as e:print("存在错误,错误信息如下:", e)finally:print("即将关闭链接")self.close()if __name__ == "__main__":# # 获取链接对象# db = DBUtil()# # 准备sql语句及其对应的参数# sql = "select * from user_info where uname=%s and password=%s;"# args =["muxikeqi","123321"]# # 运行sql语句并关闭链接# re = db.query_one(sql,args)# print(re)pass
完整play.py文件如下:
import pygame
import time
# 初始化加载音乐的混合器
pygame.mixer.init()
# 加载音乐(路径可以是相对路径也可以是绝对路径)
pygame.mixer.music.load(f".\music\c.flac")
# 播放音乐
pygame.mixer.music.play()
# 程序进入等待(不要立即关闭程序),单位为秒
time. Sleep(20)
完整ui.py文件内容如下:
# import tkinter
from tkinter import *
from service import Music
import tkinter.filedialogclass Ui:def __init__(self):# 主窗口top = tkinter.Tk()# top.withdraw()# 创建按钮对象,第一个参数是父容器,text表示显示的内容b1 = tkinter.Button(top, text="播放")b2 = tkinter.Button(top, text="导入音乐")b3 = tkinter.Button(top, text="删除音乐")# 设置按钮显示位置(row表示放在哪一行,column表示放在哪一列,pad表示距离边框的内边距,单位为像素)b1.grid(row=0,column=1,padx=10,pady=10)b2.grid(row=0,column=2,padx=10,pady=10)b3.grid(row=0,column=3,padx=10,pady=10)# 为导入音乐的按钮添加点击事件,bind方法的第一个参数是事件名称,第二个参数是点击事件(点击按钮后触发的函数)b2.bind("<ButtonRelease-1>",self.importMusic)# ButtonRelease表示点击并释放了(第一个参数写法固定,不要更改)b1.bind("<ButtonRelease-1>", self.play_music)b3.bind("<ButtonRelease-1>", self.delete_music)# 创建播放列表(为了让importMusic函数能够使用,所有为变量传入了对象self)self.lisbox = tkinter.Listbox(top)# 设置播放列表位置,columnspan表示垮了多少列self.lisbox.grid(row=1,column=0,columnspan=4,padx=5,pady=5)self.music_list()# 进入消息循环top.mainloop()# 导入音乐的点击事件def importMusic(self,event):# 弹出选择框(返回的结果是元组)(一定要通过filetypes限制文件类型,否则什么文件都能加入进来)filenames = tkinter.filedialog.askopenfilenames(filetypes=[("mp3",".mp3"),("flac",".flac")])# 创建服务对象(这里如果不干掉,绑定用户和音乐时就拿不到u_id,因为创建了两个实例对象)# ser = Music()# 调用增加音乐的功能(将前端的数据发送给后端处理)ser.add_music(filenames)# 获取用户的音乐列表self.music_list()def music_list(self) -> list[str]:"""本函数用于获取音乐列表"""# 调用获取列表的函数m_lis = ser.find_user_music()# 清空列表self.lisbox.delete(0,tkinter.END)# 重新加载列表for m in m_lis:self.lisbox.insert(0, m[0])def play_music(self,event):# 获取当前列表中选中音乐的索引index = self.lisbox.curselection()# 根据索引索取音乐的名称music_name = self.lisbox.get(index)# 将音乐名称传递给服务对象ser.play_music(music_name)def delete_music(self,event):"""本函数用于删除用户指定的音乐"""# 获取当前列表中选中音乐的索引index = self.lisbox.curselection()# 根据索引索取音乐的名称music_name = self.lisbox.get(index)# 调用删除功能ser.delete_music(music_name);# 重新加载播放列表self.music_list()if __name__=="__main__":# 获取用户名和密码uname = input("请输入用户名:")password = input("请输入密码:")# 创建Music类的实例对象ser = Music()# 利用实例对象调用实例方法(由于会返回布尔值,所以直接进行判断)if ser.login(uname,password):ui=Ui()else:print("用户名或密码错误!")
完整service.py文件如下:
from tools import DBUtil
import pygameclass Music:def __init__(self):# 用户默认为空self.user = Nonedef login(self, uname: str, password: str) -> bool:""":param uname:用户名:param password:密码:return: 登录成功返回True,登录失败返回False"""# 准备要执行的sql语句sql = "select * from user_info where uname=%s and password=%s"# 准备sql语句需要的参数args = (uname, password)# 创建工具对象(实际时获取数据库的链接对象和游标对象)db = DBUtil()# 利用游标对象调用对应的单条查询方法re = db.query_one(sql, args)# 由于query_one函数运行成功后是有返回值的,可以通过返回值判断是否查询成功,进而判断是否有该用户if re:print("登录成功")self.user=re# 查看内容是否包含u_id对应的内容# print(self.user)# print(self.user[0])return Trueelse:print("登录失败")return Falsedef add_music(self,files:tuple[str]) -> None:"""该函数用于将前台返回的文件路径存储到数据库中:param file:音乐文件的路径,默认是多个,元素类型为字符串:return: None"""# 编写sql语句sql = "insert into music_info(name,path) values(%s,%s)"# 遍历数据for f in files:# 根据路径获取歌曲名name = f[f.rfind("/")+1:f.rfind(".")]# 创建数据库链接对象db = DBUtil()# 准备参数args=(name,f)# 将音乐信息添加到music_info表中m_id = db.dml_back_id(sql,args)# 上一句调用的函数中由于需要执行return语句,所以会直接执行finally语句中关闭数据库的操作,因此需要重新链接数据库db = DBUtil()# 实现音乐与用户绑定musicBindId_sql = "insert into play_info(u_id,m_id) values(%s,%s)"args=(self.user[0],m_id)db.dml(musicBindId_sql,args)def find_user_music(self) -> list[str]:"""本函数用于查询特定用户id对应的音乐列表"""# 准备sql语句(前面已经准备好了)sql = "SELECT name FROM play_info p LEFT JOIN music_info m ON p.m_id=m.id WHERE u_id=%s;"# 创建工具类对象db = DBUtil();# 执行sql语句(这里使用和上一章同样的方法获取用户id)music_list = db.query_many(sql,self.user[0])# 将结果返回return music_listdef play_music(self,music_name:str) -> None:"""播放音乐:param music_name:音乐名称:return: None"""# 编写sqlsql = "select path from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s;"# 创建工具类(链接数据库)db = DBUtil()args=(music_name,self.user[0])# 运行sql并将返回的结果保存到变量path中path = db.query_one(sql,args)[0]# 调用播放器播放音乐(拷贝play.py文件的代码)# 初始化加载音乐的混合器pygame.mixer.init()# 加载音乐(路径可以是相对路径也可以是绝对路径)pygame.mixer.music.load(path)# 播放音乐pygame.mixer.music.play()def delete_music(self,music_name:str) -> None:# 编写SQLsql_query_m_id = "select m.id from music_info m left join play_info p on m.id=p.m_id where m.name=%s and p.u_id=%s;"sql_delete_music = "delete from music_info where id=%s"sql_delete_play = "delete from play_info where m_id=%s and u_id=%s"# 创建工具类(链接数据库)db = DBUtil()args = (music_name, self.user[0])# 运行sqlm_id = db.query_one(sql_query_m_id, args)[0]# 准备参数args2 = (m_id,self.user[0])DBUtil().dml(sql_delete_play,args2)# 注意:有外键约束的列,要先删除有外键关联列的数据,再删除其他数据DBUtil().dml(sql_delete_music,m_id)# 测试代码
if __name__ == "__main__":# 创建Music类的实例对象service = Music()# 利用实例对象调用实例方法re = service.login("muxikeqi", "123321")print(re)
相关文章:

Python操作MySQL实战
文章导读 本文用于巩固Pymysql操作MySQL与MySQL操作的知识点,实现一个简易的音乐播放器,拟实现的功能包括:用户登录,窗口显示,加载本地音乐,加入和删除播放列表,播放音乐。 点击此处获取参考源…...

【Linux系统】进程间通信
本篇博客整理了进程间通信的方式管道、 system V IPC的原理,结合大量的系统调用接口,和代码示例,旨在让读者透过进程间通信去体会操作系统的设计思想和管理手段。 目录 一、进程间通信 二、管道 1.匿名管道 1.1-通信原理 1.2-系统调用 …...

北大国际医院腹膜后纤维化课题组 多学科协作开辟治疗新径
腹膜后纤维化(Retroperitoneal Fibrosis,简称RPF)是一种罕见的自身免疫性疾病,其核心特征是纤维组织的异常增生与硬化。这种疾病主要影响肾脏下方的腹主动脉和髂动脉区域,增生的纤维组织会逐渐压迫周围的输尿管和下腔静脉,从而导致一系列并发症,包括主动脉瘤、肾功能衰竭等,甚至…...

面试数据库八股文十问十答第七期
面试数据库八股文十问十答第七期 作者:程序员小白条,个人博客 相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新! ⭐点赞⭐收藏⭐不迷路!⭐ 1)索引是越多越好吗ÿ…...

【C++题解】1133. 字符串的反码
问题:1133. 字符串的反码 类型:字符串 题目描述: 一个二进制数,将其每一位取反,称之为这个数的反码。下面我们定义一个字符的反码。 如果这是一个小写字符,则它和字符 a 的距离与它的反码和字符 z 的距离…...

【Python编程实战】基于Python语言实现学生信息管理系统
🎩 欢迎来到技术探索的奇幻世界👨💻 📜 个人主页:一伦明悦-CSDN博客 ✍🏻 作者简介: C软件开发、Python机器学习爱好者 🗣️ 互动与支持:💬评论 &…...

AI网络爬虫:批量爬取电视猫上面的《庆余年》分集剧情
电视猫上面有《庆余年》分集剧情,如何批量爬取下来呢? 先找到每集的链接地址,都在这个class"epipage clear"的div标签里面的li标签下面的a标签里面: <a href"/drama/Yy0wHDA/episode">1</a> 这个…...

md5强弱碰撞
一,类型。 1.弱比较 php中的""和""在进行比较时,数字和字符串比较或者涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行。按照此理,我们可以上传md5编码后是0e的字符串,在…...

【Docker故障处理篇】运行容器报错“docker: failed to register layer...file exists.”解决方法
【Docker故障处理篇】运行容器报错“docker: failed to register layer...file exists.” 一、Docker环境介绍2.1 本次环境介绍2.2 本次实践介绍二、故障现象2.1 运行容器消失2.2 重新运行容器报错三、故障分析四、故障处理4.1 停止 Docker 服务:4.2 备份重要数据4.3 清理冲突…...

小红书-社区搜索部 (NLP、CV算法实习生) 一面面经
😄 整个流程按如下问题展开,用时60min左右面试官人挺好,前半部分问问题,后半部分coding一道题。 各位有什么问题可以直接评论区留言,24小时内必回信息,放心~ 文章目录 1、自我介绍2、介绍下项目:微信-多模态小视频分类2.1、看你用了cross-att来融合多模态信息,cross…...

解读makefile中的.PHONY
在 Makefile 中,.PHONY 是一个特殊的目标,用于声明伪目标(phony target)。伪目标是指并不代表实际构建结果的目标,而是用来触发特定动作或命令的标识。通常情况下,.PHONY 会被用来声明一组需要执行的动作&a…...

linux配置防火墙端口
配置防火墙,添加或删除端口,需要有root权限。 防火墙常用命令如下: 1.查看防火墙状态: systemctl status firewalld active(running):开启状态,正在运行中 inactive(dead):关闭状态ÿ…...

sklearn线性回归--岭回归
sklearn线性回归--岭回归 岭回归也是一种用于回归的线性模型,因此它的预测公式与普通最小二乘法相同。但在岭回归中,对系数(w)的选择不仅要在训练数据上得到好的预测结果,而且还要拟合附加约束,使系数尽量小…...

三十一、openlayers官网示例Draw Features解析——在地图上自定义绘制点、线、多边形、圆形并获取图形数据
官网demo地址: Draw Features 先初始化地图,准备一个空的矢量图层,用于显示绘制的图形。 initLayers() {const raster new TileLayer({source: new XYZ({url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/…...

医疗科技:UWB模块为智能医疗设备带来的变革
随着医疗科技的不断发展和人们健康意识的提高,智能医疗设备的应用越来越广泛。超宽带(UWB)技术作为一种新兴的定位技术,正在引领着智能医疗设备的变革。UWB模块作为UWB技术的核心组成部分,在智能医疗设备中发挥着越来越…...

Java面试题大全(从基础到框架,中间件,持续更新~~~)
从Java基础到数据库,Spring,MyBatis,消息中间件,微服务解决全部Java面试过程中的问题。(持续更新~~) Java基础 2024最新Java面试题——java基础 MySQL基础 mysql基础知识——适合不太熟悉数据库知识的小…...

零知识证明在隐私保护和身份验证中的应用
PrimiHub一款由密码学专家团队打造的开源隐私计算平台,专注于分享数据安全、密码学、联邦学习、同态加密等隐私计算领域的技术和内容。 隐私保护和身份验证是现代社会中的关键问题,尤其是在数字化时代。零知识证明(Zero-Knowledge Proofs&…...

15.微信小程序之async-validator 基本使用
async-validator是一个基于 JavaScript 的表单验证库,支持异步验证规则和自定义验证规则 主流的 UI 组件库 Ant-design 和 Element中的表单验证都是基于 async-validator 使用 async-validator 可以方便地构建表单验证逻辑,使得错误提示信息更加友好和…...

元宇宙vr科普馆场景制作引领行业潮流
在这个数字化高速发展的时代,北京3D元宇宙场景在线制作以其独特的优势,成为了行业内的创新引领者。它能够快速完成空间设计,根据您的个性化需求,轻松设置布局、灯光、音效以及互动元素等,为您打造出一个更加真实、丰富…...

kotlin基础之高阶函数
Kotlin中的高阶函数、内联函数以及noinline和crossinline关键字是函数式编程中的重要概念。下面我将逐一解释这些概念的定义、实现原理、使用场景以及noinline和crossinline关键字的具体用法。 高阶函数 定义:高阶函数是接受一个或多个函数作为参数,或…...

【Python音视频技术】用moviepy实现图文成片功能
今天上班的时候看到有人群里问 图文成片怎么实现。 临时给我提供一点写作的灵感,趁着下班写一篇。这里用到 python的moviepy库, 之前文章介绍过。 大体思路:假定有4张图片,每张图片将在视频中展示2秒钟,并且图片会按照…...

【Linux】权限的理解之权限掩码(umask)
目录 前言 一、利用八进制数值表示文件或目录的权限属性 二、系统默认的权限掩码和权限掩码的作用原理 三、分析权限掩码改变文件或目录的权限属性 前言 权限掩码是由4个数字组合而成的,默认的第一位数字是0;后三位数字分别由八进制位数字组成。权限…...

UVa1466/LA4849 String Phone
UVa1466/LA4849 String Phone 题目链接题意分析AC 代码 题目链接 本题是2010年icpc亚洲区域赛大田赛区的G题 题意 平面网格上有n(n≤3000)个单元格,各代表一个重要的建筑物。为了保证建筑物的安全,警察署给每个建筑物派了一名警察…...

使用Word表格数据快速创建图表
实例需求:Word的表格如下所示,标题行有合并单元格。 现在需要根据上述表格数据,在Word中创建如下柱图。如果数据在Excel之中,那么创建这个图并不复杂,但是Word中就没用那么简单了,虽然Word中可以插入图表&a…...

JAVA面试题大全(十三)
1、Mybatis 中 #{}和 ${}的区别是什么? 在 MyBatis 中,#{} 和 ${} 是两种用于参数绑定的方式,它们之间的主要区别在于数据处理的方式和 SQL 注入的风险。 #{}:预编译处理 #{} 用于预编译处理,MyBatis 会为其生成 Prep…...

搜维尔科技:第九届元宇宙数字人设计大赛入围作品名单
随着第九届元宇宙数字人设计大赛渐近尾声,各院校提交的数字人作品已陆续完成评分统计汇总工作!现将入围名单公布,请入围团队尽可能到场参加大赛颁奖典礼,具体获奖名次将在颁奖典礼中现场公布! 颁奖典礼时间、地点&…...

SMB工具横向移动
一. SMB工具介绍和使用 1.介绍 2013年的Defcon上,就引入了smbexec,后续 smbexec 被 Impacket 进一步完善了。在Impacket中支持明文认证,NTLM认证,Aeskey认证等方式! 2. 使用方法 命令: smbexec.exe 用户…...

cesuim
new Cesium.Color(255,255,0,1), //颜色 Math.PI/2color: Cesium.Color.fromCssColorString("#f40"), //16进制颜色初始化地球 import * as Cesium from "cesium";import { onMounted } from "vue"; onMounted(() > {Cesium.Ion.defaultAcc…...

2023、2024国赛web复现wp
2023 Unzip 类型:任意文件上传漏洞 主要知识点:软链接 随便上传一个一句话木马文件,得到一串php代码 根据代码上传zip文件发现进入后还是此页面 代码审计: <?php error_reporting(0); highlight_file(__FILE__);$finfo fin…...

day34 贪心算法 455.分发饼干 376. 摆动序列
贪心算法理论基础 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 贪心一般解题步骤(贪心无套路): 将问题分解为若干个子问题找出适合的贪心策略求解每一个子问题的最优解将局部最优解堆叠成全局最优解 455.分发饼干 …...