egg(十):上传excel文件并解析内容,存到mysql数据库,并保存到本地,vue+egg实现前后端

前言:

       在egg中的上传是有两种方法来实现:官方入口

  • File 模式:

  • Stream 模式:

目录:

实现效果:

1、界面上

2、代码中:上传以后,mysql中新增数据,并且,public/ upload/ excel 里面保存我们上传的文件

 这里来讲一讲他的File 模式模式的用法:

后端部分:

1、引入插件:这个插件是用来解析excel内容的必备插件

2、准备一个excel文件,如果是按照我教程的话,第九步就是下载功能的实现,入口点我

3、router文件里面配置路由

4、(非常重要)config/ config.default.js

config.default.js  加入下面的内容,注意白名单,如果你的文件类型默认没有,必须加上,不然会报错,官方解释入口

 5、app/ controller/ new/ uploadFile.js 

6、uploadFile.js

 7、serve/ common.js ,这里放给mysql库里存数据的相关代码

前端部分 vue+element:

1、封装文件:   uploadAndDown.vue

2、调用封装文件

3、上传和下载的事件

到此结束!


实现效果:

1、界面上

2、代码中:上传以后,mysql中新增数据,并且,public/ upload/ excel 里面保存我们上传的文件

 这里来讲一讲他的File 模式模式的用法:

后端部分:

1、引入插件:这个插件是用来解析excel内容的必备插件

cnpm install xlsx --save

2、准备一个excel文件,如果是按照我教程的话,第九步就是下载功能的实现,入口点我

3、router文件里面配置路由

module.exports = app => {
    //上传-批量用户数据-用的file
    app.post('/uploadUserList', controller.new.uploadFile.uploadFiles_file);
}

4、(非常重要)config/ config.default.js

config.default.js  加入下面的内容,注意白名单,如果你的文件类型默认没有,必须加上,不然会报错,官方解释入口

//上传文件所需配置
  config.multipart = {
    mode: 'file',//启用 file 模式
    fileSize: 1048576000,
    whitelist: ['.xlsx'] //白名单,把你的文件类型加上,不然会报错
  }
官方默认就有的格式
// images
'.jpg', '.jpeg', // image/jpeg
'.png', // image/png, image/x-png
'.gif', // image/gif
'.bmp', // image/bmp
'.wbmp', // image/vnd.wap.wbmp
'.webp',
'.tif',
'.psd',
// text
'.svg',
'.js', '.jsx',
'.json',
'.css', '.less',
'.html', '.htm',
'.xml',
// tar
'.zip',
'.gz', '.tgz', '.gzip',
// video
'.mp3',
'.mp4',
'.avi',

 5、app/ controller/ new/ uploadFile.js 

6、uploadFile.js

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

const fs = require('fs')
const path = require('path');
class uploadFileController extends Controller {
    /**
   * @上传文件-将excel文件数据输入到user表
   * 两种类型,file和stream
   * 这里使用的是file
   */
  async uploadFiles_file(){
    const {ctx} = this;
    const file = ctx.request.files[0]; //获取上传文件,config没有配置,这里file拿不到
    if (!file) return ctx.throw(404);
    const filename = ctx.request.body.name?ctx.request.body.name:file.filename //文件名称,如果前端没传就直接用文件的
    const distPath = path.join('', 'app/public/upload/excel');
    const stat = fs.statSync(distPath);
    if (!stat.isDirectory()) {
      fs.mkdirSync(distPath);
    }
    const targetPath = path.join('', 'app/public/upload/excel', filename);//目标文件地址
    //将上传的文件保存到本地,如果本地有就覆盖
    fs.readFile(file.filepath, function (err, data) {  // 异步读取文件内容
      fs.writeFile(targetPath, data, function (err) { // des_file是文件名,data,文件数据,异步写入到文件
        if( err ){
          console.log( '文件保存到本地失败,原因:' );
          console.log( err );
        }else{
          console.log('文件保存到本地成功');
          // 读取内容
          const workbook = xlsx.readFile(targetPath);
          const sheetNames = workbook.SheetNames; //获取表名
          const sheet = workbook.Sheets[sheetNames[0]]; //通过表名得到表对象
          // console.log(sheet);
          // console.log('111111111');thead的内容通过   打印sheet  得到
          const thead = [sheet.A1.v, sheet.B1.v, sheet.C1.v, sheet.D1.v, sheet.E1.v];
          const exceldata = xlsx.utils.sheet_to_json(sheet); //通过工具将表对象的数据读出来并转成json
          // console.log(thead);//[ '姓名', '年龄', '地址', '邮箱', '手机号' ]
          // console.log(data);//[{'姓名': '张浩','年龄': 12,'地址': '幸福1','邮箱': '1234@.qq.com','手机号': '12345678900'}]
          if(exceldata.length>0){
            //将excel数据增添到库里
            ctx.service.common.addSimCard(exceldata);
          }
        }
      });
    })
    ctx.body = {
      code:200,
      masg:'success',
      data:'上传成功'
    };

  }


}

module.exports = uploadFileController;

 7、serve/ common.js ,这里放给mysql库里存数据的相关代码

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

class CommonService extends Service {
  /**
   * 上次excel添加到mysql数据库
   * @param {Array} headers excel标题栏
   * @param {Array} result excel内容
   */
  async addSimCard(result) {
      const values = []; //[ [1,'张三','13519105845',...] ,[],[]...    ]
      result.forEach(item=> {
        let _arr = [];
        _arr[0] = parseInt(Math.random()*100000)
        _arr[1] = item['姓名']
        _arr[2] = item['手机号']
        _arr[3] = item['地址']
        _arr[4] = item['年龄']
        _arr[5] = item['邮箱']

        values.push(_arr);
      });
        
      // 重点sql语句
      const addSql = 'INSERT INTO user (id,name,phone,address,age,email) VALUES ?';
      const _result = await this.app.mysql.query(addSql, [values]);
      console.log('上传成功')
    }
 
}
module.exports = CommonService;

前端部分 vue+element:

1、封装文件:   uploadAndDown.vue

<template>
  <el-upload
    v-if="Refresh"
    class="upload-demo"
    ref="upload"
    :action="action"
    :headers="headers"
    :multiple="multiple"
    :data="data"
    :name="name"
    :with-credentials="cookieOK"
    :show-file-list="showFileList"
    :drag="drag"
    :accept="accept"
    :list-type="listType"
    :auto-upload="autoUpload"
    :file-list="fileList"
    :disabled="is_disabled"

    :on-preview="handlePreview"
    :on-remove="handleRemove"
    :on-success="handleSuccess"
    :on-error="handleError"
    :on-progress="handleProgress"
    :on-exceed="handleExceed"
    :on-change="onChange"

    :before-upload="beforeUpload"
    :before-remove="beforeRemove"
    :http-request="httpRequest"
  >
    <el-button slot="trigger" type="primary" icon="el-icon-upload2">选取文件</el-button>
    <el-button style="margin-left: 10px;"
               type="success"
               @click="submitUploadSD"
               :disabled="fileList.length==0"
               :title="fileList.length==0?'请先选中文件':''"
               icon="el-icon-upload">开始上传</el-button>
    <el-button type="danger"
               v-if="fileList.length>0"
               icon="el-icon-delete"
               @click.stop="clearFiles"
               title="清空选中文件"
               circle></el-button>
    <el-button style="margin-left: 10px;"
               type="primary"
               @click.stop="downFile"
               icon="el-icon-download">下载模板</el-button>

    <!--提示信息-->
    <div slot="tip" class="el-upload__tip" v-if="tip_text!=''">{{tip_text}}</div>
  </el-upload>

</template>

<script>
  //element的上传文件组件
  export default {
    props:{
      /**
       * 自动上传参数
       * */
      autoUpload:{ // 是否需要选取完自动上传功能
        type: Boolean,
        default: false
      },
      action:{//上传的地址
        type: String,
        default: ''
      },
      headers: {//设置上传的请求头部
        type:Object,
        default: () => {
          return {}
        }
      },
      data: {//上传时额外带的参数
        type:Object,
        default: () => {
          return {}
        }
      },
      name:{//上传的文件字段名
        type: String,
        default: 'file'
      },
      cookieOK:{//支持发送 cookie 凭证信息
        type: Boolean,
        default: true
      },
      /**
       * 公共参数
       * */
      showFileList:{//是否显示已上传文件列表
        type: Boolean,
        default: true
      },
      drag:{//是否启用拖拽上传
        type: Boolean,
        default: false
      },
      accept:{//接受文件类型-图片上传类型-不同的格式之间以逗号隔开
        type: String,
        // default:'.doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document'
        default: '.xlsx,.xls'
      },
      listType:{ // 文件列表的类型 - text/picture/picture-card
        type: String,
        default: 'text'
      },
      fileList:{//已上传的文件列表,
        type:Array,
        default: () => {
          // { 默认格式
          //   name: 'food.jpeg',
          //   url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
          // }
          return []
        }
      },
      is_disabled:{//是否禁止,true是禁止,false不禁止
        type: Boolean,
        default: false
      },
      multiple:{//是否可以多选
        type: Boolean,
        default: true
      },
      limit:{//最大允许上传个数
        type: Number,
        default: 30
      },

      tip_text:{//提示信息
        type: String,
        default: ''
      },
      /**
       * 手动上传参数
       * */
      needFromUpload:{ // form表单,将上传的file文件通过 formUpload  方法发送出去
        type: Boolean,
        default: false
      },


    },
    watch: {},
    data() {
      return {
        Refresh:true,//强制刷新
      }
    },
    created() {
    },
    mounted() {
    },
    methods: {
      /**
       * 上传-默认事件
       * */
      //文件列表移除文件时的钩子
      handleRemove(file, fileList) {
        console.log('当前移除的是'+file);
      },
      //点击文件列表中已上传的文件时的钩子
      handlePreview(file) {
        console.log('当前点击的是'+file);
      },
      //文件上传成功时的钩子
      handleSuccess(response, file, fileList) {
        console.log('文件上传成功');
      },
      //文件上传失败时的钩子
      handleError(err, file, fileList) {
        console.log('文件上传失败');
      },
      //文件上传时的钩子
      handleProgress(event, file, fileList) {
        console.log(file);
      },
      //文件超出个数限制时的钩子
      handleExceed(files, fileList) {
        console.log('文件超出个数限制');
      },
      //覆盖默认的上传行为,可以自定义上传的实现
      httpRequest(){

      },
      //删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止删除。
      beforeRemove(file, fileList) {
        console.log('当前删除的文件'+file);
        this.fileList.forEach((item,index)=>{
          if(item == file){
            this.fileList.splice(index,1)
          }
        })
      },

      /**
       * 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用
       */
      onChange(file, fileList) {
        this.fileList = fileList;
        console.log('当前的选中文件:');
        console.log(fileList);
      },
      /**
       * 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传。
       */
      beforeUpload(file) {
        console.log(file);
      },
      /**
       * 上传-自定义事件
       * */
      submitUpload() {
        this.$refs.upload.submit();
      },
      //清空已上传的文件列表(该方法不支持在 before-upload 中调用)
      clearFiles(){
        this.$refs.upload.clearFiles();
        this.fileList = [];
      },
      //取消上传某个文件
      abortFiles(file){
        this.$refs.upload.abort(file);
      },



      /**
       * 手动上传点击确认
       * */
      submitUploadSD(){
        let arr = this.fileList;
        let str = {
          fileList:arr
        }
        this.$emit('uploadFile',str);
      },
      /**
       * 下载模板点击
       * */
      downFile(){
        this.$emit('downFile');
      },
      /**
       * 手动刷新上传组件
       * */
      RefreshUpload(){
        let arr = this.fileList;
        this.Refresh = false;
        this.$nextTick(()=>{
          this.Refresh = true;
        })
      },

    },
    components: {},
    beforeDestroy() {
    }

  }
</script>

<style lang='scss' scoped>

</style>

2、调用封装文件

<upload-and-down 
    class="uploadAndDown" 
    @uploadFile="uploadFile" 
    @downFile="downFile">
</upload-and-down>

3、上传和下载的事件

      /**
       * 上传
       * */
      uploadFile(str){
        let fileList = str.fileList;
        let formData = new FormData
        fileList.forEach(item=>{
          formData.append('file',item.raw)
        })
        this.$axios({
          method:'post',
          url:'http://localhost:7001/uploadUserList',
          data:formData,
          headers:{
            'Content-Type': 'application/x-www-form-urlencoded'
          }
        }).then(res => {
          this.$message.success('上传成功')
        })
      },
      //下载事件
      downFile(){
        console.log('点击下载按钮');
        // 创建隐藏的可下载链接
        var eleLink = document.createElement('a');
        eleLink.style.display = 'none';
        eleLink.href = 'http://localhost:7001/toexecl';
        // 触发点击
        document.body.appendChild(eleLink);
        eleLink.click();
        // 然后移除
        document.body.removeChild(eleLink);
      }

到此结束!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值