【VUE案例练习】一文把握vue2+express实现文件上传

打印 上一主题 下一主题

主题 955|帖子 955|积分 2865

前言

   近期在做跟毕业筹划相关的数据后台管理系统,此中的列表项展示有图片,添加/编辑功能有文件上传。
  “文件上传/删除”也是我们开发中的常见功能,分享个人的实现过程,与各人分享交流
  一、预备工作

   

  • 本次案例使用的node版本是18.16.1
  • 前端vue2+element-ui
  • 后端使用node+express
  • 安装对应库:element-ui、axios、multer
  留意:本篇重点介绍文件上传的相关功能,后端express的详细使用可以看我的express专栏~
express专栏
二、前端

文件上传组件,来自element-ui组件库
留意:自行安装组件库
Element - The world's most popular Vue UI framework

   关于组件,有些展示和功能需要对应设置(比如文件上传的服务器地址,删除后端文件等等)才可以正常使用,以是我对代码进行了修改补充。
  1、组件代码

  1. <template>
  2.   <div>
  3.     <el-upload
  4.       ref="upload"
  5.       action="http://localhost:4000/api/upload"  //文件上传的接口
  6.       list-type="picture-card"
  7.       :on-preview="handlePictureCardPreview"
  8.       :on-remove="handleRemove"
  9.       :file-list="fileList"
  10.       :on-change="handleFileChange"
  11.       :on-success="handleUploadSuccess"
  12.       :on-error="handleUploadError"
  13.       name="file"
  14.     >
  15.       <i class="el-icon-plus" />
  16.     </el-upload>
  17.     <el-dialog :visible.sync="dialogVisible">
  18.       <img width="100%" :src="dialogImageUrl" alt="">
  19.     </el-dialog>
  20.   </div>
  21. </template>
复制代码
2、变量和相关函数

留意:需要安装axios(若安装则跳过)
  1. npm install axios
复制代码
  1. <script>
  2. import Axios from 'axios'
  3. export default {
  4.   data() {
  5.     return {
  6.       dialogImageUrl: '', //预览时展示的图片
  7.       dialogVisible: false,
  8.       fileList: [] // 用于存储文件列表
  9.     }
  10.   },
  11.   methods: {
  12.     // 生成文件预览 URL
  13.     handleFileChange(file, fileList) {
  14.       file.url = URL.createObjectURL(file.raw)
  15.       this.fileList = fileList
  16.     },
  17.     // 删除文件
  18.     handleRemove(file, fileList) {
  19.       this.fileList = fileList
  20.       // 调用后端删除接口
  21.       if (file.response && file.response.data) {
  22.         this.deleteFile(file.response.data)
  23.       } else {
  24.         this.$message.warning('文件尚未上传成功,无法删除')
  25.       }
  26.     },
  27.     // 预览图片
  28.     handlePictureCardPreview(file) {
  29.       this.dialogImageUrl = file.url
  30.       this.dialogVisible = true
  31.     },
  32.     // 文件上传成功
  33.     handleUploadSuccess(response, file) {
  34.       console.log('文件上传成功', response)
  35.       if (response.code === 0) {
  36.         // 从后端响应中获取图片的 URL
  37.         const imageUrl = response.data
  38.         // 更新 fileList 中的文件 URL
  39.         const index = this.fileList.findIndex(f => f.uid === file.uid)
  40.         if (index !== -1) {
  41.           this.fileList[index].url = imageUrl
  42.           this.fileList[index].response = response // 保存后端返回的响应
  43.         }
  44.         this.$message.success('文件上传成功')
  45.       } else {
  46.         this.$message.error('文件上传失败: ' + response.msg)
  47.       }
  48.     },
  49.     // 文件上传失败
  50.     handleUploadError(err, file) {
  51.       console.error('文件上传失败', err)
  52.       this.$message.error('文件上传失败')
  53.     },
  54.     deleteFile(filename) {
  55.       // 去掉前缀 /public/static/upload/
  56.       const pureFilename = filename.replace('/public/static/upload/', '')
  57.       // 调用后端删除接口
  58.       Axios.delete(`http://localhost:4000/api/upload/${pureFilename}`)
  59.         .then(response => {
  60.           if (response.data.code === 0) {
  61.             this.$message.success('文件删除成功')
  62.           } else {
  63.             this.$message.error('文件删除失败: ' + response.data.msg)
  64.           }
  65.         })
  66.         .catch(err => {
  67.           console.error('文件删除失败', err)
  68.           this.$message.error('文件删除失败')
  69.         })
  70.     }
  71.   }
  72. }
  73. </script>
复制代码
3、完整代码

 留意看:''localhost:4000''相关字眼(关于后端接口的,下文会作介绍)
  1. <template>
  2.   <div>
  3.     <el-upload
  4.       ref="upload"
  5.       action="http://localhost:4000/api/upload"
  6.       list-type="picture-card"
  7.       :on-preview="handlePictureCardPreview"
  8.       :on-remove="handleRemove"
  9.       :file-list="fileList"
  10.       :on-change="handleFileChange"
  11.       :on-success="handleUploadSuccess"
  12.       :on-error="handleUploadError"
  13.       name="file"
  14.     >
  15.       <i class="el-icon-plus" />
  16.     </el-upload>
  17.     <el-dialog :visible.sync="dialogVisible">
  18.       <img width="100%" :src="dialogImageUrl" alt="">
  19.     </el-dialog>
  20.   </div>
  21. </template>
  22. <script>
  23. import Axios from 'axios'
  24. export default {
  25.   data() {
  26.     return {
  27.       dialogImageUrl: '',
  28.       dialogVisible: false,
  29.       fileList: [] // 用于存储文件列表
  30.     }
  31.   },
  32.   methods: {
  33.     // 生成文件预览 URL
  34.     handleFileChange(file, fileList) {
  35.       file.url = URL.createObjectURL(file.raw)
  36.       this.fileList = fileList
  37.     },
  38.     // 删除文件
  39.     handleRemove(file, fileList) {
  40.       this.fileList = fileList
  41.       // 调用后端删除接口
  42.       if (file.response && file.response.data) {
  43.         this.deleteFile(file.response.data)
  44.       } else {
  45.         this.$message.warning('文件尚未上传成功,无法删除')
  46.       }
  47.     },
  48.     // 预览图片
  49.     handlePictureCardPreview(file) {
  50.       this.dialogImageUrl = file.url
  51.       this.dialogVisible = true
  52.     },
  53.     // 文件上传成功
  54.     handleUploadSuccess(response, file) {
  55.       console.log('文件上传成功', response)
  56.       if (response.code === 0) {
  57.         // 从后端响应中获取图片的 URL
  58.         const imageUrl = response.data
  59.         // 更新 fileList 中的文件 URL
  60.         const index = this.fileList.findIndex(f => f.uid === file.uid)
  61.         if (index !== -1) {
  62.           this.fileList[index].url = imageUrl
  63.           this.fileList[index].response = response // 保存后端返回的响应
  64.         }
  65.         this.$message.success('文件上传成功')
  66.       } else {
  67.         this.$message.error('文件上传失败: ' + response.msg)
  68.       }
  69.     },
  70.     // 文件上传失败
  71.     handleUploadError(err, file) {
  72.       console.error('文件上传失败', err)
  73.       this.$message.error('文件上传失败')
  74.     },
  75.     // 删除后端文件,参数传递的是文件名(经前端上传过后,返回给前端的文件名)
  76.     deleteFile(filename) {
  77.       // 去掉前缀 /public/static/upload/
  78.       const pureFilename = filename.replace('/public/static/upload/', '')
  79.       // 调用后端删除接口
  80.       Axios.delete(`http://localhost:4000/api/upload/${pureFilename}`)
  81.         .then(response => {
  82.           if (response.data.code === 0) {
  83.             this.$message.success('文件删除成功')
  84.           } else {
  85.             this.$message.error('文件删除失败: ' + response.data.msg)
  86.           }
  87.         })
  88.         .catch(err => {
  89.           console.error('文件删除失败', err)
  90.           this.$message.error('文件删除失败')
  91.         })
  92.     }
  93.   }
  94. }
  95. </script>
  96. <style>
  97. .el-upload-list__item-thumbnail {
  98.   width: 100%;
  99.   height: 100%;
  100.   object-fit: cover;
  101. }
  102. </style>
复制代码
三、后端

1、搭建express应用

【express-generator】01-安装和基本使用
如果按照文章步骤(默认端口是3000,我这里设置成4000端口),则对应更换端口为4000,在创建的express项目标bin/www中进行修改。

2、新建文件夹及文件

2.1、新建public/static/upload

这是存储上传文件的位置。

 2.2、新建routes/upload.js,撰写路由方法

安装multer,这是处理文件上传的相关库。
   npm install multer
  

  1. var express = require("express");
  2. const multer = require("multer");
  3. const { uploading } = require("../utils/tool");
  4. const fs = require('fs');
  5. const path = require('path');
  6. var router = express.Router();
  7. // 文件上传接口
  8. router.post("/", async function (req, res, next) {
  9.     // single 方法里面书写上传控件的 name 值
  10.     uploading.single("file")(req, res, function (err) {
  11.         if (err instanceof multer.MulterError) {
  12.             next("上传文件失败,请检查文件的大小,控制在 6MB 以内");
  13.         } else {
  14.             console.log("req.file>>>", req.file);
  15.             
  16.             const filePath = "/public/static/upload/" + req.file.filename;
  17.             res.send({ code: 0, msg: "文件上传成功", data: filePath });
  18.         }
  19.     })
  20. });
  21. // 文件删除接口
  22. router.delete("/:filename", function (req, res, next) {
  23.     const filename = req.params.filename;
  24.     const filePath = path.join(__dirname, '../public/static/upload',filename);
  25.     console.log("后端接收到的文件参数>>>",filename,"完整基本路径是>>>>",filePath);
  26.     fs.unlink(filePath, (err) => {
  27.         if (err) {
  28.             console.error("删除文件失败", err);
  29.             return res.status(500).send({ code: 1, msg: "删除文件失败" });
  30.         }
  31.         res.send({ code: 0, msg: "文件删除成功" });
  32.     });
  33. });
  34. module.exports = router;
复制代码
2.3、新增utlis/tool.js,撰写工具类函数


  1. const multer = require("multer");
  2. const path = require("path");
  3. // 设置上传文件的引擎
  4. const storage = multer.diskStorage({
  5.     // 文件存储的位置
  6.     destination: function (req, file, cb) {
  7.         cb(null, __dirname + '/../public/static/upload');
  8.     },
  9.     // 上传到服务器的文件,文件名要做单独处理
  10.     filename: function (req, file, cb) {
  11.         // 获取文件名
  12.         const basename = path.basename(file.originalname, path.extname(file.originalname));
  13.         // 获取后缀名
  14.         const extname = path.extname(file.originalname);
  15.         // 构建新的名字
  16.         const newName = basename + new Date().getTime() + Math.floor(Math.random() * 9000 + 1000) + extname;
  17.         cb(null, newName);
  18.     }
  19. })
  20. module.exports.uploading = multer({
  21.     storage: storage,
  22.     limits: {
  23.         fileSize: 6000000,
  24.         files: 1
  25.     }
  26. })
复制代码
 3、在app.js中引入和使用

  1. var createError = require('http-errors');
  2. var express = require('express');
  3. var path = require('path');
  4. var cookieParser = require('cookie-parser');
  5. var logger = require('morgan');
  6. const cors = require('cors');
  7. // 文件上传
  8. const multer = require('multer');
  9. const fs = require('fs');
  10. // const path = require('path');
  11. var indexRouter = require('./routes/index');
  12. var usersRouter = require('./routes/users');
  13. var uploadRouter = require('./routes/upload');
  14. var app = express();
  15. // view engine setup
  16. app.set('views', path.join(__dirname, 'views'));
  17. app.set('view engine', 'jade');
  18. // 允许所有来源访问
  19. app.use(cors());
  20. // 文件上传
  21. // const upload = multer({ dest: 'static/upload/' });
  22. app.use(express.static(path.join(__dirname, 'public')));
  23. app.use(logger('dev'));
  24. app.use(express.json());
  25. app.use(express.urlencoded({ extended: false }));
  26. app.use(cookieParser());
  27. app.use(express.static(path.join(__dirname, 'public')));
  28. app.use('/', indexRouter);
  29. app.use('/users', usersRouter);
  30. app.use('/api/upload/', uploadRouter);
  31. // error handler
  32. app.use(function(err, req, res, next) {
  33.   // set locals, only providing error in development
  34.   res.locals.message = err.message;
  35.   res.locals.error = req.app.get('env') === 'development' ? err : {};
  36.   // render the error page
  37.   res.status(err.status || 500);
  38.   
  39.   res.render('error');
  40. });
  41. module.exports = app;
复制代码
四、测试

1、上传文件(图片)


 查看存储上传文件的位置

 2、删除文件(图片)

前端组件,鼠标进入到图片区域,点击删除按键

前端作出对应提示

末了前端的文件列表也为空,成功删除了文件。

后端查看文件夹,发现刚上传的文件由于前端的删除操作,也对应进行了删除。
 

 五、总结

一些留意点
   express应用默认端口号是3000,而案例演示的是4000(因为一般环境,3000端口容易被其他代码程序给使用用,制止这种环境,可以使用一个新的端口号(或者把占用3000端口的程序都关闭))
    关于文件上传的设置,涉及到的知识点比力多,比如fs.unlink,path相关的知识,需要各人自行进行补充了解,部门知识点可以参考下方这篇博客文章。
  【NODE】01-fs和path常用知识点
  
如果有问题,请留言评论~
如果你喜欢这篇文章,留下你的点赞和收藏~ 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

金歌

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表