Vue+Node(Egg框架)实现文件上传保存至本地和下载文件

本文Node搭建的服务器是基于egg框架搭建,如果使用其他服务器端框架,可参考部分代码,不保证所有框架都能实现

实现效果:
请添加图片描述

1、前端代码

前端部分vue利用的element-ui文件上传组件,相关属性api请参考element-ui官方文档
index.vue

<template>
  <div class="body-class">

    <el-form v-show="!isEdit && !isEditAccount" ref="userInfo" label-width="120px" :model="user" label-position="left"
      class="ruleForm">
  
        <el-form-item label="简历">
          <el-upload class="upload-demo" ref="upload" :action="fileUrl" :on-preview="handlePreview"
            :on-remove="handleRemove" :file-list="fileList" :auto-upload="false" :before-upload="beforeUpload" :limit="1"
            :on-exceed="handleExceed" :on-success="handleResumeSuccess" >
            <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
            <el-button style="margin-left: 10px;" size="small" type="warning" @click="submitUpload">上传</el-button>
            <el-button style="margin-left: 10px;" size="small" v-if="file.resumead" type="primary" @click="downloadResume">
              下载简历
            </el-button>
            <div slot="tip" class="el-upload__tip">只能上传doc/pdf文件,且不超过2MB</div>
          </el-upload>
        </el-form-item>
    </el-form>
  </div>
</template>

<script>
import { del } from '@/request/http';
import axios from 'axios';
import { updateStudent, updateAccount, getInfoByToken, deleteResume, getResumeByStudentId, saveOrUpdateResume } from '@/request/api';
export default {
  name: "StudentInfo",
  data () {
    return {
      fileList: [],//保存上传的文件
      basePath: "http://127.0.0.1:7003/",
      fileUrl: "http://127.0.0.1:7003/resume/fileUpload",//上传文件路径
      bool:true,//保存是否允许上传的文件类型
      file: {
        resumead: ""
      },
  },
  methods: {
    handlePreview (file) {
      console.log(file, 3);
    },
    // 删除文件
    async handleRemove (file, fileList) {
      // console.log(file, fileList);
      //获取文件名
      if (file.response || file.url) {
        let f;
        if (file.response) {
          let arr = file.response.data.split("\\");
          f = arr[arr.length - 1];
        } else {
          let arr = file.url.split("/"); 
          let arr2 = arr[arr.length - 1].split("\\");
          f = arr2[arr2.length - 1];
        }
        this.fileList.pop();
        try {
          let res = await del(`/resume/deleteFile/${f}`);
          if (res) {
            const x = await deleteResume({ id: this.file.id })
            // conole.log(x)
            if (x) {
              this.file = {};
              this.$message.success("删除成功")
            }
          }
        } catch (error) {
          console.log(error)
        }
      }
    },
    //文件上传前的操作
    beforeUpload (file) {
      console.log(file,1)
      //判断文件类型
      const isWORD = file.type === 'application/msword' || file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
      const isPDF = file.type === 'application/pdf';

      const isLt2M = file.size / 1024 / 1024 < 2;
      console.log(isWORD, isPDF)
      let bool=isWORD||isPDF
      if (!bool) {
        this.$message.error('上传文件只能是doc或pdf格式!');
      }
      
      if (!isLt2M) {
        this.$message.error('上传文件大小不能超过 2MB!');
      }
      this.bool = (isWORD || isPDF) && isLt2M;
      return (isWORD || isPDF) && isLt2M;
    },
    handleExceed (files, fileList) {
      this.$message.warning(`当前限制上传 1 个文件`);
    },
    //文件上传成功后
    async handleResumeSuccess (res, file) {
      console.log(file)
      //获取文件名
      this.file.resumead = this.basePath + file.response.data.replace(/\\\\/g, "/");
      if (this.bool) {
        try {
          let res = await saveOrUpdateResume({ resumead: this.file.resumead, student_id: this.user.id, filename: file.name, is_effect: 1 })
          if (res) {
            this.$message.success("上传成功");
            this.getFile();
          }
        } catch (error) {
          console.log(error)
        }
      }
    },
    //执行上传操作
    submitUpload () {
      this.$refs.upload.submit();
    },
    //下载文件
    async downloadResume () {
      const loding = this.$message({
        message: '文件下载中,请稍后...',
        duration: 0,
        iconClass: 'el-icon-loading'
      })
      try {
        let res = await axios.get(this.file.resumead, {
          timeout: 10000,
          headers: {
            responseType: 'arraybuffer'
          }
        });
        console.log(res)
        if (res) {
          const a = document.createElement('a')
          a.href = window.URL.createObjectURL(new Blob([res.data]))
          a.download = "我的简历.pdf"
          a.click();
          loding.close()
          this.$message.success('文件下载完成!')
        }
      } catch (error) {
        console.log(error)
      }
    },
    //获取文件
    async getFile () {
      try {
      	//调用获取文件的接口
        let res = await getResumeByStudentId({ student_id: this.user.id });
        // console.log(res);
        if (res.data.length>0) {
          this.fileList = [{ name: res.data[0].filename, url: res.data[0].resumead }];
          this.file = res.data[0];
        }
      } catch (error) {
        console.log(error)
      }
    },
  },
}
</script>

在这里插入图片描述
调用文件上传接口
在这里插入图片描述
调用存储简历的接口,将返回的文件路径和文件名保存到表中
在这里插入图片描述
读取简历信息,显示到页面中
在这里插入图片描述

2、后端代码

router.js
后端路由配置

module.exports = (app) => {
  const { router, controller, jwt } = app;
  
  router.post('/resume/fileUpload', controller.resume.fileUpload);//上传文件
  router.get('/app/resume/:file', controller.resume.getFile);//获取文件
  router.delete('/resume/deleteFile/:file', controller.resume.deleteFile);//删除文件
};

app/controller/resume.js
下图为上传文件保存的路径
在这里插入图片描述

const Controller = require('egg').Controller;

const Response = require('../utils/Response');
const fs = require('fs');
const path = require('path');

/**
 * @Controller ResumeController:公司模块
 */
class ResumeController extends Controller {

  //上传文件***
  async fileUpload() {
    const { ctx, config } = this;
    try {
      // 获取文件
      const file = ctx.request.files[0];
      console.log('获取文件', file);
      // ctx.request.files[0] 表示获取第一个文件,若前端上传多个文件则可以遍历这个数组对象
      //读取文件
      const fileData = fs.readFileSync(file.filepath);
      // console.log('fileData', fileData);

      const date = Date.now(); // 毫秒数
      //设置文件保存路径
      const tempDir = path.join(
        'app/resume',
        date + path.extname(file.filename)
      ); // 返回文件保存的路径
      // console.log('毫秒数 extname', date, path.extname(file.filename));
      console.log('返回文件保存的路径', tempDir);
      // 写入文件夹
      fs.writeFileSync(tempDir, fileData);
      ctx.body = {
        status: 200,
        desc: '上传成功',
        data: tempDir,
      };
    } catch (error) {
      console.log('error', error); // 错误处理程序或处理器,比如打开文件错误,文件名
      ctx.body = {
        status: 500,
        desc: '上传失败',
        data: null,
      };
    }
  }

 //删除文件 
  async deleteFile() {
    // 删除图片文件夹中的所有文件和图片  /delete/img/filename.png 或 delete/img/filename.png
    const { ctx } = this;
    console.log(ctx.params.file); // 获取删除文件的条目的唯一标志
    const fileDelete = `app/resume/${ctx.params.file}`; // 这里写一个例子  app/resume/filename.png
    const fileDeleteExists = fs.existsSync(fileDelete); // 检查文件是否存在
    console.log(fileDeleteExists); // 获取删除文件条目的唯一标志 
    if (fileDeleteExists) {
      // 如果文件存在 执行删除操作  delete/img/filename.png
      fs.unlinkSync(fileDelete);
      ctx.body = { status: 200, desc: '文件删除成功', data: null };
    }
  }
  
  //获取文件
  async getFile() {
    const { ctx } = this;

    ctx.body = fs.readFileSync(`app/resume/${ctx.params.file}`);
  }
}

module.exports = ResumeController; // 自动挂载类 到 基类

上传文件后接口输出
在这里插入图片描述
保存简历路径到表中接口返回数据
在这里插入图片描述

config.default.js
egg配置文件,必须要配,之前没配一直上传不了。。。

  config.multipart = {
    // mode: "file",
    // fileSize: '100mb',
    mode: 'file',
    cleanSchedule: {
      cron: '0 0 4 * * *',
    },
    whitelist() {
      return true;
    }
  };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值