express处理图片文件

news/2024/12/18 21:34:47/

express处理图片文件

    • 整体内容
    • 以下为分步解释
      • 先导入
      • 在路由中使用它
      • 处理路径
      • 数据库操作
    • 测试

整体内容

介绍处理多个图片文件的方法
前端使用uniapp的api,后端使用express框架,数据库使用mysql

首先来看前端内容,使用uniapp上传文件api,会向后端传输一个formdata类型的数据,正常node.js是处理不了的

// 调用上传图片接口
uni.chooseImage({// 上传成功回调success: chooseImageRes => {// console.log(chooseImageRes);// 包括tempFilePaths(这是是所选所有图片地址的路径),tempFiles(这个是所选所有图片的地址对象)const tempFilePaths = chooseImageRes.tempFilePaths;//	上传多个文件时,多次访问tempFilePaths.forEach(item => {// 上传图片文件uni.uploadFile({url: 'http://127.0.0.1:3000/upload', // 所上传到的服务器地址filePath: item, // 要上传的文件路径信息name: 'files', // 传与后端的图片数组名formData: { 'user': 'test' },success: uploadFileRes => {console.log(uploadFileRes.data);}});});}
});

现在看后端,这里使用multer来处理formdata

multer详情可见https://github.com/expressjs/multer

以下是处理formdata以及数据库操作全部内容

// 上传图片  
// req.files 是 `files` 文件数组的信息  
router.post('/upload', upload.array('files', 4), function (req, res, next) {if (!req.files || req.files.length === 0) {return res.status(400).send('No files were uploaded.');}try {// 处理所有图片路径const uploadedFiles = req.files.map(file => {// 获取文件扩展名const ext = path.extname(file.originalname);// 生成唯一文件名const dbPath = path.join(UPLOAD_DIR, file.filename + ext).replace(/\\/g, '/');// 获取文件的原始路径const sourcePath = path.normalize(file.path);// 确保目标目录在,UPLOAD_DIR 是上传文件的目录if (!fs.existsSync(UPLOAD_DIR)) {// 目标目录不在,创建目录,recursive: true 表示如果目录不存在,则创建目录fs.mkdirSync(UPLOAD_DIR, { recursive: true });}// 重命名文件fs.renameSync(sourcePath, dbPath);return {path: dbPath,id: Date.now().toString() + Math.random().toString(36).substr(2, 5) // 为每个文件生成唯一ID};});// 数据库存储代码const sql = 'INSERT INTO `photos` (`id`, `path`) VALUES (?, ?)';// 每个文件使用自己的唯一IDconst values = uploadedFiles.map(file => [file.id, file.path]);// 使用 Promise 处理数据库操作,all 方法可以同时执行多个数据库操作  Promise.all(values.map(item => {return new Promise((resolve, reject) => {connection.query(sql, item, function (err, result) {if (err) reject(err);else resolve(result);});});})).then(() => {res.send({success: true,message: 'Files uploaded successfully',// 返回图片路径和IDfiles: uploadedFiles.map(file => ({id: file.id,path: file.path,url: `http://localhost:3000/${file.path}`}))});}).catch(err => {console.error('数据库存储错误:', err);res.status(500).send('Error saving files to database');});} catch (error) {console.error('文件处理错误:', error);res.status(500).send('Error processing files');}
});

以下为分步解释

首先需要使用multer来处理formdata数据,接收formdata数据req.body是空的

使用path来处理multer造成的路径问题

先导入

使用multer({ dest: 'uploads/' })表示告诉它你是在同级目录uploads下存储文件

const multer = require('multer'); // 上传文件
const upload = multer({ dest: 'uploads/' }); // 上传文件到uploads目录

在路由中使用它

upload.array('files')代表你要上传的文件可能是多个,使用数组存储,而数组名是files

.array(fieldname[, maxCount]),还可以配置maxCount来限制最大文件数

router.post('/upload', upload.array('files', 4), function (req, res, next)  {}

处理路径

使用multer后,文件数据会存放在req.files中

不做处理的到的filename是没有后缀的,如下
在这里插入图片描述

以下是完整路径处理流程

try {// 处理所有图片路径const uploadedFiles = req.files.map(file => {// 获取文件扩展名const ext = path.extname(file.originalname);// 生成唯一文件名const dbPath = path.join(UPLOAD_DIR, file.filename + ext).replace(/\\/g, '/');// 获取文件的原始路径const sourcePath = path.normalize(file.path);// 确保目标目录在,UPLOAD_DIR 是上传文件的目录if (!fs.existsSync(UPLOAD_DIR)) {// 目标目录不在,创建目录,recursive: true 表示如果目录不存在,则创建目录fs.mkdirSync(UPLOAD_DIR, { recursive: true });}// 重命名文件fs.renameSync(sourcePath, dbPath);return {path: dbPath,id: Date.now().toString() + Math.random().toString(36).substr(2, 5) // 为每个文件生成唯一ID};});
}

以下是内容详细解释:

首先可以使用extname来获取文件的后缀,file.originalname是含有后缀的,它表示用户计算机上的文件的名称,如果是中文名称会乱码,所以使用filename进行加工使用

使用过程中发现路径默认使用\会造成各种错误、转义错误等,会造成路径错误,所以统一使用/代替掉

使用path.join()方法拼接filenameext扩展名(后缀)就可以得到一个没有乱码的完整路径

// 获取文件扩展名
const ext = path.extname(file.originalname);// 处理文件路径, UPLOAD_DIR 是上传文件的目录
// 将 file.filename + ext 拼接成新的文件路径
// 将所有的 \ 替换为 /
const dbPath = path.join(UPLOAD_DIR, file.filename + ext).replace(/\\/g, '/');

接下来进行路径加工,拼接上目录,使用path.normalize()格式化路径,保证路径没有问题,然后替换之前的fsPath

// 将 dbPath 拼接成 fsPath
// __dirname 是当前文件的目录(本地完整目录),中间使用空字符串拼接,避免有多余的 / 等等,看个人需求
// const fsPath = path.join(__dirname, '..', dbPath);// 确保源路径格式正确,path.normalize() 将路径格式化
const sourcePath = path.normalize(file.path);if (!fs.existsSync(UPLOAD_DIR)) {// 目标目录不在,创建目录,recursive: true 表示如果目录不存在,则创建目录fs.mkdirSync(UPLOAD_DIR, { recursive: true });
}// 重命名文件,renameSync(new_file_path, old_file_path) 重命名文件,将旧文件路径重命名为新文件路径,将位于 sourcePath 的文件或目录重命名为 dbPath 
fs.renameSync(sourcePath, dbPath);
return {path: dbPath,id: Date.now().toString() + Math.random().toString(36).substr(2, 5) // 为每个文件生成唯一ID
};return dbPath; // 返回用于数据库存储的统一格式路径

数据库操作

定义插入数据的sql语句,将uploadedFiles中的路径都遍历出来得到values

 // 数据库存储代码const sql = 'INSERT INTO `photos` (`id`, `path`) VALUES (?, ?)';// 在处理路径时已经生成的idconst values = uploadedFiles.map(file => [file.id, file.path]);

然后通过遍历执行所以的sql语句

// 使用 Promise 处理数据库操作,all 方法可以同时执行多个数据库操作  
Promise.all(values.map(item => {return new Promise((resolve, reject) => {// 执行数据库操作connection.query(sql, item, function (err, result) {if (err) reject(err);else resolve(result);});});
})).then(() => {res.send({success: true,message: 'Files uploaded successfully',// 返回图片路径和IDfiles: uploadedFiles.map(file => ({id: file.id,path: file.path,url: `http://localhost:3000/${file.path}`}))});}).catch(err => {	// 捕获错误console.error('数据库存储错误:', err);res.status(500).send('Error saving files to database');});

可以看到数据存储成功

在这里插入图片描述

测试

最后前端测试是否可以正常访问

写一个访问api

// 获取图片
router.get('/upload', function (req, res, next) {const sql = 'SELECT * FROM `photos`';connection.query(sql, function (err, result) {if (err) {console.error('查询数据库错误:', err);return res.status(500).send('Error querying database');}// 为每个图片添加完整的访问URLconst photosWithUrls = result.map(photo => ({id: photo.id,path: photo.path,url: `http://localhost:3000/${photo.path}` // 添加完整的访问URL}));res.send(photosWithUrls);});
});

前端访问,正常情况是不需要传上面所传的url的,由于是本地服务器可以传,测试方便

getImg() {this.$http.get('http://127.0.0.1:3000/upload').then(res => {this.imgList = [];res.data.forEach(item => {item.path = 'http://127.0.0.1:3000/' + item.path;this.imgList.push(item);});console.log(this.imgList);}).catch(err => {console.log(err);});
}

图片都可以正常显示

在这里插入图片描述


http://www.ppmy.cn/news/1556211.html

相关文章

通过使用 contenteditable=“true“,我们彻底防止了 iOS 系统键盘的弹出

明白了,对于苹果手机(iOS),即使使用了 bindtap 和 e.preventDefault() 来阻止默认行为,系统键盘仍然可能会弹出。这是因为 iOS 对输入框的处理方式与 Android 不同,尤其是在处理 input 元素时,iOS 会更加积极地弹出键盘。 解决方案 为了彻底防止 iOS 系统键盘弹出,我…

在 ThinkPHP中 post 请求中 执行 异步 command ,该 command 创建一个命令行脚本 执行 curl请求 并设置其执行时间无限制

在 ThinkPHP 中实现一个 POST 请求,通过异步执行命令来启动一个命令行脚本,并让该脚本执行一个 cURL 请求,同时设置执行时间无限制,可以按照以下步骤进行。 1. 通过 POST 请求接收数据 假设你已经有了一个处理 POST 请求的接口。…

相机(Camera)成像原理详解

简介:个人学习分享,如有错误,欢迎批评指正。 成像流程 1、光学相机的定义 顾名思义,光学相机就是利用光学原理进行成像的相机,而且市面上的相机几乎都是光学相机,只不过随着时代的发展,胶卷式…

国标GB28181-2022平台EasyGBS:双网口的网络硬盘录像机怎么设置IP地址以及录像机怎么添加不同网段的摄像机?

在现代安防监控系统中,双网口的网络硬盘录像机(NVR)因其灵活性和高效性而备受青睐。这种设备不仅能够提供网络容错,确保网络的稳定性,还能通过多址设定模式连接不同网段的设备,极大地增强了监控系统的扩展性…

Polars数据聚合与旋转实战教程

在这篇博文中,我们的目标是解决数据爱好者提出的一个常见问题:如何有效地从Polars DataFrame中创建汇总视图,以便在不同时间段或类别之间轻松进行比较。我们将使用一个实际的数据集示例来探索实现这一目标的各种方法。 Polars简介 Polars 是…

Spring Boot应用开发深度解析与实战案例

Spring Boot应用开发深度解析与实战案例 在当今快速发展的软件开发领域,Spring Boot凭借其“约定优于配置”的理念,极大地简化了Java应用的开发、配置和部署过程,成为了微服务架构下不可或缺的技术选型。本文将深入探讨Spring Boot的核心特性、最佳实践,并通过一个具体的…

rabbitMq举例

新来个技术总监,把 RabbitMQ 讲的那叫一个透彻,佩服! 生产者 代码举例 public String sendMsg(final String exchangeName,final String routingKey,final String msg) {} /*** 发送消息* param exchangeName exchangeName* param routin…

【网络安全设备系列】7、流量监控设备

0x00 定义: 网络流量控制是一种利用软件或硬件方式来实现对电脑网络流量的控制。它的最主要方法,是引入QoS的概念,从通过为不同类型的 网络数据包标记,从而决定数据包通行的优先次序。 0x01 类型: 流控技术分为两种: 一种是…