最近写导出Excel这个功能,开始了解过,觉得不是挺难,但实际上手写起来遇到了一些小问题,这里记录一下,防止以后再犯
目录
1.生成Excel并存入数据
这里使用的是NPIO这个组件实现的Excel导出,用法很简单,这里贴上代码 边写边说
1.1 首先是得拿到你需要转换的数据源,这里每个人获取的数据类型不一样,可能是list,dataset,datatable其实都不影响
StaticPagedList<E_Arc_Receip> list = bll_Rec.GetArcAllListPage(queryCond, myAccountInfo.ModelSysUser);
1.2 这一节是利用NPIO创建新的Excel来插入数据
- HSSFWorkbook 这里引用 using NPOI.HSSF.UserModel;
- Isheet是创建页签,就像你每次打开Excel时,左下角有默认的页签
- cells创建表头,并且给表头赋值
- 下面的是给每一列设置宽度,这个值自己调,而且还能设置很多别的样式,这里就自行百度了
HSSFWorkbook excelBook = new HSSFWorkbook();
NPOI.SS.UserModel.ISheet sheet = excelBook.CreateSheet("收文表");
NPOI.SS.UserModel.IRow cells = sheet.CreateRow(0);
//设置表头
cells.CreateCell(0).SetCellValue("来文编号");
cells.CreateCell(1).SetCellValue("公文标题");
cells.CreateCell(2).SetCellValue("文种");
//设置列宽
sheet.SetColumnWidth(0, 10000);
sheet.SetColumnWidth(1, 30000);
sheet.SetColumnWidth(2, 10000);
1.3 循环给每一列赋值
- 这里从数据源拿数据,利用for循环对每一列赋值
- 需要从i+1行开始赋值,因为第一行已经设置了表头
for (int i = 0; i <list.Count; i++)
{
//创建行
NPOI.SS.UserModel.IRow celllist = sheet.CreateRow(i+1);
//添加数据
celllist.CreateCell(0).SetCellValue(list[i].FormerNum);
celllist.CreateCell(1).SetCellValue(list[i].Title);
celllist.CreateCell(2).SetCellValue(list[i].ClassID);
}
2.进行导出操作
我这里的做法是前台ajax请求,然后返回一个状态码以及下载地址返回前台,在进行访问地址下载,因为ajax没有办法获取到我后台直接返回的文件流,所以没法调用到浏览器的下载。如果有别的更好的办法,也可以进行参照
2.1 先将文件保存到本地(服务器)
- path可以跟你自己的路径来定,采用配置文件动态获取
- 创建一个文件流,并将上面生成的Excel写入流中,最后记得关闭,不然文件存到本地但是无法打开
string fileName = "收文检索信息" + Guid.NewGuid().ToString() + ".xls";
string path = ConfigurationManager.AppSettings.Get("ExOAFileUrl");
string filePath = Path.Combine(path, fileName);
FileStream fs = new FileStream(filePath, FileMode.Create);
excelBook.Write(fs);
fs.Close();
2.2将路径以json返回到前台
- 这里我将URL地址转换了一下,因为我的path是物理路径,得转换为相对路径才可以
- 下面的方法仅供参考,还是需要根据自己的实际路径进行修改
filePath = "/" + urlconvertor(filePath);
return Json(new { Result = true, Message = "转换Excel成功,正在请求下载!" , FilePath = filePath },JsonRequestBehavior.AllowGet);
private string urlconvertor(string imagesurl1)
{
string tmpRootDir = Server.MapPath(System.Web.HttpContext.Current.Request.ApplicationPath.ToString());//获取程序根目录
string imagesurl2 = imagesurl1.Replace(tmpRootDir, ""); //转换成相对路径
imagesurl2 = imagesurl2.Replace(@"\", @"/");
//imagesurl2 = imagesurl2.Replace(@"Aspx_Uc/", @"");
return imagesurl2;
}
这样一来,后台的事就结束了,剩下就是前台的事情了
3.前台下载
3.1前台是使用ajax请求的,就直接在success里面写代码
- 这里我的需求不一样,因为我的文件名是随机的GUID,不能让用户下载下来就是随机字符,所以要进行一下统一替换
- 用了一个download方法,这里面具体的替换方式可以参考代码自己研究一下,这里就不写太多
if (result.Result)
{
alert(result.Message);
download(result.FilePath, '发文检索表');
//location.href = encodeURI(result.FilePath);
console.log(result.FilePath);
}
//附上替换方法
function getBlob(url, cb) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onload = function () {
if (xhr.status === 200) {
cb(xhr.response);
}
};
xhr.send();
}
function saveAs(blob, filename) {
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, filename);
} else {
var link = document.createElement('a');
var body = document.querySelector('body');
link.href = window.URL.createObjectURL(blob);
link.download = filename;
// fix Firefox
link.style.display = 'none';
body.appendChild(link);
link.click();
body.removeChild(link);
window.URL.revokeObjectURL(link.href);
};
}
function download(url, filename) {
getBlob(url, function (blob) {
saveAs(blob, filename);
});
};
到这里就结束了一个导出功能,可能有些人会觉得这样长时间,存在服务器上的文件会越来会多,这里可以写一个定时服务,去定期删掉前一天的冗余文件,至于怎么实现,这个就后面在更新了