前言: 最近做项目遇到了一个需求,上传Excel获取数据更新Excel文档,并直接返回更新完的Excel到前端下载;其实需求并没有什么问题,关键是前端用到的是layui上传组件(layui.upload)踩了不少坑啊;为此写下了如下笔记:

(一)后端:

  public async Task<string> UploadExcelUpdateExcel()
{
var file = Request.Form.Files.FirstOrDefault();//这里只获取一个文件
if (file == null)
throw new UserFriendlyException(L("File_Empty_Error")); long fileSize = file.Length;
if (fileSize > )
throw new UserFriendlyException(L("File_SizeLimit_Error")); string fileExtension = Path.GetExtension(file.FileName).ToLower();
//限定只能上传xls和xlsx
string[] allowExtension = { ".xls", ".xlsx" }; //上传文件类型不正确
if (!allowExtension.Any(x => x == fileExtension))
throw new UserFriendlyException(L("File_Invalid_Type_Error")); //获取本机储存地址
var filePath = Path.Combine(_hostingEnvironment.WebRootPath, "uploadfiles", file.FileName); //写入cookie
var httpContext = IocManager.Instance.Resolve<IHttpContextAccessor>().HttpContext; try
{
var memoryStream = new MemoryStream(); //创建工作台
IWorkbook workbook = null;
//操作Excel
using (var fileStream = file.OpenReadStream())
{
//判断版本2007版本.xlsx,2003版本.xls
if (fileExtension == ".xlsx")
workbook = new XSSFWorkbook(fileStream);
else
workbook = new HSSFWorkbook(fileStream);
//获取第一个sheet
ISheet sheet = workbook.GetSheetAt();
IRow rowSour;//定义行数据
//定义要修改的列索引
var cellIndex = new int[] { , };
//获取第一行的数据
var firstSour = sheet.GetRow();
var input = new ImportExcelSourInput();
input.BeginDate = Convert.ToDateTime(firstSour.GetCell().ToString()).AddMonths(-);
input.EndDate = Convert.ToDateTime(firstSour.GetCell().ToString()).AddMonths(-);
//获取数据源
var usersSour = await _basicSalaryAppService.ImportExcelSourServices(input); //遍历所有行
var cells = sheet.GetRow().PhysicalNumberOfCells;
for (var i = ; i <= sheet.LastRowNum; i++)
{
rowSour = sheet.GetRow(i);
if (rowSour == null || cells != rowSour.PhysicalNumberOfCells)
break;
//获取第三列的这个人的身份证
var IDCard = rowSour.GetCell().ToString();
var thisSour = usersSour.Where(s => s.IDCard == IDCard).FirstOrDefault();
//修改本期收入,住房公积金
if (thisSour != null)
{
rowSour.GetCell(cellIndex[]).SetCellValue(Convert.ToDouble(thisSour.ShouldSalary));
rowSour.GetCell(cellIndex[]).SetCellValue(Convert.ToDouble(thisSour.PublicAccumulationFundsDeduction));
}
else
{
var Name = rowSour.GetCell().ToString();
throw new UserFriendlyException($"系统中:[ {Name} ] 身份证号:( {IDCard} )与Excel数据不一致,请修正员工档案数据!");
}
}
//写入流
workbook.Write(memoryStream);
//恢复起始位置
memoryStream.Position = ;
//关闭
fileStream?.Close();
workbook?.Close();
}
//保存至本地
using (var fileStm = new FileStream(filePath, FileMode.Create))
{
memoryStream.WriteTo(fileStm); fileStm.Dispose();
}
}
catch (Exception e)
{
httpContext.Response.Cookies.Append("xinzi_message", Convert.ToBase64String(Encoding.UTF8.GetBytes($"上传错误!错误消息:{e.Message}")), new CookieOptions
{
Expires = DateTime.Now.AddMinutes()
}); throw new UserFriendlyException($"上传错误!错误消息:{e.Message}");
} var path = $"{httpContext.Request.Scheme}://{httpContext.Request.Host.Value}/uploadfiles/{file.FileName}";
return path;//文件路径;
}

后端上传服务代码

(二)前端:

  //读取cookies
function getCookie(name) {
var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
if (arr = document.cookie.match(reg))
return unescape(arr[2]);
else
return null;
} upload.render({
elem: '#upload-salary'
, url: 'UploadExcelUpdateExcel'
, acceptMime: ".xlsx,.xls"
, before: function (obj) {
abp.ui.setBusy("body") //上传loading
}
, type: "file"
, accept: 'file' //普通文件
, done: function (res) {
var a = document.createElement('a');
a.download = "导出文件名";
a.href = res.result;
$("body").append(a);
a.click();
abp.ui.clearBusy("body") //关闭loading
}
, error: function () {
var base = new Base64();
//获取后端写入的cookie message
var msg = getCookie("xinzi_message");
if (msg != null)
abp.message.error(base.decode(msg));
abp.ui.clearBusy("body") //关闭loading
}
});

前端渲染代码

  存在的问题:

    1),layui.upload上传组件成功后,返回类型应该是不支持返回流文件下载(欢迎大佬们指正解决方案),无奈之举我只有在后端生成好填充完数据的Excel表格,返回服务器文件路径下载了;

    2),layui.upload上传组件失败的时候,服务器端抛出异常消息,前端无法展示,失败回调函数只有两个参数(当前文件的索引,上传函数,官网解释如下图),没有返回参数!(我去什么情况,淡淡的忧桑啊!)

   百般思考终于有了如下解决方案:

      a.后端catch捕获到异常消息后,将异常消息填充到响应的Cookie中;前端异常回调函数里获取Cookie来获取后端传来的消息异常。前后端代码示例:

      b.此时layui默认的上传失败回调函数,会抛出一个消息框上传失败,这里就需要手动改下upload.js的失败回调消息提示了,我是把默认的消息提示删了;

  注:后端返回中文消息前端可能会有显示问题,我个人是后端base64加密,前端解密来完成显示的;

 /**
*
* Base64 encode / decode
*
* @author haitao.tu
* @date 2010-04-26
* @email tuhaitao@foxmail.com
*
*/ function Base64() { // private property
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; // public method for encoding
this.encode = function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
} // public method for decoding
this.decode = function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = _utf8_decode(output);
return output;
} // private method for UTF-8 encoding
_utf8_encode = function (string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
} }
return utftext;
} // private method for UTF-8 decoding
_utf8_decode = function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if ((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i + 1);
c3 = utftext.charCodeAt(i + 2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}

前端base64解密,js代码

layui上传Excel更新数据并下载的更多相关文章

  1. Layui上传文件以及数据表格

    layui对于一些前端小白来说,例如我,真的非常的好用,不用去花很多很多的心思在前端美化中,并且提高了很大的工作效率.所以建议一些觉得自己前端技术不是很强,但是想让前端美化一点的可以使用layui. ...

  2. 使用phpExcel批量上传excel表数据到mysql数据库中

    /*批量上传数据*/ if(isset($_POST['submit']) && $_POST['submit']=='上传文件') { //导入类文件 require_once (& ...

  3. 上传excel数据到数据库中

    上传excel表格数据到数据库 导入固定路径下的excel数据到数据库 <form id="disposeFlightDataForm" action="../up ...

  4. postman上传excel,java后台读取excel生成到指定位置进行备份,并且把excel中的数据添加到数据库

    最近要做个前端网页上传excel,数据直接添加到数据库的功能..在此写个读取excel的demo. 首先新建springboot的web项目 导包,读取excel可以用poi也可以用jxl,这里本文用 ...

  5. ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案 try.dot.net 的正确使用姿势 .Net NPOI 根据excel模板导出excel、直接生成excel .Net NPOI 上传excel文件、提交后台获取excel里的数据

    ASP.NET Core 2.2 : 十六.扒一扒新的Endpoint路由方案   ASP.NET Core 从2.2版本开始,采用了一个新的名为Endpoint的路由方案,与原来的方案在使用上差别不 ...

  6. SpringBoot(十三)_springboot上传Excel并读取excel中的数据

    今天工作中,发现同事在整理数据,通过excel上传到数据库.所以现在写了篇利用springboot读取excel中的数据的demo.至于数据的进一步处理,大家肯定有不同的应用场景,自行修改 pom文件 ...

  7. jsp+servlet上传excel并将数据导入到数据库表的实现方法

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  8. java的poi技术下载Excel模板上传Excel读取Excel中内容(SSM框架)

    使用到的jar包 JSP: client.jsp <%@ page language="java" contentType="text/html; charset= ...

  9. 【asp.net】asp.net实现上传Excel文件并读取数据

    #前台代码:使用服务端控件实现上传 <form id="form1" runat="server"> <div> <asp:Fil ...

随机推荐

  1. iis mime 类型

    application/sqlite3 .db application/octet-stream .MP4 application/vnd.android.package-archive .apk

  2. python的内存分配

    一.前言 大多数编译型语言,变量在使用前必须先声明,其中C语言更加苛刻:变量声明必须位于代码块最开始,且在任何其他语句之前.其他语言,想C++和java,允许“随时随地”声明变量,比如,变量声明可以在 ...

  3. java.lang.ClassNotFoundException: org.hibernate.ejb.HibernatePersistence 解决方法

    编译遇到错误,如下: May 11, 2017 1:49:42 PM org.springframework.web.context.ContextLoader initWebApplicationC ...

  4. SYN2136型 北斗NTP网络时间服务器

    SYN2136型  北斗NTP网络时间服务器 北斗NTP网络时间服务器时间服务器使用说明视频链接: http://www.syn029.com/h-pd-109-0_310_36_-1.html 请将 ...

  5. SpringCloud-分布式配置中心【加密-非对称加密】

    案例代码:https://github.com/q279583842q/springcloud-e-book 非对称加密 一.什么是非对称加密(Asymmetric encryption) 二.Jav ...

  6. Hexo+NexT(五):Hexo第三方插件提供功能及配置

    本篇文章介绍NexT中通过第三方实现的功能,有的需要通过额外的插件,有的需要通过第三方提供的功能.这些功能丰富了网站内容,弥补了原生静态网站的不足. Hexo博客专题索引页 增加百度统计分析功能 访问 ...

  7. 迁移桌面程序到MS Store(9)——APPX With Desktop Extension

    在<迁移桌面程序到MS Store(8)——通过APPX下载Win32Component>中我们讨论了通过APPX来下载Service部分的安装包.但是纯UWP的客户端并不能自动运行下载的 ...

  8. webapi使用autofac

    注意:您的项目中如果使用的是webapi2,此处必须为webapi2而不是webapi,否则在运行时将出现“重写成员“Autofac.Integration.WebApi.AutofacWebApiD ...

  9. Java多线程学习(吐血超详细总结)

    Java多线程学习(吐血超详细总结) 林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 写在前面的话:此文只能说是java多线程的一个入门,其实 ...

  10. Android使用Camera2获取预览数据

    一.Camera2简介 Camera2是Google在Android 5.0后推出的一个全新的相机API,Camera2和Camera没有继承关系,是完全重新设计的,且Camera2支持的功能也更加丰 ...