首先:Model类
public class InfoVM { /// <summary> /// 标题 /// </summary> public string Title { set; get; } /// <summary> /// 类别 /// </summary> public string Category { set; get; } /// <summary> /// 内容信息 /// </summary> public string Description { set; get; } /// <summary> /// 是否发布 /// </summary> public bool IsRelease { set; get; } /// <summary> /// 文件路径 /// </summary> public string FilePath { set; get; } /// <summary> /// 图片字节 /// </summary> public byte[] ImageBytes { set; get; } }
然后构造要导入的Excel信息:
/// <summary> /// 导出Excel /// </summary> /// <returns></returns> public JsonResult Export() { string rooturl = Request.Url.GetLeftPart(UriPartial.Authority); List<InfoVM> list = new List<InfoVM>(); Random ram = new Random(); for (int i = 1; i < 100; i++) { InfoVM vm = new InfoVM(); vm.Title = "信息的标题" + i; vm.Category = "大事记"; vm.IsRelease = i % 2 == 0; int xh = ram.Next(1,3); vm.FilePath = string.Format("/Files/0{0}.jpg", xh); string fullpath = vm.FilePath; if (!fullpath.StartsWith("http") || fullpath.StartsWith("/")) { fullpath = string.Format("{0}{1}", rooturl,vm.FilePath); } vm.ImageBytes = NetHelper.GetImgBytes(fullpath); list.Add(vm); } ResultModel rm = new ResultModel(); try { string fileExt = ".xlsx"; string fileName = string.Format("{0:yyyyMMddHHmmssffff}", DateTime.Now) + fileExt; string fullPath = HttpRuntime.AppDomainAppPath+string.Format("Files\{0}",fileName); DataTable dt = ExcelHelper.GetTabFromList<InfoVM>(list); string errmsg = string.Empty; bool issuc = ExcelHelper.ReadDataTabToExcel(fullPath,dt, ref errmsg,"大事记", "大事记", fileExt); if (issuc) { rm.Err = 0; rm.Msg = "生成成功"; rm.Data = string.Format("/Files/{0}", fileName); } else { rm.Err = 1; rm.Msg = errmsg; } } catch(Exception ex) { rm.Err = 1; rm.Msg = ex.Message; } return Json(rm,JsonRequestBehavior.AllowGet); }
Excel帮助类如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Data; using System.IO; using NPOI.HSSF.UserModel; using NPOI.HSSF.Util; using NPOI.XSSF.UserModel; using NPOI.SS.UserModel; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System.Reflection; namespace TestUpfile { public class ExcelHelper { /// <summary> /// 将Excel文件转成dataset(针对有多个工作表、并且多个工作表结构一致) /// </summary> /// <param name="excelFilePath">Excel文件</param> /// <param name="headerRowIndex">表头行</param> /// <param name="fTitle">返回文件标题</param> /// <returns></returns> public static DataTable GeneralDataSetFromExcel(string excelFilePath, int headerRowIndex, ref string fTitle, string fileext = ".xlsx") { DataTable dt = new DataTable(); dt = GeneralDataSetFromExcel(System.IO.File.OpenRead(excelFilePath), headerRowIndex, ref fTitle,fileext); return dt; } /// <summary> /// 将Excel文件转成dataset(针对有多个工作表、并且多个工作表结构一致) /// </summary> /// <param name="stream">Excel文件流</param> /// <param name="headerRowIndex">表头行</param> /// <param name="fTitle">返回文件标题</param> /// <returns></returns> public static DataTable GeneralDataSetFromExcel(Stream stream, int headerRowIndex, ref string fTitle, string fileext= ".xlsx") { DataTable dt = new DataTable(); IWorkbook workbook = null; if (fileext == ".xlsx") { workbook = new XSSFWorkbook(stream); } else { workbook = new HSSFWorkbook(stream); } //XSSFWorkbook workbook = new XSSFWorkbook(stream); int sheetIndex = 0; ISheet sheet = workbook.GetSheetAt(sheetIndex); //先去掉表头标题行 IRow headerRow = sheet.GetRow(headerRowIndex); if (headerRow == null) { while (headerRow == null) { headerRowIndex++; headerRow = sheet.GetRow(headerRowIndex); if (headerRowIndex > 5) break; } } fTitle = headerRow.GetCell(0).StringCellValue; //本次的Excel是双表头 headerRowIndex += 1;//加1行,跳过表头 IRow secondeRow = sheet.GetRow(headerRowIndex); headerRowIndex += 1;//加1行,跳过表头 IRow thirdRow = sheet.GetRow(headerRowIndex); int cellCount = thirdRow.LastCellNum; int secondCellIndex = 0; int thirdCellIndex = 0; for (int i = secondeRow.FirstCellNum; i < cellCount; i++) { ICell cell = secondeRow.GetCell(i); if (cell == null || cell.StringCellValue == "") { //第二行为空,则看第三行是否也为空,如果两行都为空,则跳过 ICell tcell = thirdRow.GetCell(thirdCellIndex); if (tcell == null || tcell.StringCellValue == "") { continue; } else { DataColumn column = new DataColumn(tcell.StringCellValue); dt.Columns.Add(column); secondCellIndex++; thirdCellIndex++; } } else { string cellValue = cell.StringCellValue; if (cellValue == "意见提出人信息" || cellValue == "意见对应情况") { //这是合并的,意见提出人信息下面有两列,意见对应情况下面有四列 if (cellValue == "意见提出人信息") { //下面有两列,切换到下一行的单元格 for (int j = 0; j < 2; j++) { ICell tcell = thirdRow.GetCell(thirdCellIndex); if (tcell.StringCellValue != "") { DataColumn column = new DataColumn(tcell.StringCellValue); dt.Columns.Add(column); } else { //补齐列 DataColumn column = new DataColumn("Emp" + Guid.NewGuid().ToString().Replace("-", "")); dt.Columns.Add(column); } thirdCellIndex++; } secondCellIndex++; } if (cellValue == "意见对应情况") { //下面有四列,切换到下一行的单元格 for (int j = 0; j < 3; j++) { ICell tcell = thirdRow.GetCell(thirdCellIndex); if (tcell.StringCellValue != "") { DataColumn column = new DataColumn(tcell.StringCellValue); dt.Columns.Add(column); } else { //补齐列 DataColumn column = new DataColumn("Emp" + Guid.NewGuid().ToString().Replace("-", "")); dt.Columns.Add(column); } thirdCellIndex++; } secondCellIndex++; } } else { if (cell.StringCellValue != "") { DataColumn column = new DataColumn(cell.StringCellValue); dt.Columns.Add(column); } secondCellIndex++; thirdCellIndex++; } } } for (int i = (headerRowIndex + 1); i <= sheet.LastRowNum; i++) { IRow row = sheet.GetRow(i); int rownum = row.Cells.Count; int max = 10; bool isnull = false; if (max > rownum) max = rownum;//检查前三列是否有数据,如果前三都没有,则不再向后读取 int cnt = 0; for (int k = 0; k < max; k++) { if (row == null) break; ICell cell = row.GetCell(k); if (cell == null) break; if (cell.CellType == CellType.String) { if (cell.StringCellValue.Trim() == "") { cnt++; if (cnt >= 3) { // 如果遇到第一个空行,则不再继续向后读取 isnull = true; break; } } } else { break; } } if (isnull) { continue; } DataRow dataRow = dt.NewRow(); for (int j = row.FirstCellNum; j < cellCount; j++) { dataRow[j] = row.GetCell(j); } dt.Rows.Add(dataRow); } sheet = null; workbook = null; return dt; } /// <summary> /// 将一个datatable写入一个Excel文件,按人导出门禁 /// </summary> /// <param name="tab"></param> /// <returns></returns> public static bool ReadDataTabToExcel(string savePath,DataTable tab,ref string errmsg, string sheetname = null, string tabtitle = null,string fileExt=".xlsx") { try { Stream stream = new MemoryStream(); IWorkbook workbook = null; if (fileExt.ToLower() == ".xlsx") { workbook = new XSSFWorkbook(); } else { workbook = new HSSFWorkbook(); } int totalcount = tab.Rows.Count; int max = 65510;//设置每个sheet最多存储数量 int totalsheet = 1; if (totalcount % max == 0) { totalsheet = totalcount / max; } else { totalsheet = totalcount / max + 1; } ICellStyle headstyle = workbook.CreateCellStyle(); headstyle.FillBackgroundColor = HSSFColor.Teal.Index; headstyle.FillPattern = FillPattern.SolidForeground; headstyle.FillForegroundColor = HSSFColor.Grey25Percent.Index; headstyle.Alignment = HorizontalAlignment.Center; IFont font12 = workbook.CreateFont(); font12.FontName = "微软雅黑"; font12.Boldweight = 15; font12.FontHeightInPoints = 12; headstyle.SetFont(font12); headstyle.BorderBottom = BorderStyle.Hair; //带背景色,并且文字居中 ICellStyle huibgstyle = workbook.CreateCellStyle(); huibgstyle.FillBackgroundColor = HSSFColor.SeaGreen.Index; huibgstyle.FillPattern = FillPattern.SolidForeground; huibgstyle.FillForegroundColor = HSSFColor.SeaGreen.Index; huibgstyle.Alignment = HorizontalAlignment.Center; huibgstyle.VerticalAlignment = VerticalAlignment.Top; huibgstyle.BorderTop = BorderStyle.Thin; huibgstyle.BorderRight = BorderStyle.Thin; huibgstyle.BorderBottom = BorderStyle.Thin; huibgstyle.BorderLeft = BorderStyle.Thin; //普通的行,只是文字居中 ICellStyle norstyle = workbook.CreateCellStyle(); norstyle.Alignment = HorizontalAlignment.Center; norstyle.VerticalAlignment = VerticalAlignment.Top; norstyle.BorderTop = BorderStyle.Thin; norstyle.BorderRight = BorderStyle.Thin; norstyle.BorderBottom = BorderStyle.Thin; norstyle.BorderLeft = BorderStyle.Thin; for (int shct = 0; shct < totalsheet; shct++) { ISheet sheet = null; if (string.IsNullOrEmpty(sheetname)) { sheet = workbook.CreateSheet(); } else { sheet = workbook.CreateSheet(sheetname + (shct + 1)); } //CellRangeAddress()该方法的参数次序是:开始行号,结束行号,开始列号,结束列号。 sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, tab.Columns.Count-1)); IRow frow = sheet.CreateRow(0); frow.Height = 30 * 20; ICellStyle fstyle = workbook.CreateCellStyle(); IFont font14 = workbook.CreateFont(); font14.FontName = "微软雅黑"; font14.FontHeightInPoints = 14; font14.Color = HSSFColor.Blue.Index; font14.Boldweight = short.MaxValue; fstyle.Alignment = HorizontalAlignment.Center; fstyle.VerticalAlignment = VerticalAlignment.Center; fstyle.SetFont(font14); ICell fcell = frow.CreateCell(0); fcell.SetCellValue(tabtitle); fcell.CellStyle = fstyle; IRow headerRow = sheet.CreateRow(1); //第一列是序号,第二列是门禁名称,按名称来设置背景色 int rownum = 0; string prevmj = ""; foreach (DataColumn column in tab.Columns) { string colName = column.ColumnName; string cnName = colName; switch (colName) { case "Title": { cnName = "标题"; break; } case "Category": { cnName = "类别"; break; } case "Description": { cnName = "内容"; break; } case "IsRelease": { cnName = "是否发布"; break; } case "FilePath": { cnName = "文件路径"; break; } case "ImageBytes": { cnName = "图片"; break; } } headerRow.CreateCell(column.Ordinal).SetCellValue(cnName); headerRow.GetCell(column.Ordinal).CellStyle = headstyle; //列宽每个像素1/256 if (column.ColumnName == "Title") { sheet.SetColumnWidth(column.Ordinal, 50 * 256); } if (column.ColumnName == "Description") { sheet.SetColumnWidth(column.Ordinal, 100 * 256); } if (column.ColumnName == "FilePath") { sheet.SetColumnWidth(column.Ordinal, 50 * 256); } if(column.ColumnName== "ImageBytes") { sheet.SetColumnWidth(column.Ordinal, 60 * 256); } } int rowIndex = 2; int curmin = shct * max; int curmax = shct * max + max; if (curmax > totalcount) curmax = totalcount; for (int ct = curmin; ct < curmax; ct++) { DataRow row = tab.Rows[ct]; //string curmj = row["卡号"].ToString(); //if (string.IsNullOrEmpty(prevmj)) //{ // prevmj = curmj; //} //if (curmj != prevmj) //{ // prevmj = curmj; // rownum++; //} ICellStyle style = norstyle; if (rownum % 2 != 0) { style = huibgstyle; } IRow datarow = sheet.CreateRow(rowIndex); datarow.Height = 100 * 20;//设置行高,Excel行高的每个像素点是1/20 foreach (DataColumn col in tab.Columns) { if(col.ColumnName== "ImageBytes") { byte[] bytes = (byte[])row[col.ColumnName]; if (bytes != null) { int pictureIdx = workbook.AddPicture(bytes, PictureType.JPEG); IDrawing patriarch = sheet.CreateDrawingPatriarch(); IClientAnchor anchor = patriarch.CreateAnchor(70, 10, 0, 0, col.Ordinal, rowIndex, col.Ordinal+1, rowIndex + 1); IPicture pict = patriarch.CreatePicture(anchor, pictureIdx); } } else { string content = row[col.ColumnName].ToString(); datarow.CreateCell(col.Ordinal).SetCellValue(content); datarow.GetCell(col.Ordinal).CellStyle = style; } } rowIndex++; } } using(FileStream fs=new FileStream(savePath, FileMode.OpenOrCreate, FileAccess.ReadWrite)) { workbook.Write(fs); } } catch(Exception ex) { errmsg = ex.Message; return false; } return true; } /// <summary> /// 将list转成datatable /// </summary> /// <typeparam name="T"></typeparam> /// <param name="list"></param> /// <returns></returns> public static DataTable GetTabFromList<T>(IList<T> list) { if (list == null || list.Count == 0) return null; DataTable dt = new DataTable(); Type type = typeof(T); PropertyInfo[] pinfos = type.GetProperties(); foreach (var pi in pinfos) { Type mytp = pi.PropertyType; DataColumn dc = new DataColumn(pi.Name, mytp); dt.Columns.Add(dc); } foreach (var t in list) { DataRow dr = dt.NewRow(); foreach (var pi in pinfos) { object ov = pi.GetValue(t, null); dr[pi.Name] = ov; } dt.Rows.Add(dr); } return dt; } /// <summary> /// 返回一个json字符串 /// </summary> /// <param name="obj"></param> /// <returns></returns> public static string GetJsonMsg(object obj) { IsoDateTimeConverter timeConverter = new IsoDateTimeConverter(); timeConverter.DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss"; return JsonConvert.SerializeObject(obj, Formatting.Indented, timeConverter); } public static byte[] CopyStream(Stream stream) { int len = 1024; byte[] bytes = new byte[len]; MemoryStream ms = new MemoryStream(); int count = 0; while ((count = stream.Read(bytes, 0, len)) > 0) { ms.Write(bytes, 0, count); } stream.Seek(0, SeekOrigin.Begin); return ms.ToArray(); } } }
参数的解析: HSSFClientAnchor(int dx1,int dy1,int dx2,int dy2,int col1,int row1,int col2,int row2)
dx1:图片左边相对excel格的位置(x偏移) 范围值为:0~1023;即输100 偏移的位置大概是相对于整个单元格的宽度的100除以1023大概是10分之一
dy1:图片上方相对excel格的位置(y偏移) 范围值为:0~256 原理同上。
dx2:图片右边相对excel格的位置(x偏移) 范围值为:0~1023; 原理同上。
dy2:图片下方相对excel格的位置(y偏移) 范围值为:0~256 原理同上。
col1和row1 :图片左上角的位置,以excel单元格为参考,比喻这两个值为(1,1),那么图片左上角的位置就是excel表(1,1)单元格的右下角的点(A,1)右下角的点。
col2和row2:图片右下角的位置,以excel单元格为参考,比喻这两个值为(2,2),那么图片右下角的位置就是excel表(2,2)单元格的右下角的点(B,2)右下角的点。
导出的结果如图: