uniapp使用本地数据库sqlite,以及文件下载并保存到设备本地

news/2025/2/26 20:15:10/文章来源:https://www.cnblogs.com/youantianqin/p/18739500

一、建立SQL.js,内容如下:

class SQL {

constructor(plus) {
// 数据库名称一个软件只需要一个库这里写死
this.name = 'sqlite_mine_sql';
this.plus = plus;
// 存储路径
this.path = `_doc/sqlite_mine.db`;
}

initDatabase() {
return new Promise((resolve, reject) => {
const that = this;
console.log('数据表初始化');
// **第一步:确保数据库已打开**
plus.sqlite.openDatabase({
name: that.name,
path: this.path,
success() {
console.log("数据库打开成功,开始检查表");

// **第二步:查询 media 表是否存在**
let checkMediaSql =
`SELECT name FROM sqlite_master WHERE type='table' AND name='media'`;

plus.sqlite.selectSql({
name: that.name,
sql: checkMediaSql,
success(data) {
console.log("查询表结果:", JSON.stringify(data));

if (data.length === 0) {
console.log("media 表不存在,创建表,设置url为唯一索引");

const createMediaSql = `
CREATE TABLE IF NOT EXISTS media (
id INTEGER PRIMARY KEY AUTOINCREMENT,
type TEXT,
url TEXT UNIQUE,
localUrl TEXT,
mid TEXT
)`;

plus.sqlite.executeSql({
name: that.name,
sql: createMediaSql,
success() {
console.log("media 表创建成功");
resolve({
message: "表创建成功"
});
},
fail(e) {
console.error("创建 media 表失败:", JSON
.stringify(e));
reject({
message: "创建表失败",
error: e
});
}
});
} else {
console.log("media 表已存在");
resolve({
message: "表已存在"
});
}
},
fail(e) {
console.error("查询表失败:", JSON.stringify(e));
reject({
message: "查询表失败",
error: e
});
}
});
},
fail(e) {
console.error("数据库打开失败:", JSON.stringify(e));
reject({
message: "数据库打开失败",
error: e
});
}
});
});
}

 

// 连接数据库
openDB() {
return new Promise((resolve, reject) => {
if (this.isOpen()) {
return resolve();
}
this.initDatabase();
});
}

// 判断数据库是否打开
isOpen() {
return this.plus.sqlite.isOpenDatabase({
name: this.name,
path: this.path
});
}

// 关闭数据库
closeDB() {
this.plus.sqlite.closeDatabase({
name: this.name,
success(e) {
console.log('closeDatabase success!');
},
fail(e) {
console.log('closeDatabase failed: ' + JSON.stringify(e));
}
});
}

// 执行sql语句
//handleType类型 dbname数据表 options条件 data修改时操作的数据 sort查询时排序 page查询时分页数据
async handleSQL(handleType, dbname, options, data = {}, sort = 'id asc', page = {}, isClose = false) {
await this.openDB();
// await this.initDatabase();
switch (handleType) {
case 'insert':
return this.insertSQL(dbname, options, isClose);
case 'delete':
return this.deleteSQL(dbname, options, isClose);
case 'select':
return this.selectSQL(dbname, options, sort, page, isClose);
case 'update':
return this.updateSQL(dbname, data, options, isClose);
case 'find':
return this.findSQL(dbname, options, isClose);
default:
throw new Error('没有这个操作!!!');
}
}

// 插入sql语句
insertSQL(dbname, options, isClose) {
const that = this;
return new Promise((resolve, reject) => {
if (!options || Object.keys(options).length === 0) {
console.error("insertSQL 失败:options 不能为空");
return reject("插入数据不能为空");
}

const keys = Object.keys(options).join(', '); // "type, url, localUrl"
const valuesStr = Object.values(options).map(val => `'${val}'`).join(
', '); // "'image', 'http://...', '_doc/...'"

const sql = `INSERT INTO ${dbname} (${keys}) VALUES (${valuesStr});`;

// console.log('执行插入 SQL:', sql);
that.plus.sqlite.executeSql({
name: that.name,
sql: sql,
success() {
console.log('insertSQL success');

// 查询刚插入的数据
that.plus.sqlite.selectSql({
name: that.name,
sql: "SELECT last_insert_rowid() AS id;",
success(data) {
// console.log('最后插入的 ID:', data[0].id);
isClose && that.closeDB();
resolve(data[0].id);
},
fail(e) {
console.log('查询 last_insert_rowid 失败:', JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
},
fail(e) {
console.log('insertSQL failed:', JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
});
}


// 删除sql语句
deleteSQL(dbname, options, isClose) {
return new Promise((resolve, reject) => {
const that = that || this;
if (!options || Object.keys(options).length === 0) {
console.error("deleteSQL 失败:options 不能为空");
return reject("删除条件不能为空");
}

// 构造 WHERE 条件
let whereClause = " WHERE " + Object.keys(options)
.map(key => {
let value = options[key];
// 判断是否是对象(用于大于、小于等特殊情况)
if (typeof value === "object" && value !== null) {
let operator = Object.keys(value)[0]; // 取出 >、<、>=、<=
let val = value[operator]; // 取出具体值
return `${key} ${operator} '${val}'`;
} else {
return `${key} = '${value}'`;
}
})
.join(" AND "); // 用 AND 连接多个条件

// 生成完整的 SQL 语句
const sql = `DELETE FROM ${dbname} ${whereClause};`;

console.log("执行 SQL:", sql); // 调试 SQL 语句

that.plus.sqlite.executeSql({
name: that.name,
sql:sql,
success(data) {
console.log('deleteSQL success: ' + JSON.stringify(data));
isClose && that.closeDB();
resolve(data);
},
fail(e) {
console.log('deleteSQL failed: ' + JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
});
}

// 查询sql语句 options参数为是否分页
selectSQL(dbname, options, sort, page, isClose) {
return new Promise((resolve, reject) => {
const that = that || this;

if (!options || Object.keys(options).length === 0) {
console.error("selectSQL 失败:options 不能为空");
return reject("查询条件不能为空");
}

// 构造 WHERE 条件
let whereClause = " WHERE " + Object.keys(options)
.map(key => {
let value = options[key];
// 判断是否是对象(用于大于、小于等特殊情况)
if (typeof value === "object" && value !== null) {
let operator = Object.keys(value)[0]; // 取出 >、<、>=、<=
let val = value[operator]; // 取出具体值
return `${key} ${operator} '${val}'`;
} else {
return `${key} = '${value}'`;
}
})
.join(" AND "); // 用 AND 连接多个条件

// 生成完整的 SQL 语句
const sql = `SELECT * FROM ${dbname} ${whereClause};`;

that.plus.sqlite.selectSql({
name: that.name,
sql:sql,
success(data) {
console.log('selectSQL success: ' + JSON.stringify(data));
if (page.hasOwnProperty('pageNum') && page.hasOwnProperty('pageSize')) {
let {
pageNum,
pageSize
} = page;
let total = data.length;
let page = Math.ceil(total / pageSize);
let req = {
pageNum,
pageSize,
list: [],
total
};
let startIndex = (pageNum - 1) * pageSize;
if (pageNum < page) {
req.list = data.slice(startIndex, startIndex + pageSize);
return resolve(req);
}
} else {
resolve(data);
}
isClose && that.closeDB();
},
fail(e) {
console.log('selectSQL failed: ' + JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});

});
}

//修改sql语句
updateSQL(dbname, data, options, isClose) {
const that = this;
return new Promise((resolve, reject) => {

if (!data || Object.keys(data).length === 0) {
console.error("updateSQL 失败:更新数据不能为空");
return reject("更新数据不能为空");
}
if (!options || Object.keys(options).length === 0) {
console.error("updateSQL 失败:条件不能为空");
return reject("更新条件不能为空");
}

// 构造 SET 语句
let setClause = Object.keys(data)
.map(key => `${key} = '${data[key]}'`)
.join(", ");

// 构造 WHERE 条件
let whereClause = " WHERE " + Object.keys(options)
.map(key => {
let value = options[key];
if (typeof value === "object" && value !== null) {
let operator = Object.keys(value)[0]; // 取出 >、<、>=、<=
let val = value[operator]; // 取出具体值
return `${key} ${operator} '${val}'`;
} else {
return `${key} = '${value}'`;
}
})
.join(" AND ");

// 生成完整的 SQL 语句
const sql = `UPDATE ${dbname} SET ${setClause} ${whereClause};`;

// console.log("执行 SQL:", sql); // 调试 SQL 语句

that.plus.sqlite.executeSql({
name: that.name,
sql:sql,
success(data) {
console.log('updateSQL success: ' + JSON.stringify(data));
isClose && that.closeDB();
resolve(data);
},
fail(e) {
console.log('updateSQL failed: ' + JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
});
}

// 查询单条数据的 SQL 语句
findSQL(dbname, options, isClose) {
return new Promise((resolve, reject) => {
const that = that || this;

if (!options || Object.keys(options).length === 0) {
console.error("queryOneSQL 失败:options 不能为空");
return reject("查询条件不能为空");
}

// 构造 WHERE 条件
let whereClause = " WHERE " + Object.keys(options)
.map(key => {
let value = options[key];
// 判断是否是对象(用于大于、小于等特殊情况)
if (typeof value === "object" && value !== null) {
let operator = Object.keys(value)[0]; // 取出 >、<、>=、<=
let val = value[operator]; // 取出具体值
return `${key} ${operator} '${val}'`;
} else {
return `${key} = '${value}'`;
}
})
.join(" AND "); // 用 AND 连接多个条件

// 生成完整的 SQL 语句
const sql = `SELECT * FROM ${dbname} ${whereClause} LIMIT 1;`;

// console.log("执行 SQL:", sql); // 调试 SQL 语句

that.plus.sqlite.selectSql({
name: that.name,
sql:sql,
success(data) {
// console.log('findSQL success: ' + JSON.stringify(data));
isClose && that.closeDB();
// 只返回第一条数据
resolve(data.length > 0 ? data[0] : null);
},
fail(e) {
console.log('findSQL failed: ' + JSON.stringify(e));
isClose && that.closeDB();
reject(e);
}
});
});
}
//检测文件是否存在本地
// checkFileExists(filePath,url='') {
// plus.io.resolveLocalFileSystemURL(filePath,
// function(entry) {
// console.log("文件存在: " + filePath);
// },
// function(error) {
// console.log("文件不存在或路径错误,需要重新下载保存到本地: " + filePath);
// //下载保存逻辑...
// }
// );
// }

}

export default new SQL(plus);

 

二、引入方式:在main.js引入

// #ifdef APP-PLUS
import SQL from './library/SQL.js'; // 引入 SQL 类
Vue.prototype.$sql = SQL; // 挂载到 Vue 全局
// #endif

 

//文件缓存
Vue.prototype.file_cache = async function(image_url,type='image',mid='') {

// #ifndef APP-PLUS
if (image_url == undefined) return false;

if (image_url.indexOf('http') <= -1) image_url = store.getters.get_weburl.imgUri + image_url;

return image_url;
// #endif


// #ifdef APP-PLUS
if (image_url == undefined) return false;

if (image_url.indexOf('http') <= -1) image_url = store.getters.get_weburl.imgUri + image_url;
// return '_doc/uniapp_save/17404810011980.jpg';
try {
let res = await this.$sql.handleSQL('find', 'media', {
type: type,
url: image_url
});
if (res) {
image_url = res.localUrl; // ✅ 查询到本地缓存,返回本地路径
} else {
// 没查询到,需要下载并缓存
try {
// 先返回原始 URL,不等待下载完成
(async () => {
try {
let localPath = await action.localSaveFileHttp(type, mid, image_url);

// 下载完成后,更新数据库
let insertId = await this.$sql.handleSQL('insert', 'media', {
type: type,
url: image_url,
mid: mid,
localUrl: localPath
});
// console.log("文件下载并插入数据库成功 ID:", insertId);
} catch (error) {
// console.error("后台文件下载失败:", error);
}
})();
// console.log('立即返回',image_url)
return image_url; // 立即返回原始 URL
} catch (error) {
return image_url; // 发生异常,依然返回原始 URL
}

}
return image_url;
} catch (error) {
return image_url; // ❌ 查询数据库失败,返回原始 URL
}
// #endif

}

 

二、(2)action的方法:

// 服务器下载到本地
async localSaveFileHttp(type, mid, url) {
return new Promise((resolve, reject) => {
uni.downloadFile({
url: url, // 你的音频文件或其他文件的 HTTPS 链接
success: (downloadRes) => {
if (downloadRes.statusCode === 200) {
// 下载成功,保存文件
let localPath = this.localSaveFile(type, mid, downloadRes.tempFilePath, url);
resolve(localPath); // ✅ 返回最终的本地路径
} else {
// console.error('文件下载失败:', downloadRes);
reject(new Error('下载失败,状态码:' + downloadRes.statusCode));
}
},
fail: (error) => {
// console.error('下载文件失败:', error);
reject(url);
}
});
});
}

// 文件保存本地类型type 唯一标识mid,url远程路径
async localSaveFile(type, mid, tempFilePath, url = '') {
return new Promise((resolve, reject) => {
uni.saveFile({
tempFilePath: tempFilePath,
success: (saveRes) => {
let savedFilePath = saveRes.savedFilePath; // 获取本地存储路径
// console.log('文件保存成功:', savedFilePath);
resolve(savedFilePath); // ✅ 正确返回保存后的本地路径
},
fail: (error) => {
console.error('保存失败:', error);
reject(error);
}
});
});
}

 

三、使用方式:

//替换视频缩略图为本地图片
this.vedioImgSrc = await this.file_cache(url,'vedio');

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

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

相关文章

纯离线部署本地知识库LLM大模型

纯离线部署本地知识库LLM大模型 一、下载离线大模型下载的网址:https://hf-mirror.com/deepseek qwen 相关的模型,只建议使用1.5B的,GGUF后缀的模型 推荐下载llama相关模型,同样是GGUF后缀的,自己笔记本电脑推荐下载8B的 二、下载大模型管理平台 LM Studio下载网址:https…

mailto链接

本文主要内容转载自Haorooms!好用的mailto网站话不多说直接上正菜! 大佬dawsbot提供的工具mailto.vercel.app前言 今天看到老外写的一篇关于mailto: HTML e-mail 的文章,感觉很新奇,以前从来没有这么用过,用email的时候,最多用过mailto,但是其中穿链接参数,还是第一次看…

二次开发(第一周作业)

(1) 来源 C++ 大作业 超市收银系统 - shugen - 博客园 该文章介绍了一个软件的实现过程,并提供了相关代码。通过对该软件的分析对其进行了改进和二次开发。 (2) 运行环境+运行结果的截图(伸缩代码附上) 操作系统:Windows 11 开发工具:Dev-c++ 编程语言:C++ 运行结果截…

iconfont本地引入

本地引入iconfont的好处 Butterfly主题自带的Font Awesome图标库免费版里有好多图标没有,而阿里巴巴的开源图标iconfont里的图标非常丰富,所以可以同时引入一下iconfont图标作为Font Awesome图标库的补充。 考虑到在线引入的icon图标大小都是16x16的,而Font Awesome图标一般…

powershell-alias配置方案

最近实在被git命令和poetry命令搞烦了,每次都要输入好长的命令,并且都差不太多,所以就搜索了怎么配置alias,下面是我的配置过程,主要资料来自[1]。配置 因为我用的是Windows Terminal,主要使用的Powershell环境,所以一下教程主要是以Powershell为例,配置的Alias主要是关…

leetcode hot 13

解题思路:本题思路主要是前缀和思想,涉及到子集和问题,前缀和思想有效,两个前缀和的差就等于对应一个子集和。本题可以用哈希表的方式记录每个前缀和的值,核心依靠k = pre[j]-pre[i]转化成pre[j]-k=pre[i],计算pre[i]这个值出现的个数加到res中,最后返回。 class Solutio…

redis - [10] 持久化

redis是一个内存数据库,断电即失。需要持久化到磁盘中。 001 || RDB 在执行的时间间隔内将内存中的数据集快照写入到磁盘(快照),恢复时是将快照文件直接读到内存中。 Redis会单独创建(fork)一个子进程进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了…

小红书独立开发大赛:让你的宝藏应用被更多人看到

无论你是业余在做一款 passion project 的 builder,还是试图 bootstrapping 自己造血的小团队。小红书发起的首届独立开发大赛都值得你关注。最近越来越多的社区开发者说,他们会选择在小红书冷启动自己的项目,因为这里能获取到友善的初期反馈和精准的早期用户。这些反馈和用…

博客作业:软件缺陷分析与二次开发实践(图书管理系统)

(1)来源 本次分析的代码来源于网络上的一个C++书籍购买系统项目。该项目模拟了不同用户类型(如会员、贵宾、学生等)购买书籍时的折扣计算和购买记录保存功能。原始代码虽能运行,但存在一些设计缺陷和潜在问题。 (2)运行环境+运行结果截图 运行环境: 环境:Windows 11 +…

博客添加看板娘

{% note info flat %} 本文转载自偷掉月亮的阿硕,本博客看板娘基于该教程搭建。 文章作者: 偷掉月亮的阿硕 文章链接: https://moonshuo.cn/posts/16544.html {% endnote %}

预祝2025省选嗨翻天

预祝2025省选嗨翻天\(T1\) A. 单峰序列 \(8pts\)部分分\(8pts\) :枚举每个数在单峰序列的左边还是右边,求次数做法同 luogu P3531 [POI 2012] LIT-Letters 。点击查看代码 int a[500010],b[500010],c[500010],ans[500010],id; vector<int>l,r; struct BIT {int c[50001…

配置github图床+picgo-core上传+jsdelivr

GitHub图床GitHub图床部分参考自教程Github图床+PicGo+JsDelivr+imgbot+automerge-action.imgbot图片压缩图片压缩部分参考自教程Github图床+PicGo+JsDelivr+imgbot+automerge-action.automerge-action最新版地址https://github.com/marketplace/actions/merge-pull-requests-a…