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;
    }
  };
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用Vue.js和Element UI来实现前端界面,使用Spring Boot来处理后端逻辑来实现文件模板的上传和下载功能。 首先,你可以创建一个Vue组件来处理文件上传下载的界面。可以使用Element UI中的Upload组件来实现文件上传功能,使用Button组件来实现文件下载功能。在上传组件中,你可以设置上传的文件类型和大小限制,并在上传成功后获取到文件的URL或者其他信息。 接下来,在后端使用Spring Boot来处理上传和下载的逻辑。你可以创建一个Controller来处理文件上传下载的请求。在文件上传的方法中,你可以使用MultipartFile来接收上传的文件,并将其保存到服务器上的某个目录中。在文件下载的方法中,你可以根据传入的文件名或者其他标识,从服务器上读取相应的文件,并将其以流的形式返回给前端。 以下是一个简单的示例代码: 前端Vue.js + Element UI): ```vue <template> <div> <el-upload class="upload-demo" action="/api/upload" :on-success="handleSuccess" :before-upload="beforeUpload" > <el-button type="primary">点击上传</el-button> </el-upload> <el-button type="primary" @click="downloadTemplate">下载模板</el-button> </div> </template> <script> export default { methods: { handleSuccess(response) { // 处理上传成功后的逻辑 console.log(response); }, beforeUpload(file) { // 设置上传文件的类型和大小限制 const fileType = file.type; const fileSize = file.size / 1024 / 1024; // MB const allowedTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']; // 允许的文件类型 const maxFileSize = 10; // 允许的最大文件大小,单位:MB if (!allowedTypes.includes(fileType)) { this.$message.error('只能上传pdf、doc或docx格式的文件'); return false; } if (fileSize > maxFileSize) { this.$message.error(`文件大小超过了${maxFileSize}MB`); return false; } return true; }, downloadTemplate() { // 处理下载模板的逻辑 window.location.href = '/api/download'; }, }, }; </script> ``` 后端(Spring Boot): ```java @RestController @RequestMapping("/api") public class FileController { @PostMapping("/upload") public String uploadFile(@RequestParam("file") MultipartFile file) { // 处理文件上传逻辑 // 可以将上传的文件保存到服务器上的某个目录中 return "上传成功"; } @GetMapping("/download") public void downloadTemplate(HttpServletResponse response) { // 处理文件下载逻辑 // 根据文件名或者其他标识,从服务器上读取相应的文件,并将其以流的形式返回给前端 String fileName = "template.docx"; // 下载文件名 String filePath = "/path/to/template.docx"; // 文件在服务器上的路径 try { File file = new File(filePath); InputStream inputStream = new FileInputStream(file); response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")); IOUtils.copy(inputStream, response.getOutputStream()); response.flushBuffer(); } catch (Exception e) { e.printStackTrace(); } } } ``` 这是一个简单的示例,你可以根据自己的需求进行进一步的调整和优化。希望对你有帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值