express上传文件处理

2 篇文章 0 订阅

1.安装multer模块

npm i multer -S

multer是node.js的中间件,用于处理multipart/form-data类型的表单数据,主要用于上传文件

2.前端处理文件的上传、预览、下载

这里使用的vue+elementui

<template>
	 <el-upload
          class="avatar-uploader"
          action="#"
          :before-upload="beforeAvatarUpload"
          :http-request="httpRequest"
          :show-file-list="false"
        >
          <img v-if="imageUrl" :src="imageUrl" class="avatar" />
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>

        <el-button @click="handlePreview" v-show="showPreviewBtn" type="primary"
          >预览</el-button
        >

        <el-button @click="updateAvatar" v-show="showPreviewBtn"
          >上传头像</el-button
        >

        <el-button @click="downloadFile" v-show="showPreviewBtn" type="primary"
          >下载头像</el-button
        >
      </el-form-item>
</template>

<script>
	export default{
        data(){
            return{
                imageUrl: "",
              	previewImage: false,
              	showPreviewBtn: false, //默认隐藏预览按钮
              	fileId: "", //文件的二进制名称
              	currentFileId: "", //判断上传后的fileId是否相同  如果相同则提示图片重复上传
              	currentFileNameCN: "", //当前图片的名称
            }
        },
        computed: {
    		...mapState(["userInfo", "userId"]),
  		},
        methods:{
            /**上传之前 */
            beforeAvatarUpload(file) {
              console.log(file);
              let { name, size } = file;
              let nameArr = name.split(".");
              //文件后缀名
              let fileType = nameArr[nameArr.length - 1];
              //文件大小
              let fileSize = (size / 1024 / 1024).toFixed(4);
              console.log(fileType, fileSize);
              //文件大小不超过2M且格式必须是jpg/png
              let fileTypeList = ["jpg", "png"];
              if (!(fileSize > 2 || fileTypeList.includes(fileType))) {
                this.$message.error("文件类型只能为jpg或png且文件大小不能超过2M");
                return;
              }
            },
                /**上传文件 及 预览*/
            async httpRequest(params) {
              const { file } = params;
              const formData = new FormData();
              formData.append("file", file);
              const fileData = await uploadFile(formData);
              let { filename, fileNameCN, originalname } = fileData;
              //返回的fileId 用于上传时用
              this.fileId = filename;
              //用于下载时的文件名
              this.currentFileNameCN = fileNameCN || originalname;
              const { data } = await previewFile(filename);
              this.imageUrl = `${baseUrl}/uploadFile/${data.fileNewName}`;
              //显示预览 上传 下载 按钮
              this.showPreviewBtn = true;
            },

            /**预览图片 */
            handlePreview() {
              this.previewImage = true;
            },

            /**上传头像 上传成功则用户头像*/
            async updateAvatar() {
              let params = {
                fileId: this.fileId,
                userId: this.userInfo.userId,
              };
              const { code, msg } = await uploadAvatar(params);
              if (code == 200) {
                this.$message.success(msg);
                this.$parent.$parent.$parent.init();
              } else {
                this.$message.error(msg);
              }
            },

            /**下载头像 */
            async downloadFile() {
              const data = await downloadAvatar(this.fileId);
              let a = document.createElement("a");
              a.download = this.currentFileNameCN;
              a.style.display = "none";
              let blob = new Blob([data]);
              const url = URL.createObjectURL(blob);
              a.href = url;
              a.click();
              window.URL.revokeObjectURL(url);
            },
          },
        },
        created() {
            //获取用户信息
            this.formData = this.userInfo;
            this.fileId = this.userInfo.fileId;
            this.currentFileNameCN = this.userInfo.fileNewName;
            //判断是否存在用户图片
            if (this.userInfo.fileId) {
              this.imageUrl = `${baseUrl}/uploadFile/${this.userInfo.fileNewName}`;
              this.showPreviewBtn = true;
            } else {
              this.showPreviewBtn = false;
            }
  		},
    }
</script>

3.后端处理文件的上传、预览、下载

后端用的express ,用multer处理文件上传

为了将文件路径或二进制名称存入数据库存储,将源文件名称及二进制文件名都存入数据库中(避免相同的源文件名称)

由于img的src属性可以直接读取二进制文件,所以在存取时可以直接存入src属性中,通过对文件的读写操作,保存上传文件的二进制文件及上传的源文件,但是为了防止文件名重复,上传的文件名按照年月日时分秒_文件名格式存入数据库

后端代码:

var express = require('express');
var router = express.Router();

let fs = require('fs')
let multer = require('multer')

let upload = multer({ dest: './public/uploadFile/' }) //创建文件夹
/**上传 + 预览*/
router.post('/uploadFile', upload.any(), (req, res, next) => {
      //var des_file = "./public/uploadFile/" + req.files[0].originalname;
    //读取文件  fs.readFile(path,callback) => path 为路径 callback为回调函数,err:错误  data:
      // fs.readFile( req.files[0].path, function (err, data) {
      // fs.writeFile(des_file, data, function (err) {
      //     if( err ){
      //         console.log( err );
      //     }else{
      //         let response = {
      //             filename: req.files[0].filename,
      //			 path: req.files[0].path
      //         };
      //         res.send( response );
      //     }
      // });
  // });
    
    /*鉴于官方建议使用异步方法,比起同步,异步方法性能更高,速度更快,而且没有阻塞。读写后会生成二进制文件及源文件*/
    //fs.writeFileSync(des_file,fs.readFileSync(req.files[0].path)) //先读文件,然后重新定义文件路径写入文件
    
    //直接改名且不生成二进制文件
    //文件重新命名
  let fileNameArr = file.originalname.split('.');
  let suffix = fileNameArr[fileNameArr.length - 1];
  let currentDate = dateFormat(new Date(), 'YYYYmmddHHMMSS')
  //避免文件名重复  格式为 年月日时分秒_文件名
  let fileNewName = `${currentDate}_${fileNameArr[0]}.${suffix}`
    fs.renameSync('./public/uploadFile/' + file.filename, `./public/uploadFile/${fileNewName}`)
    
    /**如果存在相同的文件  则不添加  根据图片名称、二进制名称、文件类型及大小判断 */
  //上传成功后在fileInfo表中插入文件数据
  let select = `select * from fileinfo where  fileName='${file.originalname}' and fileType='${suffix}' and fileSize='${file.size}'`
  console.log(select)
  connection.query(select, (selectErr, selectData) => {
    //当文件相同时
    if (selectData.length > 0) {
      let response = {
        filename: selectData[0].fileId,
        path: selectData[0].filePath,
        fileNameCN: selectData[0].fileNewName,
      }
      // console.log(response, '111111111')
      res.send(response)
    } else {
        //上传新文件 则直接添加一条数据
      let sql = "insert into fileinfo(fileId,fileName,fileNewName,fileType,filePath,fileSize) values(?,?,?,?,?,?)"
      let sqlParams = [file.filename, file.originalname, fileNewName, suffix, file.path, file.size]
      connection.query(sql, sqlParams, (err, doc) => {
        if (err) res.json({ code: 500, data: null, msg: err })
        let response = {
          filename: req.files[0].filename,
          path: req.files[0].path,
          fileNameCN: fileNewName,
        }
        // console.log(response, '2222222222222')
        res.send(response)
      })
    }
  })
})

前端代码:

<template>
	 <el-upload
          class="avatar-uploader"
          action="#"
          :before-upload="beforeAvatarUpload"
          :http-request="httpRequest"
          :show-file-list="false"
        >
          <img v-if="imageUrl" :src="imageUrl" class="avatar" />
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>

        <el-button @click="handlePreview" v-show="showPreviewBtn" type="primary"
          >预览</el-button
        >

        <el-button @click="updateAvatar" v-show="showPreviewBtn"
          >上传头像</el-button
        >

        <el-button @click="downloadFile" v-show="showPreviewBtn" type="primary"
          >下载头像</el-button
        >
      </el-form-item>
</template>

<script>
	export default{
        data(){
            return{
                imageUrl: "",
              	previewImage: false,
              	showPreviewBtn: false, //默认隐藏预览按钮
              	fileId: "", //文件的二进制名称
              	currentFileId: "", //判断上传后的fileId是否相同  如果相同则提示图片重复上传
              	currentFileNameCN: "", //当前图片的名称
            }
        },
        computed: {
    		...mapState(["userInfo", "userId"]),
  		},
        methods:{
            /**上传之前 */
            beforeAvatarUpload(file) {
              console.log(file);
              let { name, size } = file;
              let nameArr = name.split(".");
              //文件后缀名
              let fileType = nameArr[nameArr.length - 1];
              //文件大小
              let fileSize = (size / 1024 / 1024).toFixed(4);
              console.log(fileType, fileSize);
              //文件大小不超过2M且格式必须是jpg/png
              let fileTypeList = ["jpg", "png"];
              if (!(fileSize > 2 || fileTypeList.includes(fileType))) {
                this.$message.error("文件类型只能为jpg或png且文件大小不能超过2M");
                return;
              }
            },
                /**上传文件 及 预览*/
            async httpRequest(params) {
              const { file } = params;
              const formData = new FormData();
              formData.append("file", file);
              const fileData = await uploadFile(formData);
              let { filename, fileNameCN, originalname } = fileData;
              //返回的fileId 用于上传时用
              this.fileId = filename;
              //用于下载时的文件名
              this.currentFileNameCN = fileNameCN || originalname;
              const { data } = await previewFile(filename);
              this.imageUrl = `${baseUrl}/uploadFile/${data.fileNewName}`;
              //显示预览 上传 下载 按钮
              this.showPreviewBtn = true;
            },

            /**预览图片 */
            handlePreview() {
              this.previewImage = true;
            },

            /**上传头像 上传成功则用户头像*/
            async updateAvatar() {
              let params = {
                fileId: this.fileId,
                userId: this.userInfo.userId,
              };
              const { code, msg } = await uploadAvatar(params);
              if (code == 200) {
                this.$message.success(msg);
                this.$parent.$parent.$parent.init();
              } else {
                this.$message.error(msg);
              }
            },

            /**下载头像*/
            async downloadFile() {
              const data = await downloadAvatar(this.fileId);
              let a = document.createElement("a");
              a.download = this.currentFileNameCN;
              a.style.display = "none";
              let blob = new Blob([data]);
              const url = URL.createObjectURL(blob);
              a.href = url;
              a.click();
              window.URL.revokeObjectURL(url);
            },
          },
        },
        created() {
            //获取用户信息
            this.formData = this.userInfo;
            this.fileId = this.userInfo.fileId;
            this.currentFileNameCN = this.userInfo.fileNewName;
            //判断是否存在用户图片
            if (this.userInfo.fileId) {
              this.imageUrl = `${baseUrl}/uploadFile/${this.userInfo.fileNewName}`;
              this.showPreviewBtn = true;
            } else {
              this.showPreviewBtn = false;
            }
  		},
    }
</script>

注意:这里做的下载返回类型是blob(responseType:‘blob’)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值