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

news2024/11/21 2:21:59

文章目录

    • 1、前端代码
    • 2、后端代码

本文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;
    }
  };

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/755492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++服务器框架开发11——编译调试1/cmake学习

该专栏记录了在学习一个开发项目的过程中遇到的疑惑和问题。 其教学视频见&#xff1a;[C高级教程]从零开始开发服务器框架(sylar) 上一篇&#xff1a;C服务器框架开发10——日志系统1~9代码 C服务器框架开发11——编译调试1/cmake学习 目前进度ubuntu下的cmake学习简单样例同…

【论文笔记】SINE: SINgle Image Editing with Text-to-Image Diffusion Models

声明 不定期更新自己精度论文&#xff0c;通俗易懂&#xff0c;初级小白也可以理解 涉及范围&#xff1a;深度学习方向&#xff0c;包括 CV、NLP 论文标题&#xff1a;SINE: SINgle Image Editing with Text-to-Image Diffusion Models 论文链接&#xff1a;https://www.seman…

ESXI 安装win10详细步骤

在esix安装win10安装过程遇到了坑&#xff0c;发现必须对具体选项进行设置后才可&#xff0c;做下记录&#xff1a; 1、CPU设置 &#xff12;、硬盘 3、网络适配器 4、驱动器 5、虚拟机选项

LangChain大型语言模型(LLM)应用开发(四):QA over Documents

LangChain是一个基于大语言模型&#xff08;如ChatGPT&#xff09;用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口&#xff0c;可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互&#x…

动手学深度学习——图像分类数据集(代码详解)

目录 1. 图像分类数据集1.1 读取数据集1.2 读取小批量1.3 整合所有组件1.4 小结 1. 图像分类数据集 这里采用Fashion-MNIST数据集 torchvision&#xff1a;torch类型的可视化包&#xff0c;一般计算机视觉和数据可视化需要使用from torchvision import transforms&#xff1a;…

kotlin forEach循环return/break

kotlin forEach循环return/break fun main(args: Array<String>) {var a mutableListOf("0", "1", "2", "3", "4")var b mutableListOf<String>()a.forEachIndexed { index, s ->if (index > 2) {retu…

CGY-OS 正式开源!

一个初中生自己编写的一个很LOW的“OS”&#xff0c;编写不易&#xff0c;不喜勿喷&#xff1b;耗时巨大&#xff0c;引用时请说明。 接下来&#xff0c;让我们一起学习使用cgyOS。 零、配置 下载本程序后&#xff0c;在Python3.10环境下使用pip安装pygame和keyboard的最新版本…

Java二叉树

目录 一、树形结构 1.1 概念 1.2 树的性质 1.3 树的表示形式 二、二叉树 2.1 概念 2.2 两种特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储 2.5 二叉树的基本操作 2.5.1 二叉树的遍历 2.5.2 二叉树的基本操作 一、树形结构 1.1 概念 树是一种非线性的数据结构&#xff0…

H3C-Cloud Lab-实验-DHCP中继实验

实验需求&#xff1a; 1、按照图示配置IP地址 2、配置R1为DHCP服务器&#xff0c;能够跨网段为192.168.2.0/24网段自动分配IP地址。要求分配DNS地址为202.103.24.68和202.103.0.117 3、PC3获取IP地址后&#xff0c;能够访问到192.168.1.1 实验拓扑图&#xff1a; 连接CRT 设…

Linux5.97 Ceph集群

文章目录 计算机系统5G云计算第四章 LINUX Ceph集群一、Ceph1.存储基础1&#xff09;单机存储设备2&#xff09;单机存储的问题3&#xff09;商业存储解决方案4&#xff09;分布式存储&#xff08;软件定义的存储 SDS&#xff09;5&#xff09;分布式存储的类型 2.Ceph 简介3.C…

tmux安装及使用

tmux安装及使用 tmux是一款很好使用的终端工具&#xff0c;配合shell脚本使用非常方便。 一、tmux安装 终端输入命令&#xff1a; sudo apt-get install tmux二、tmux使用 首先需要对tmux使用的名词有一个基本了解&#xff1a; session &#xff1a;会话 window : 窗口 pa…

职责链(Chain of responsibility)模式

目录 处理过程应用场景参与者协作效果实现相关模式应用与思考类图 职责链(Chain of responsibility)是一种对象行为模式&#xff0c;可以使多个对象都有机会处理请求&#xff0c;从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递…

快速配置 Rust 开发环境并编写一个小应用

安装: curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh 更新: Rust 的升级非常频繁. 如果安装 Rustup 后已有一段时间,那么很可能 Rust 版本已经过时, 运行 rustup update 获取最新版本的 Rust rustc&#xff1a;编译Rust程序 rustc只适合简单的Rust程序&#xf…

5G全网通工业三防平板Windows移动电脑

当今科技领域的快速发展为我们的生活带来了许多便利和高效性能。在这个数字化时代&#xff0c;移动设备已成为我们生活的重要组成部分。在这一领域&#xff0c;搭载全新第12代英特尔酷睿Mi5-1235U/i7-1255U处理器的工业三防平板Windows移动电脑无疑是一款引人注目的产品。 这款…

mysql获取附近的店并显示当前距离并由近到远显示

1、创建测试数据 CREATE TABLE store (id int(11) NOT NULL AUTO_INCREMENT,name varchar(50) NOT NULL COMMENT 商家名称,address varchar(200) NOT NULL COMMENT 商家地址,coordinates varchar(50) NOT NULL COMMENT 经纬度,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT…

阿卡西斯 USB4 雷电4 移动硬盘盒做Mac系统盘 体验

硬盘盒(USB4 JHL7440 RTL9210B) 无风扇版本(型号 TBU405 659RMB). 发热大 所以官方出了带风扇版本,我的是不带风扇的. 我是三星990pro组合. 我是把mac系统直接安装到硬盘盒的硬盘里面里面 这是刚买时候的速度 这是当系统重度使用(写代码 大数据环境) 4个月后的硬盘速度测试…

DBeaver设置主题

一、下载包 帮助-》Install new software Eclipse Update Site 勾选一直下一步&#xff0c;直到安装完&#xff0c;会提示重启&#xff0c;重启设置主题即可 二、设置主题 窗口-》首选项-》DevStyle

快速上手一个I2C传感器 | MAX6884

老老实实看DataSheet吧&#xff0c;查找手册有以下几种途径&#xff1a; 1&#xff09;到芯片厂商官网去下载资料&#xff1b; 2&#xff09;在芯片器件采购平台搜索&#xff0c;如立创商城、半导小芯&#xff1b; 有原厂或代理翻译的中文手册&#xff0c;或者国产芯片中文手…

leetcode 450. 删除二叉搜索树中的节点

2023.7.14 搜索二叉树相关的题一般都能用递归解决。 本体大致思路是&#xff1a;使用递归的方式&#xff0c;在树中查找目标节点&#xff0c;并根据节点的情况进行删除操作。如果目标节点是叶子节点&#xff0c;直接删除它&#xff1b;如果目标节点只有一个子树&#xff0c;将子…

H3C-Cloud Lab-实验-ACL实验

实验拓扑图&#xff1a; 网段分布情况&#xff1a; 实验需求&#xff1a; 1. 按照图示配置 IP 地址 2. 全网路由互通 3. 在 SERVER1 上配置开启 TELNET 和 FTP 服务 4. 配置 ACL 实现如下效果 1&#xff09;192.168.1.0/24 网段不允许访问 192.168.2.0/24 网段&#xff0c…