在开发的过程中,上传文件或者导入数据是一件很常见的事情,导入数据可以有两种方式:

  1. 前端上传文件到后台,后台读取文件内容,进行验证再进行存储
  2. 前端读取数据,进行数据验证,然后发送数据到后台进行存储

这两种方式需要根据不同的业务才进行采用

这次用.Net6.0+Vue3来实现一个数据导入的功能

接下来分别用代码来实现这两种方式

1. 前端上传文件到后台进行数据存储

1.1编写文件上传接口

        [DisableRequestSizeLimit]
[HttpPost]
public IActionResult Upload()
{
var files = Request.Form.Files;
long size = files.Sum(f => f.Length); string contentRootPath = AppContext.BaseDirectory;
List<string> filenames = new List<string>();
foreach (IFormFile formFile in files)
{
if (formFile.Length > 0)
{
string fileExt = Path.GetExtension(formFile.FileName);
long fileSize = formFile.Length;
string newFileName = System.Guid.NewGuid().ToString() + fileExt;
var filePath = contentRootPath + "/fileUpload/";
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
using (var stream = new FileStream(filePath + newFileName, FileMode.Create))
{
formFile.CopyTo(stream);
}
filenames.Add(newFileName);
}
}
return Ok(filenames);
}

这里只是上传文件分了两步走,第一步把文件上传到服务器,第二步调用接口把返回的文件路径发送给后台进行数据保存

1.2存储上传文件路径,读取数据并进行存储

  /// <summary>
/// 上传文件数据
/// </summary>
/// <param name="uploadStuInfoInput"></param>
/// <returns></returns>
[HttpPut]
public IActionResult Put(DataInput uploadStuInfoInput)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "fileUpload", uploadStuInfoInput.filePath);
if (!System.IO.File.Exists(filePath))
{
return BadRequest("导入失败,文件不存在!");
}
var row = MiniExcelLibs.MiniExcel.Query<CompanyImportInput>(filePath).ToList();
companies.AddRange(row.Select(x => new Company { Name = x.名称, Address = x.地址 }));
return Ok("导入成功!");
}

1.3前端Vue建立创建列表数据页面,包含表格功能及分页功能

<el-table :data="state.tableData.data">
      <el-table-column v-for="item in state.colunm" :prop="item.key" :key="item.key" :label="item.lable">
      </el-table-column>
    </el-table>
 <div class='block flex justify-end' v-if='state.tableData.total > 0'>
      <el-pagination v-model:currentPage="state.searchInput.PageIndex" v-model:page-size="state.searchInput.PageSize"
        :page-sizes="[10, 50, 200, 1000]" layout="total, sizes, prev, pager, next, jumper" @size-change="getData"
        @current-change="getData" :total="state.tableData.total" />
    </div>

1.4调用接口获取表格数据方法

 const getData = () => {
      axios.get('/Company', { params: state.searchInput }).then(function (response) {
        state.tableData = response.data;
      })
    }

1.5后台开发数据返回接口

        [HttpGet]
public dynamic Get([FromQuery] SelectInput selectInput)
{
return new
{
total = companies.Count(),
data = companies.Skip((selectInput.pageIndex - 1) * selectInput.pageSize).Take(selectInput.pageSize).ToList()
};
}

1.6主页面创建上传文件组件并进行引用

import FileUpload from '@/components/FileUpload.vue'; 

并绑定子页面回调方法fileUploadchildClick

  <FileUpload ref="fileUpload" @childClick="fileUploadchildClick" accept=".xlsx" title="上传文件"></FileUpload>

1.7FleUpload页面主要上传文件到服务器,并回调父页面存储接口

 <el-dialog :close-on-click-modal="false" v-model="state.dialogVisible" :title="title" width="40%">
    <el-form :model='state.formData' label-width='130px' class='dialogForm'>
      <el-upload class='upload-demo' :limit="1" drag :accept='accept' :file-list='state.fileList' :show-file-list='true'
        :on-success='fileUploadEnd' :action='fileUploadUrl()'>
        <i class='el-icon-upload'></i>
        <div class='el-upload__text'>将文件拖到此处,或<em>点击上传</em></div>
        <div class='el-upload__tip'>请选择({{  accept  }})文件</div>
      </el-upload>
      <div>
        <el-form-item>
          <el-button type='primary' @click='submit'>导入</el-button>
          <el-button @click='cancel'>取消</el-button>
        </el-form-item>
      </div>
    </el-form>
  </el-dialog>

1.8这里的title,accept参数由父页面传值过来,可以进行组件复用

选择文件成功回调方法

 const fileUploadEnd = (response, file) => {
      state.fileresponse = file.name;
      state.formData.filePath = response[0];
      if (state.fileList.length > 0) {
        state.fileList.splice(0, 1);
      }
    }

1.9提交保存时回调父页面存储数据方法

const submit = () => {
      if (state.formData.filePath == '') {
        ElMessage.error('请选择上传的文件')
        return;
      }
      context.emit('childClick', state.formData)
    }

1.10父页面方法调用接口进行数据存储,存储成功后关闭子页面

 const fileUploadchildClick = (e) => {
      axios.put('/Company', {
        filePath: e.filePath,
      }).then(function (response) {
        if (response.status == 200) {
          ElMessage.success(response.data);
          fileUpload.value.cancel();
          getData();
        } else {
          ElMessage.error(response.data)
        }
      })
    }

1.11后台数据存储接口

 /// <summary>
/// 上传文件数据
/// </summary>
/// <param name="uploadStuInfoInput"></param>
/// <returns></returns>
[HttpPut]
public IActionResult Put(DataInput uploadStuInfoInput)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "fileUpload", uploadStuInfoInput.filePath);
if (!System.IO.File.Exists(filePath))
{
return BadRequest("导入失败,文件不存在!");
}
var row = MiniExcelLibs.MiniExcel.Query<CompanyImportInput>(filePath).ToList();
companies.AddRange(row.Select(x => new Company { Name = x.名称, Address = x.地址 }));
return Ok("导入成功!");
     }

2前端读取数据,发送读取数据到后台进行数据存储

2.1创建上传数据组件并引用

import DataUpload from '@/components/DataUpload.vue';

并绑定子页面回调方法dataUploadchildClick

<DataUpload ref="dataUpload" @childClick="dataUploadchildClick" accept=".xlsx" title="上传数据"></DataUpload>

2.2DataUpload页面主要读取选择文件数据,并进行展示

<el-dialog :close-on-click-modal="false" v-model="state.dialogVisible" :title="title" width="50%">
    <el-upload class="upload-demo" :action='accept' drag :auto-upload="false" :on-change="uploadChange" :limit="1">
      <i class="el-icon-upload"></i>
      <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
    </el-upload>
    <div>
      <el-form-item>
        <el-button @click='submit'>确认导入</el-button>
      </el-form-item>
    </div>
    <el-table :data="state.tableData.data">
      <el-table-column v-for="item in state.colunm" :prop="item.key" :key="item.key" :label="item.lable">
      </el-table-column>
    </el-table>
    <div class='block flex justify-end' v-if='state.tableData.total > 0'>
      <el-pagination v-model:currentPage="state.searchInput.PageIndex" v-model:page-size="state.searchInput.PageSize"
        :page-sizes="[10, 50, 200, 1000]" layout="total, sizes, prev, pager, next, jumper" @size-change="getData"
        @current-change="getData" :total="state.tableData.total" />
    </div>
  </el-dialog>

2.3文件上传成功方法,保存数据到临时变量进行分页处理

const uploadChange = async (file) => {
      let dataBinary = await readFile(file.raw)
      let workBook = XLSX.read(dataBinary, { type: 'binary', cellDates: true })
      let workSheet = workBook.Sheets[workBook.SheetNames[0]]
      let data: any = XLSX.utils.sheet_to_json(workSheet)       let tHeader = state.colunm.map(obj => obj.lable)
      let filterVal = state.colunm.map(obj => obj.key)
      tHeader.map(val => filterVal.map(obj => val[obj]))
      const tempData: any = [];
      data.forEach((value) => {
        const ob = {};
        tHeader.forEach((item, index) => {
          ob[filterVal[index]] = value[item].toString();
        })
        tempData.push(ob);
      })
      state.tempTableData = tempData;
      getData();
    }

2.4数据绑定到表格上,这里需要通过当前选择页码及页面显示数量处理需要绑定到表格上的数据

const getData = () => {
      const tempData: any = [];
      state.tempTableData.forEach((value, index) => {
        if (index >= ((state.searchInput.PageIndex - 1) * state.searchInput.PageSize) && index < ((state.searchInput.PageIndex) * state.searchInput.PageSize)) {
          tempData.push(value);
        }
      });
      state.tableData.data = tempData;
      state.tableData.total = state.tempTableData.length;
    }

2.5点击确认导入按钮回调父页面方法进行数据保存

const submit = () => {
      context.emit('childClick', state.tempTableData)
    }

2.6父页面方法调用接口进行数据存储,存储成功后关闭子页面

const dataUploadchildClick = (data) => {
      axios.post('/Company', data)
        .then(function (response) {
          if (response.status == 200) {
            ElMessage.success(response.data);
            dataUpload.value.cancel();
            getData();
          } else {
            ElMessage.error(response.data)
          }
        })
    }

2.7后台数据存储接口

  /// 上传数据
/// </summary>
/// <param name="uploadStuInfoInput"></param>
/// <returns></returns>
[HttpPost]
public IActionResult Post(List<Company> companiesInput)
{
companies.AddRange(companiesInput);
return Ok("保存成功!"); }

最后关于这个数据导入的功能就完成了,代码中有很多得伪代码,而且很多功能还待完善,后续再进行补充

附上git地址:https://gitee.com/wyf854861085/file-upload.git

Git演示图:

.Net+Vue3实现数据简易导入功能的更多相关文章

  1. [Django]数据批量导入

    前言:历经一个月的复习,考试终于结束了.这期间上班的时候有研究了Django网页制作过程中,如何将数据批量导入到数据库中. 这个过程真的是惨不忍睹,犯了很多的低级错误,这会在正文中说到的.再者导入数据 ...

  2. .Net之Nopi Excel数据导出和批量导入功能

    一.介绍NPOI和编写demo的原因 1.Npoi是什么: 它是一个专门用于读写Microsoft Office二进制和OOXML文件格式的.NET库,我们使用它能够轻松的实现对应数据的导入,导出功能 ...

  3. c#直接调用ssis包实现Sql Server的数据导入功能

    调用ssis包实现Sql Server的数据导入功能网上已经有很多人讨论过,自己参考后也动手实现了一下,上一次笔者的项目中还用了一下这个功能.思前想后,决定还是贴一下增强记忆,高手请54. 1.直接调 ...

  4. 解析大型.NET ERP系统 设计通用Microsoft Excel导入功能

    做企业管理软件很难避免与Microsoft Excel打交道,常常是软件做好了,客户要求说再做一个Excel导入功能.导入Excel数据的功能的难度不大,从Excel列数据栏位的取值,验证值,再导入到 ...

  5. 基于Metronic的Bootstrap开发框架经验总结(7)--数据的导入、导出及附件的查看处理

    在很多系统模块里面,我们可能都需要进行一定的数据交换处理,也就是数据的导入或者导出操作,这样的批量处理能给系统用户更好的操作体验,也提高了用户录入数据的效率.我在较早时期的EasyUI的Web框架上, ...

  6. 循序渐进开发WinForm项目(5)--Excel数据的导入导出操作

    随笔背景:在很多时候,很多入门不久的朋友都会问我:我是从其他语言转到C#开发的,有没有一些基础性的资料给我们学习学习呢,你的框架感觉一下太大了,希望有个循序渐进的教程或者视频来学习就好了. 其实也许我 ...

  7. 027医疗项目-模块二:药品目录的导入导出-导入功能的Action的编写

    前一篇文章我们写了Service层,这篇文章我们写一下Action层. 实现的功能: 1:我们先下载模板:然后按照模板里面的规则,插入数据.比如存在d盘. 2:然后浏览找到那个文件,上传上去. 然后把 ...

  8. 026医疗项目-模块二:药品目录的导入导出-导入功能的Service的编写

    这个导入功能要实现的效果是: 思路是: 因为我们最后是在Action层中调用的HxlsRead工具,这个工具传入的就是我们要实现的上一篇文章说到的实现了HxlsOptRowsInterface接口的类 ...

  9. php做EXCEL数据导出导入开发的一些小问题

    前两天刚刚做开发CRM系统项目,在做要做EXCEL导出导入功能,因为以前做.NET开发用的是NPOI,但可是没找到PHP版本的,所以就网搜找了个国外的开源PHPEXCEL , 一开始只是做了简单的导入 ...

随机推荐

  1. Go写文件的权限 WriteFile(filename, data, 0644)?

    本文来自博客园,作者:阿伟的博客,转载请注明原文链接:https://www.cnblogs.com/cenjw/p/go-ioutil-writefile-perm.html 前言 go iouit ...

  2. python基础知识-day6(函数知识)

    1.函数的特点 函数式的编程范式 面向对象的编程范式 所谓函数,就是把重复的代码单独的分离出来,放在一个公共的地方,以后可以一只调用,这样就可以解决多次重复来编写. 2.函数的定义 1 def fun ...

  3. docker-compose: 未找到命令,安装docker-compose

    1.安装扩展源 sudo yum -y install epel-release 2.安装python-pip模块 sudo yum install python-pip 3.通过命令进行安装 cd ...

  4. 使用Scrcpy投屏

    下载Scrcpy: https://wwt.lanzouw.com/iAzie07bz85c官网地址: https://github.com/Genymobile/scrcpy 记录当前下载位置: 手 ...

  5. C语言整形转字符串的方法

    今天写力扣第九题,里面用到了这个,就做个笔记.   1. char *itoa( int value, char *string,int radix);(stdlib.h)     Windows特有 ...

  6. 【.NET基础】Linq常用语法代码演示

    前言:前言不重要,linq入门常用的语法,linq语法可以用来写操作集合.数据库表集合等等几乎所有集合类型的操作.下面就写几个案例(以List集合来做的),看代码和运行结果即可. 本文演示环境:VS2 ...

  7. 牛客SQL刷题第一趴——非技术入门基础篇

    user_profile表: id device_id gender age university province 1 2138 male 21 北京大学 Beijing 2 3214 male   ...

  8. CodeQL使用流程

    前言 好久没用CodeQL了,看了自己之前写的文章发现竟然没有做过相关记录 然后就不知道怎么用了hhh 使用流程 0x1 生成数据库 我们拿到一套源码,首先需要使用CodeQL生成数据库 执行命令: ...

  9. Class对象共嫩

    需求:写一个"框架",不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法 实现: 1.配置文件 2.反射 步骤: 1.将需要创建的对象的全类名和需要执 ...

  10. Stream流中的常用方法

    count package com.yang.Test.StreamStudy; import java.util.stream.Stream; /** * 统计荷属:count * 正如旧集合Col ...