后端abp,前端vue导入excel,开始准备用直接用npoi,觉得要写太多的代码,就算从以前的复制粘贴也麻烦,所以偷懒直接用别人的轮子

Magicodes.IE。这样可以节省很多工作,根据实体生成excel模板、支持枚举、导入时自动验证数据是否合法(必填、类型等)


Excel模板

要导入首先要有录入数据的excel模板,以前都是把模板做好,放到服务器上,给一个下载链接给用户下载,这里可以直接用对象动态生成模板。

    //ExcelAppService.cs
/// <summary>
/// 生成excel模板
/// </summary>
/// <typeparam name="T">模板内容实体</typeparam>
/// <param name="fileName">下载文件名称</param>
/// <returns>输出文件流</returns>
internal async Task<FileContentResult> GetTemplate<T>(string fileName = "模板") where T : class, new()
{
byte[] fileBytes = await importer.GenerateTemplateBytes<T>(); return new FileContentResult(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet)
{
FileDownloadName = $"{fileName}.xlsx"
};
}

importer是在构造函数中注入的IImporter类型,如果你使用注入需要先在module的Initialize()方法中注册。

//module.Initialize()方法
IocManager.Register<Magicodes.ExporterAndImporter.Core.IImporter, Magicodes.ExporterAndImporter.Excel.ExcelImporter>(DependencyLifeStyle.Transient);

你也可以直接使用

IImporter importer=new ExcelImporter()

生成模板就做完了,剩下的就是在需要下载的地方调用此方法,公开一个api接口就可以了

/// <summary>
/// 下载导入模板
/// </summary>
/// <returns></returns>
public async Task<ActionResult> GetTemplate()
{
return await excelAppService.GetTemplate<XXXXImportExcelDto>();
}

XXXXImportExcelDto是导入的实体类型,具体定义方式可以见https://github.com/xin-lai/Magicodes.IE

如果你用的abp官方提供的vue项目,使用的axios请求后端,也就是ajax请求,这个文件流是不会弹出保存文件框的,需要在axios请求后拦截文件流弹出下载框。找到src\lib\ajax.ts文件,修改ajax.interceptors.response方法,并添加一个downloadUrl方法

ajax.interceptors.response.use((respon)=>{
++ //拦截文件下载请求
++ if (respon.headers && (respon.headers['content-type'] === 'application/octet-stream')) {
++ downloadUrl(respon.request.responseURL)
++ respon.data='';
++ respon.headers['content-type'] = 'text/json'
++ return respon;
++ }
return respon
},(error)=>{
if(!!error.response&&!!error.response.data.error&&!!error.response.data.error.message&&error.response.data.error.details){
vm.$Modal.error({title:error.response.data.error.message,content:error.response.data.error.details})
}else if(!!error.response&&!!error.response.data.error&&!!error.response.data.error.message){
vm.$Modal.error({title:window.abp.localization.localize("LoginFailed"),content:error.response.data.error.message})
}else if(!error.response){
vm.$Modal.error(window.abp.localization.localize('UnknownError'));
}
setTimeout(()=>{
vm.$Message.destroy();
},1000);
return Promise.reject(error);
})
++const downloadUrl = url => {
++ let iframe = document.createElement('iframe')
++ iframe.style.display = 'none'
++ iframe.src = url
++ iframe.onload = function () {
++ document.body.removeChild(iframe)
++ }
++ document.body.appendChild(iframe)
++}

导入excel

导入分为两步:上传excel文件和解析数据。由于没有找到一个一次能处理这两步的方法(因为需要指定解析后的类型,这是一个强类型参数),我采用的方式是:

  1. 加一个自定义组件,主要用于上传,提供一个上传完成事件,在上传完成后触发事件并传入后台excel文件的名称,
  2. 使用的地方绑定事件并把带着文件名请求后台,
  3. 后台再调用通用方法的解析数据

定义组件

<template>
<div>
<Upload
:action="uploadURL"
:on-success="onSuccess"
accept=".xls, .xlsx"
:show-upload-list="false"
>
<Button icon="android-add" type="primary">{{btnTitle}}</Button>
</Upload>
</div>
</template> <script lang="ts">
import { Component, Vue, Inject, Prop, Watch } from "vue-property-decorator";
import Util from "../../lib/util";
import AbpBase from "../../lib/abpbase";
import appconst from "../../lib/appconst"; @Component
export default class ImportExcel extends AbpBase {
uploadURL =
appconst.remoteServiceBaseUrl + "/api/services/app/Excel/UploadExcelFile";
async onSuccess(response, file, fileList) {
//上传完成触发事件uploadCompleted
this.$emit("uploadCompleted", response.result);
}
/**按钮显示内容 */
@Prop({ type: String, default: "" }) btnTitle: String;
}
</script>
<style lang="less" scoped>
</style>

后端接收文件方法

    //ExcelAppService.cs
/// <summary>
/// 接收上传文件方法
/// </summary>
/// <param name="file">文件内容</param>
/// <returns>文件名称</returns>
public async Task<string> UploadExcelFile(IFormFile file)
{
//FileDir是存储临时文件的目录,相对路径
//private const string FileDir = "/File/ExcelTemp";
string url = await WriteFile(file, FileDir); string fullpath = Path.GetFullPath($"{Environment.CurrentDirectory}" + url); return Path.GetFileName(url);
}
/// <summary>
/// 写入文件
/// </summary>
/// <param name="avatar"></param>
/// <param name="reDir"></param>
/// <returns></returns>
public async Task<string> WriteFile(IFormFile avatar, string reDir)
{
string reName = Guid.NewGuid() + Path.GetExtension(avatar.FileName);
string dir = GetDirPath(reDir);
string path = $"{dir}\\{reName}";
Stream stream = avatar.OpenReadStream();
using (FileStream fileStream = new FileStream(path, FileMode.Create))
{
await avatar.CopyToAsync(fileStream);
}
return $"{reDir}/{reName}";
}
public string GetDirPath(string reDir)
{
string dir = $"{Environment.CurrentDirectory}/{reDir}";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
return Path.GetFullPath(dir);
}

使用组件

<template>
<ImprotExcel @uploadCompleted="importExcel" :btnTitle="'导入excel'" ></ImprotExcel>
</template>
<script>
async importExcel(fileName: string) {
//请求后端api
await this.$store.dispatch({
type: "xxx/importExcel",
data: { fileName: fileName, labId: this.labId }
});
(<any>this.$Message).success({ background: true, content: "导入成功" });
}
</script>

后端解析文件方法

    /// <summary>
/// 导入
/// </summary>
/// <param name="input">导入excel参数</param>
/// <returns></returns>
[HttpPost]
public async Task ImportExcel(XXXImprotExcelInput input)
{
var data = await excelAppService.GetData<XXXImportExcelDto>(input.FileName);
if (!data.Any())
{
return;
}
//你的逻辑
} //XXXImprotExcelInput.cs
/// <summary>
/// 导入excel
/// </summary>
public class XXXImprotExcelInput
{
/// <summary>
/// 上传的excel文件名称
/// </summary>
public string FileName { get; set; }
//你的其他参数
}
//ExcelAppService.cs
/// <summary>
/// 解析excel数据
/// </summary>
/// <typeparam name="T">要解析的数据类型</typeparam>
/// <param name="fileName">excel文件名称,不含路径</param>
/// <returns></returns>
internal async Task<IEnumerable<T>> GetData<T>(string fileName) where T : class, new()
{
var fullpath = GetFullPath(fileName);
var result = await importer.Import<T>(fullpath);
if (result.HasError)
{
var errFile = Path.GetFileNameWithoutExtension(fileName) + "_" + Path.GetExtension(fileName);
//如果excel文件内容不符合要求(格式错误、必填数据未填、数据类型错误),则弹出错误提示并给出下载链接
throw new UserFriendlyException("导入错误", GetErrorExcelDownLoadUrl(errFile));
}
return result.Data;
}
/// <summary>
/// 下载excel文件
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
[HttpGet]
public async Task<FileContentResult> DownLoadFile(string fileName)
{
var fullPath = GetFullPath(fileName);
byte[] fileBytes = await File.ReadAllBytesAsync(fullPath);
return new FileContentResult(fileBytes, System.Net.Mime.MediaTypeNames.Application.Octet)
{
FileDownloadName = fileName
};
}
/// <summary>
/// 获取文件全路径
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private string GetFullPath(string fileName)
{
fileName = Path.GetFileName(fileName);
var fullpath = Path.GetFullPath(Environment.CurrentDirectory.EnsureEndsWith('/') + FileDir.EnsureEndsWith('/') + fileName);
return fullpath;
}
/// <summary>
/// 获取excel下载链接
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
private string GetErrorExcelDownLoadUrl(string fileName)
{
return $"请按照excel文件内的错误提示修改后再次导入,<a href='{GetHost()}/api/services/app/Excel/DownLoadFile?fileName={fileName}' target='_blank'>点击下载excel</a>"
;
}
/// <summary>
/// 获取当前域名地址
/// </summary>
/// <returns></returns>
private string GetHost()
{
var req = httpContextAccessor.HttpContext.Request;
return $"{req.Scheme}://{req.Host}";
}

参考资料

abp_vue导入导出excel的更多相关文章

  1. ASP.NET Core 导入导出Excel xlsx 文件

    ASP.NET Core 使用EPPlus.Core导入导出Excel xlsx 文件,EPPlus.Core支持Excel 2007/2010 xlsx文件导入导出,可以运行在Windows, Li ...

  2. thinkphp导入导出excel表单数据

    在PHP项目经常要导入导出Excel表单. 先去下载PHPExcel类库文件,放到相应位置. 我在thinkphp框架中的位置为ThinkPHP/Library/Org/Util/ 导入 在页面上传e ...

  3. 导入导出Excel工具类ExcelUtil

    前言 前段时间做的分布式集成平台项目中,许多模块都用到了导入导出Excel的功能,于是决定封装一个ExcelUtil类,专门用来处理Excel的导入和导出 本项目的持久化层用的是JPA(底层用hibe ...

  4. php中导入导出excel的原理

    在php中我们要经常导入导出excel文件,方便后台管理.那么php导入和导出excel的原理到底是什么呢?excel分为两大版本excel2007(后缀.xlsx).excel2003(后缀.xls ...

  5. NPOI导入导出EXCEL通用类,供参考,可直接使用在WinForm项目中

    以下是NPOI导入导出EXCEL通用类,是在别人的代码上进行优化的,兼容xls与xlsx文件格式,供参考,可直接使用在WinForm项目中,由于XSSFWorkbook类型的Write方法限制,Wri ...

  6. .NET导入导出Excel

    若是开发后台系统,ASP.NET MVC中总是涉及了很多导入导出Excel的问题,有的时候处理起来比较烦 如果能使用以下代码解决,就完美了 public class ReportModel { [Ex ...

  7. Java利用POI导入导出Excel中的数据

         首先谈一下今天发生的一件开心的事,本着一颗android的心我被分配到了PB组,身在曹营心在汉啊!好吧,今天要记录和分享的是Java利用POI导入导出Excel中的数据.下面POI包的下载地 ...

  8. .Net MVC 导入导出Excel总结(三种导出Excel方法,一种导入Excel方法) 通过MVC控制器导出导入Excel文件(可用于java SSH架构)

    .Net MVC  导入导出Excel总结(三种导出Excel方法,一种导入Excel方法) [原文地址] 通过MVC控制器导出导入Excel文件(可用于java SSH架构)   public cl ...

  9. jxl导入/导出excel

    1.jxl导入/导出excel案例,黏贴即可运行 package junit.test; import java.io.File; import java.io.IOException; import ...

随机推荐

  1. dt系统中tag如何使用like与%来进行模糊查询

    在destoon中,如果一个品牌的详细显示页,如果要显示与品牌相关的供应的话,可以通过查询标题中带有品牌关键字的这一条件来进行查询,但是经过测试发现不能正确解析, 然后查看文件的源文件,发现 {tag ...

  2. MySQL——时间戳和时间的转化

    前言 Mysql中时间戳和时间的转化 时间转时间戳 select unix_timestamp('2019-7-29 14:23:25'); 时间戳转时间 select from_unixtime(1 ...

  3. MySql添加字段命令

    使用ALTER TABLE命令来向一个表添加字段,示例如下: -- 向t_user表添加user_age字段 ) DEFAULT NULL COMMENT '年龄' AFTER user_email; ...

  4. 输入一个正整数n,生成一张2的乘方表,输出2*0—2*n的值。

    #include<stdio.h>#include<math.h> //程序中调用幂函数pow(),需包含头文件math.h//void main(){ int i,n; pr ...

  5. LeetCode 785. Is Graph Bipartite?

    原题链接在这里:https://leetcode.com/problems/is-graph-bipartite/ 题目: Given an undirected graph, return true ...

  6. CSP2019 J组 游记

    结果 分数出来了.100+100+10+35=245. 一等线230,擦着边进一等. (点击图片放大) 期待明年s组的表现. 第一轮 不就是初赛吗?擦边轻松水过去! 第二轮 Day -14 停两周晚自 ...

  7. asp.net Web 项目的文件/文件夹上传下载

    以ASP.NET Core WebAPI 作后端 API ,用 Vue 构建前端页面,用 Axios 从前端访问后端 API ,包括文件的上传和下载. 准备文件上传的API #region 文件上传  ...

  8. JavaScript开发——文件夹的上传和下载

    我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 首先我们需要了解的是上传文件三要素: 1.表单提交方式:post (get方式提交有大小 ...

  9. Nodejs中的JavaScript

    一.Ecmascript ①基本语法:if var function Object Array等 ②特别注意:Node.js中没有DOM和BOM 二.核心模块: 1.Node.js为JavaScrip ...

  10. 【JZOJ6217】【20190614】最大面积

    题意 平面上有\(n\)个点\(A_i\),\(q\)次询问,每次给出一个点\(P\),求: \[ \sum_{i=L}^{R} 2S_{\triangle OPA_i} \] 最大值,其中$S_{\ ...