要在ASP.NET MVC站點上作excel導出功能,可是要導出的excel文件比較大,有幾十M,因此導出比較費時,爲了避免影響對界面的其它操做,我就採用異步的方式,後臺開闢一個線程將excel導出到指定目錄,而後提供下載。導出的excel涉及到了多個sheet(工做簿),表格合併,格式設置等,因此採用了NPOI組件。html
效果以下:設計模式
選中了多行,會導出多個工做簿sheet,一個彙總的,其餘的就是明細數據。服務器
下面是要幾個封裝好的類,從網上找的,而後修改了一下。這幾個類不少方法都封裝好了,十分利於複用。常見的excel格式均可以導出,若是有特別的需求,能夠本身修改一下源碼進行擴展。架構
GenerateSheet.cs併發
using NPOI.SS.UserModel; using NPOI.SS.Util; using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Reflection; using System.Text.RegularExpressions; namespace Core.Excel { /// <summary> /// 導出Excel基類 /// </summary> public class GenerateSheet<T> : BaseGenerateSheet { #region 私有字段 // Excel 顯示時間的樣式 private ICellStyle dateStyle = null; // Excel 顯示列頭的樣式 private ICellStyle headStyle = null; // Excel 顯示內容的樣式 private ICellStyle contentsStyle = null; // Excel 顯示總計的樣式 private ICellStyle totalStyle = null; // 列頭集合 private List<ColumnsMapping> columnHeadList = null; // 顯示的數據 private List<T> dataSource; private List<object> dataSource2; #endregion #region 屬性 /// <summary> /// Excel 顯示時間的樣式 /// </summary> protected ICellStyle DateStyle { get { return dateStyle; } set { dateStyle = value; } } /// <summary> /// Excel 顯示列頭的樣式 /// </summary> protected ICellStyle HeadStyle { get { return headStyle; } set { headStyle = value; } } /// <summary> /// Excel 顯示內容的樣式 /// </summary> protected ICellStyle ContentsStyle { get { return contentsStyle; } set { contentsStyle = value; } } /// <summary> /// Excel 顯示總計的樣式 /// </summary> protected ICellStyle TotalStyle { get { return totalStyle; } set { totalStyle = value; } } /// <summary> /// 是否有邊框 只讀 /// </summary> protected bool IsBorder { get; private set; } protected List<ColumnsMapping> ColumnHeadList { get { return this.columnHeadList; } private set { this.columnHeadList = value; } } #endregion #region 構造方法 /// <summary> /// 導出Excel基類 /// </summary> /// <param name="_dataSource">Sheet裏面顯示的數據</param> public GenerateSheet(List<T> _dataSource) : this(_dataSource, null, string.Empty, true) { } /// <summary> /// 導出Excel基類 /// </summary> /// <param name="_dataSource">Sheet裏面顯示的數據</param> public GenerateSheet(List<T> _dataSource, string sheetName) : this(_dataSource, null, sheetName, true) { } /// <summary> /// 導出Excel基類 /// </summary> /// <param name="_dataSource">Sheet裏面顯示的數據</param> public GenerateSheet(List<T> _dataSource, List<object> _dataSource2, string sheetName) : this(_dataSource, _dataSource2, sheetName, true) { } /// <summary> /// 導出Excel基類 /// </summary> /// <param name="_dataSource">Sheet裏面顯示的數據</param> /// <param name="isBorder">是否有邊框</param> public GenerateSheet(List<T> _dataSource, bool isBorder) : this(_dataSource, null, string.Empty, isBorder) { } /// <summary> /// 導出Excel基類 /// </summary> /// <param name="_dataSource">Sheet裏面顯示的數據</param> /// <param name="isBorder">是否有邊框</param> public GenerateSheet(List<T> _dataSource, List<object> _dataSource2, string sheetName, bool isBorder) { //if (_dataSource != null && _dataSource.Count > 0) this.dataSource = _dataSource; this.dataSource2 = _dataSource2; //else // throw new Exception("數據不能爲空!"); this.IsBorder = isBorder; this.SheetName = sheetName; } #endregion #region 能夠被重寫的方法 /// <summary> /// 生成Excel的Sheet /// </summary> /// <param name="sheet"></param> public override void GenSheet(ISheet sheet) { this.SetSheetContents(sheet); } /// <summary> /// 初始化列頭 /// </summary> /// <returns></returns> protected virtual List<ColumnsMapping> InitializeColumnHeadData() { try { List<PropertyInfo> propertyList = this.GetObjectPropertyList(); List<ColumnsMapping> columnsList = new List<ColumnsMapping>(); int colIndex = 0; foreach (PropertyInfo propertyInfo in propertyList) { columnsList.Add(new ColumnsMapping() { ColumnsData = propertyInfo.Name, ColumnsText = propertyInfo.Name, ColumnsIndex = colIndex, IsTotal = false, Width = 15 }); colIndex++; } return columnsList; } catch (Exception ex) { throw ex; } } /// <summary> /// 設置列頭 /// </summary> /// <param name="sheet">Excel Sheet</param> /// <param name="rowIndex">記錄Excel最大行的位置,最大值爲65535</param> protected virtual void SetColumnHead(ISheet sheet, ref int rowIndex) { if (columnHeadList.Count > 0) { IRow headerRow = sheet.CreateRow(rowIndex); foreach (ColumnsMapping columns in columnHeadList) { ICell newCell = headerRow.CreateCell(columns.ColumnsIndex); newCell.SetCellValue(columns.ColumnsText); newCell.CellStyle = headStyle; //設置列寬 SetColumnsWidth(sheet, columns.ColumnsIndex, columns.Width); } rowIndex++; } } /// <summary> /// 設置Excel內容 /// </summary> /// <param name="sheet"></param> /// <param name="dataSource"></param> /// <param name="rowIndex"></param> protected virtual void SetSheetContents(ISheet sheet, List<T> dataSource, ref int rowIndex) { if (dataSource != null) { foreach (T value in dataSource) { #region 填充內容 IRow dataRow = sheet.CreateRow(rowIndex); int colIndex = 0; foreach (ColumnsMapping columns in columnHeadList) { if (columns.ColumnsIndex >= 0) { if (columns.ColumnsIndex >= colIndex) colIndex = columns.ColumnsIndex; else columns.ColumnsIndex = colIndex; ICell newCell = dataRow.CreateCell(colIndex); string drValue = string.Empty; if (!string.IsNullOrEmpty(columns.ColumnsData)) drValue = GetModelValue(columns.ColumnsData, value); SetCellValue(newCell, rowIndex, drValue, columns); colIndex++; } } #endregion rowIndex++; } //rowIndex++; } } /// <summary> /// 設置單元格的數據 /// </summary> /// <param name="cell">單元格對像</param> /// <param name="rowIndex">單元格行索引</param> /// <param name="drValue">單元格數據</param> /// <param name="columns">單元格的列信息</param> protected virtual void SetCellValue(ICell cell, int rowIndex, string drValue, ColumnsMapping columns) { cell.CellStyle = contentsStyle; if (!string.IsNullOrEmpty(columns.ColumnsData)) { PropertyInfo info = GetObjectProperty(columns.ColumnsData); switch (info.PropertyType.FullName) { case "System.String": //字符串類型 double result; if (IsNumeric(drValue, out result)) { double.TryParse(drValue, out result); cell.SetCellValue(result); break; } else { cell.SetCellValue(drValue); break; } case "System.DateTime": //日期類型 if (string.IsNullOrEmpty(drValue)||drValue=="0001/1/1 0:00:00") { cell.SetCellValue(""); } else { DateTime dateV; DateTime.TryParse(drValue, out dateV); cell.SetCellValue(dateV); cell.CellStyle = dateStyle; //格式化顯示 } break; case "System.Boolean": //布爾型 bool boolV = false; bool.TryParse(drValue, out boolV); cell.SetCellValue(boolV); break; case "System.Int16": //整型 case "System.Int32": case "System.Int64": case "System.Byte": int intV = 0; int.TryParse(drValue, out intV); cell.SetCellValue(intV); break; case "System.Decimal": //浮點型 case "System.Double": double doubV = 0; double.TryParse(drValue, out doubV); cell.SetCellValue(doubV); break; case "System.DBNull": //空值處理 cell.SetCellValue(""); break; default: cell.SetCellValue(""); break; } } else { cell.SetCellValue(""); } } /// <summary> /// 設置總計單元格的數據 /// </summary> /// <param name="cell">總計單元格</param> /// <param name="rowIndex">當前行的索引</param> /// <param name="startRowIndex">內容數據的開始行</param> /// <param name="columns">當前列信息</param> protected virtual void SetTotalCellValue(ICell cell, int rowIndex, int startRowIndex, ColumnsMapping columns) { if (columns.IsTotal) { string colItem = CellReference.ConvertNumToColString(columns.ColumnsIndex); cell.CellStyle = totalStyle; cell.SetCellFormula(string.Format("SUM({0}{1}:{2}{3})", colItem, startRowIndex, colItem, rowIndex)); } } /// <summary> /// 在全部數據最後添加總計,固然也能夠是其它的公式 /// </summary> /// <param name="sheet">工做薄Sheet</param> /// <param name="rowIndex">當前行</param> /// <param name="startRowIndex">內容開始行</param> protected virtual void SetTotal(ISheet sheet, ref int rowIndex, int startRowIndex) { if (rowIndex > startRowIndex) { IRow headerRow = sheet.CreateRow(rowIndex) as IRow; foreach (ColumnsMapping columns in columnHeadList) { ICell newCell = headerRow.CreateCell(columns.ColumnsIndex); SetTotalCellValue(newCell, rowIndex, startRowIndex, columns); } } } /// <summary> /// 數據源2 /// </summary> /// <param name="sheet">工做薄Sheet</param> /// <param name="rowIndex">當前行</param> protected virtual void SetToSecond(ISheet sheet, ref int rowIndex, List<object> dataSource2) { } #endregion #region 公共方法 /// <summary> /// 獲取屬性名字 /// </summary> /// <param name="expr"></param> /// <returns></returns> protected string GetPropertyName(Expression<Func<T, object>> expr) { var rtn = ""; if (expr.Body is UnaryExpression) { rtn = ((MemberExpression)((UnaryExpression)expr.Body).Operand).Member.Name; } else if (expr.Body is MemberExpression) { rtn = ((MemberExpression)expr.Body).Member.Name; } else if (expr.Body is ParameterExpression) { rtn = ((ParameterExpression)expr.Body).Type.Name; } return rtn; } protected void SetColumnsWidth(ISheet sheet, int colIndex, int width) { //設置列寬 sheet.SetColumnWidth(colIndex, width * 256); } #endregion #region 私有方法 private void SetSheetContents(ISheet sheet) { if (sheet != null) { // 初始化相關樣式 this.InitializeCellStyle(); // 初始化列頭的相關數據 this.columnHeadList = InitializeColumnHeadData(); // 當前行 int rowIndex = 0; // 設置列頭 this.SetColumnHead(sheet, ref rowIndex); // 內容開始行 int startRowIndex = rowIndex; // 設置Excel內容 this.SetSheetContents(sheet, dataSource, ref rowIndex); // 在全部數據最後添加總計,固然也能夠是其它的公式 if (dataSource.Count > 0) { this.SetTotal(sheet, ref rowIndex, startRowIndex); } this.SetToSecond(sheet, ref rowIndex, dataSource2); } } /// <summary> /// 初始化相關對像 /// </summary> private void InitializeCellStyle() { columnHeadList = new List<ColumnsMapping>(); // 初始化Excel 顯示時間的樣式 dateStyle = this.Workbook.CreateCellStyle(); IDataFormat format = this.Workbook.CreateDataFormat(); dateStyle.DataFormat = format.GetFormat("yyyy-mm-dd"); if (this.IsBorder) { //有邊框 dateStyle.BorderBottom = BorderStyle.Thin; dateStyle.BorderLeft = BorderStyle.Thin; dateStyle.BorderRight = BorderStyle.Thin; dateStyle.BorderTop = BorderStyle.Thin; } // 初始化Excel 列頭的樣式 headStyle = this.Workbook.CreateCellStyle(); headStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Left;// 文本居左 IFont font = this.Workbook.CreateFont(); font.FontHeightInPoints = 12; // 字體大小 font.Boldweight = 700; // 字體加粗 headStyle.SetFont(font); if (this.IsBorder) { //有邊框 headStyle.BorderBottom = BorderStyle.Thin; headStyle.BorderLeft = BorderStyle.Thin; headStyle.BorderRight = BorderStyle.Thin; headStyle.BorderTop = BorderStyle.Thin; } // 初始化Excel 顯示內容的樣式 contentsStyle = this.Workbook.CreateCellStyle(); font = this.Workbook.CreateFont(); font.FontHeightInPoints = 10; contentsStyle.SetFont(font); if (this.IsBorder) { //有邊框 contentsStyle.BorderBottom = BorderStyle.Thin; contentsStyle.BorderLeft = BorderStyle.Thin; contentsStyle.BorderRight = BorderStyle.Thin; contentsStyle.BorderTop = BorderStyle.Thin; } // 初始化Excel 顯示總計的樣式 totalStyle = this.Workbook.CreateCellStyle(); font = this.Workbook.CreateFont(); font.Boldweight = 700; font.FontHeightInPoints = 10; totalStyle.SetFont(font); if (this.IsBorder) { //有邊框 totalStyle.BorderBottom = BorderStyle.Thin; totalStyle.BorderLeft = BorderStyle.Thin; totalStyle.BorderRight = BorderStyle.Thin; totalStyle.BorderTop = BorderStyle.Thin; } } /// <summary> /// 獲取 T 對像的全部屬性 /// </summary> /// <returns></returns> private List<PropertyInfo> GetObjectPropertyList() { List<PropertyInfo> result = new List<PropertyInfo>(); Type t = typeof(T); if (t != null) { PropertyInfo[] piList = t.GetProperties(); foreach (var pi in piList) { if (!pi.PropertyType.IsGenericType) { result.Add(pi); } } } return result; } /// <summary> /// 根據屬性名字獲取 T 對像的屬性 /// </summary> /// <returns></returns> private PropertyInfo GetObjectProperty(string propertyName) { Type t = typeof(T); PropertyInfo result = t.GetProperty(propertyName); return result; } /// <summary> /// 獲取類中的屬性值 /// </summary> /// <param name="FieldName"></param> /// <param name="obj"></param> /// <returns></returns> private string GetModelValue(string FieldName, object obj) { try { Type Ts = obj.GetType(); object o = Ts.GetProperty(FieldName).GetValue(obj, null); string Value = Convert.ToString(o); if (string.IsNullOrEmpty(Value)) return null; return Value; } catch { return null; } } /// <summary> /// 判斷是否爲一個數字並反回值 /// </summary> /// <param name="message"></param> /// <param name="result"></param> /// <returns></returns> private bool IsNumeric(String message, out double result) { if (!string.IsNullOrEmpty(message)) { Regex rex = new Regex(@"^[-]?\d+[.]?\d*$"); result = -1; if (rex.IsMatch(message)) { result = double.Parse(message); return true; } else return false; } else { result = 0; return false; } } #endregion } }
GenerateExcel.csapp
using NPOI.HPSF; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Core.Excel { public class GenerateExcel { #region 私有字段 protected XSSFWorkbook workbook = null; #endregion #region 屬性 /// <summary> /// Excel的Sheet集合 /// </summary> public List<BaseGenerateSheet> SheetList { get; set; } #endregion #region 構造方法 public GenerateExcel() { InitializeWorkbook(); } #endregion #region 私有方法 /// <summary> /// 初始化相關對像 /// </summary> private void InitializeWorkbook() { workbook = new XSSFWorkbook(); SheetList = new List<BaseGenerateSheet>(); #region 右擊文件 屬性信息 //DocumentSummaryInformation dsi = PropertySetFactory.CreateDocumentSummaryInformation(); //dsi.Company = "http://www.kjy.cn"; //workbook.DocumentSummaryInformation = dsi; //SummaryInformation si = PropertySetFactory.CreateSummaryInformation(); //si.Author = "深圳市跨境易電子商務有限公司"; //填加xls文件做者信息 //si.ApplicationName = "深圳市跨境易電子商務有限公司"; //填加xls文件建立程序信息 //si.LastAuthor = "深圳市跨境易電子商務有限公司"; //填加xls文件最後保存者信息 //si.Comments = "深圳市跨境易電子商務有限公司"; //填加xls文件做者信息 //si.Title = "深圳市跨境易電子商務有限公司"; //填加xls文件標題信息 //si.Subject = "深圳市跨境易電子商務有限公司"; //填加文件主題信息 //si.CreateDateTime = DateTime.Now; //workbook.SummaryInformation = si; #endregion } /// <summary> /// 生成Excel並返回內存流 /// </summary> /// <returns></returns> private void ExportExcel() { foreach (BaseGenerateSheet sheet in SheetList) { ISheet sh = null; if (string.IsNullOrEmpty(sheet.SheetName)) sh = workbook.CreateSheet(); else sh = workbook.CreateSheet(sheet.SheetName); sheet.Workbook = this.workbook; sheet.GenSheet(sh); } //using (MemoryStream ms = new MemoryStream()) //{ // workbook.Write(ms); // ms.Flush(); // ms.Position = 0; // return ms; //} } #endregion #region 公共方法 /// <summary> /// 導出到Excel文件 /// </summary> /// <param name="strFileName">保存位置</param> public void ExportExcel(string strFileName) { try { ExportExcel(); if (workbook != null) { using (MemoryStream ms = new MemoryStream()) { workbook.Write(ms); if (!Directory.Exists(Path.GetDirectoryName(strFileName))) { Directory.CreateDirectory(Path.GetDirectoryName(strFileName)); } using (FileStream fs = new FileStream(strFileName, FileMode.Create, FileAccess.Write)) { byte[] data = ms.ToArray(); fs.Write(data, 0, data.Length); fs.Flush(); } } } } catch (Exception ex) { throw; } } #endregion } }
ColumnsMapping.cs框架
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Core.Excel { /// <summary> /// Excel列頭的相關設置 /// </summary> public class ColumnsMapping { #region 屬性 /// <summary> /// Excel 列頭顯示的值 /// </summary> public string ColumnsText { get; set; } /// <summary> /// Excel 列綁定對像的屬性, 能夠爲空 /// </summary> public string ColumnsData { get; set; } /// <summary> /// Excel 列的寬度 /// </summary> public int Width { get; set; } /// <summary> /// 是否須要總計行 /// </summary> public bool IsTotal { get; set; } /// <summary> /// Excel列的索引 /// </summary> public int ColumnsIndex { get; set; } #endregion #region 構造方法 /// <summary> /// Excel列頭的相關設置 /// </summary> public ColumnsMapping() { } /// <summary> /// Excel列頭的相關設置 /// </summary> public ColumnsMapping(string colText, string colData, int width, int colIndex, bool _isTotal) { this.ColumnsText = colText; this.ColumnsData = colData; this.Width = width; this.IsTotal = _isTotal; this.ColumnsIndex = colIndex; } #endregion } }
BaseGenerateSheet.cs異步
using NPOI.SS.UserModel; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Core.Excel { public abstract class BaseGenerateSheet { public string SheetName { set; get; } public IWorkbook Workbook { get; set; } public virtual void GenSheet(ISheet sheet) { } } }
如下這兩個類,是我根據上面幾個基礎類自定義的一個導出類,基本上就配置一下表頭,而後設置下正文表格樣式。(哎呀,這個類代碼我拷貝錯了,不過使用方式基本相似,改天我修改下)ide
IdentityCardMonthPayOffSheet.cspost
/* ============================================================================== * 功能描述:MonthPayOffSheet * 創 建 者:Zouqj * 建立日期:2015/8/24 16:23:53 ==============================================================================*/ using Core.Receivable; using Core.Statistical; using NPOI.SS.UserModel; using NPOI.SS.Util; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Core.Excel.IdentityCardMonthPayOff { /// <summary> /// 總表 /// </summary> public class IdentityCardMonthPayOffSheet : GenerateSheet<IdentityCardMonthPay> { public IdentityCardMonthPayOffSheet(List<IdentityCardMonthPay> dataSource, string sheetName) : base(dataSource, sheetName) { } protected override List<ColumnsMapping> InitializeColumnHeadData() { List<ColumnsMapping> result = new List<ColumnsMapping>(); result.Add(new ColumnsMapping() { ColumnsText = "結算月份", ColumnsData = GetPropertyName(p => p.SettleMonth), ColumnsIndex = 0, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "身份證調驗數量", ColumnsData = GetPropertyName(p => p.ValidedCount), ColumnsIndex = 1, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "總成本", ColumnsData = GetPropertyName(p => p.TotalCost), ColumnsIndex = 2, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "總收入", ColumnsData = GetPropertyName(p => p.TotalIncome), ColumnsIndex = 3, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "毛利", ColumnsData = GetPropertyName(p => p.TotalMargin), ColumnsIndex = 4, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "毛利率", ColumnsData = GetPropertyName(p => p.MarginRate), ColumnsIndex = 5, IsTotal = false, Width = 15 }); return result; } protected override void SetColumnHead(NPOI.SS.UserModel.ISheet sheet, ref int rowIndex) { base.SetColumnHead(sheet,ref rowIndex); if (this.ColumnHeadList.Count > 0) { // 全部列頭居中 this.HeadStyle.Alignment = HorizontalAlignment.Center; this.HeadStyle.VerticalAlignment = VerticalAlignment.Center; } } protected override void SetCellValue(ICell cell, int rowIndex, string drValue, ColumnsMapping columns) { base.SetCellValue(cell, rowIndex, drValue, columns); if (columns.ColumnsIndex == 5) { cell.SetCellValue(drValue + "%"); cell.CellStyle.Alignment = HorizontalAlignment.Right; } } protected override void SetTotal(NPOI.SS.UserModel.ISheet sheet, ref int rowIndex, int startRowIndex) { base.SetTotal(sheet, ref rowIndex, startRowIndex); } } }
IdentityCardMonthPayDetailSheet.cs
/* ============================================================================== * 功能描述:IdentityCardMonthPayDetailSheet * 創 建 者:Zouqj * 建立日期:2015/8/24 17:52:00 ==============================================================================*/ using Core.Receivable; using Core.Reconciliation; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.SS.Util; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Core.Excel.IdentityCardMonthPayOff { /// <summary> /// 身份證月結明細 /// </summary> public class IdentityCardMonthPayDetailSheet : GenerateSheet<IdentityCardStatement> { public IdentityCardMonthPayDetailSheet(List<IdentityCardStatement> dataSource, List<object> date2, string sheetName) : base(dataSource, date2, sheetName) { } protected override List<ColumnsMapping> InitializeColumnHeadData() { List<ColumnsMapping> result = new List<ColumnsMapping>(); result.Add(new ColumnsMapping() { ColumnsText = "月份", ColumnsData = GetPropertyName(p => p.ValideMonth), ColumnsIndex = 0, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "客戶名稱", ColumnsData = GetPropertyName(p => p.CustomerName), ColumnsIndex = 1, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "姓名", ColumnsData = GetPropertyName(p => p.IdentityName), ColumnsIndex = 2, IsTotal = false, Width = 17 }); result.Add(new ColumnsMapping() { ColumnsText = "身份證號碼", ColumnsData = GetPropertyName(p => p.IdentityCardNO), ColumnsIndex = 3, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "成本調用次數", ColumnsData = GetPropertyName(p => p.CostCallCount), ColumnsIndex = 4, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "成本費用", ColumnsData = GetPropertyName(p => p.CostFee), ColumnsIndex = 5, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "收入調用次數", ColumnsData = GetPropertyName(p => p.IncomeCallCount), ColumnsIndex = 6, IsTotal = false, Width = 18 }); result.Add(new ColumnsMapping() { ColumnsText = "收入費用", ColumnsData = GetPropertyName(p => p.IncomeFee), ColumnsIndex = 7, IsTotal = false, Width = 18 }); result.Add(new ColumnsMapping() { ColumnsText = "毛利", ColumnsData = GetPropertyName(p => p.GrossProfit), ColumnsIndex = 8, IsTotal = false, Width = 15 }); result.Add(new ColumnsMapping() { ColumnsText = "毛利率", ColumnsData = GetPropertyName(p => p.GrossMargin), ColumnsIndex = 9, IsTotal = false, Width = 15 }); return result; } protected override void SetColumnHead(NPOI.SS.UserModel.ISheet sheet, ref int rowIndex) { if (this.ColumnHeadList.Count > 0) { // 凍結 //sheet.CreateFreezePane(1, 4); // 全部列頭居中 this.HeadStyle.Alignment = HorizontalAlignment.Center; this.HeadStyle.VerticalAlignment = VerticalAlignment.Center; for (int i = 0; i < 2; i++) { IRow row = sheet.CreateRow(rowIndex); foreach (ColumnsMapping cm in this.ColumnHeadList) { ICell cell = null; if (i == 0) { if (cm.ColumnsIndex < 4) { // 合併行 sheet.AddMergedRegion(new CellRangeAddress(rowIndex, rowIndex + 1, cm.ColumnsIndex, cm.ColumnsIndex)); cell = row.CreateCell(cm.ColumnsIndex); // 設置列寬 SetColumnsWidth(sheet, cm.ColumnsIndex, cm.Width); // 設置列頭樣式 cell.CellStyle = this.HeadStyle; cell.SetCellValue(cm.ColumnsText); } else if (cm.ColumnsIndex == 4 || cm.ColumnsIndex == 6|| cm.ColumnsIndex == 8) { sheet.AddMergedRegion(new CellRangeAddress(rowIndex, rowIndex, cm.ColumnsIndex, cm.ColumnsIndex + 1)); cell = row.CreateCell(cm.ColumnsIndex); SetColumnsWidth(sheet, cm.ColumnsIndex, cm.Width); cell.CellStyle = this.HeadStyle; if (cm.ColumnsIndex == 4) cell.SetCellValue("成本"); else if (cm.ColumnsIndex == 6) cell.SetCellValue("收入"); else if (cm.ColumnsIndex == 8) cell.SetCellValue("毛利"); for (int j = 4; j <= 9; j++) { if (j == 4 || j == 6|| j == 8) continue; cell = row.CreateCell(j); cell.CellStyle = this.HeadStyle; } } } else { if (cm.ColumnsIndex >= 4 && cm.ColumnsIndex <= 9) { cell = row.CreateCell(cm.ColumnsIndex); cell.CellStyle = this.HeadStyle; SetColumnsWidth(sheet, cm.ColumnsIndex, cm.Width); cell.SetCellValue(cm.ColumnsText); } else if (cm.ColumnsIndex >= 0 && cm.ColumnsIndex<=3) { cell = row.CreateCell(cm.ColumnsIndex); cell.CellStyle = this.HeadStyle; } } } rowIndex++; } } } protected override void SetCellValue(ICell cell, int rowIndex, string drValue, ColumnsMapping columns) { base.SetCellValue(cell, rowIndex, drValue, columns); if (columns.ColumnsIndex == 9) { cell.SetCellValue(drValue + "%"); cell.CellStyle.Alignment = HorizontalAlignment.Right; } if (columns.ColumnsIndex ==3) //身份證 { //cell.SetCellType(CellType.Formula); } } /// <summary> /// 合併單元格 /// </summary> /// <param name="sheet">要合併單元格所在的sheet</param> /// <param name="rowstart">開始行的索引</param> /// <param name="rowend">結束行的索引</param> /// <param name="colstart">開始列的索引</param> /// <param name="colend">結束列的索引</param> public static void SetCellRangeAddress(ISheet sheet, int rowstart, int rowend, int colstart, int colend) { CellRangeAddress cellRangeAddress = new CellRangeAddress(rowstart, rowend, colstart, colend); sheet.AddMergedRegion(cellRangeAddress); } private string IsNull(object value) { if (value == null) { return ""; } return value.ToString(); } } }
IdentityCardMonthPay.cs
using Core.Excel; using Core.Excel.IdentityCardMonthPayOff; using Core.Filters; using Core.Receivable; using Core.Statistical.Repositories; using ProjectBase.Data; using ProjectBase.Utils; /* ============================================================================== * 功能描述:IdentityCardMonthPay * 創 建 者:Zouqj * 建立日期:2015/8/19 18:06:28 ==============================================================================*/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ProjectBase.Utils.Entities; using Core.Reconciliation; namespace Core.Statistical { public class IdentityCardMonthPay : DomainObject<IdentityCardMonthPay, int, IIdentityCardMonthPayRepository> { #region property /// <summary> /// 身份證調驗數量 /// </summary> public virtual int ValidedCount { get; set; } /// <summary> /// 建立時間 /// </summary> public virtual DateTime? CreateTime { get; set; } /// <summary> /// 結算月份 /// </summary> public virtual string SettleMonth { get; set; } /// <summary> /// 月結狀態 /// </summary> public virtual MonthlyBalanceStatus Status { get; set; } /// <summary> /// 總成本 /// </summary> public virtual decimal TotalCost { get; set; } /// <summary> /// 總收入 /// </summary> public virtual decimal TotalIncome { get; set; } /// <summary> /// 總毛利 /// </summary> public virtual decimal TotalMargin { get { return (TotalIncome - TotalCost).DecimalFormat(); } } /// <summary> /// 毛利率 毛利率=(總收入-總的支出的成本)/總收入*100% /// </summary> public virtual decimal MarginRate { get { return ((TotalIncome - TotalCost) / TotalIncome * 100).DecimalFormat(); } } #endregion #region common method /// <summary> /// 根據結算月份查找記錄 /// </summary> /// <param name="SettleMonth">結算月份</param> /// <returns></returns> public static long GetModelBySettleMonth(string SettleMonth) { return Dao.GetModelBySettleMonth(SettleMonth); } /// <summary> /// 分頁獲取數據 /// </summary> /// <param name="filter"></param> /// <returns></returns> public static IPageOfList<IdentityCardMonthPay> GetByFilter(IdentityCardMonthPayFilter filter) { return Dao.GetByFilter(filter); } /// <summary> /// 獲取結算月份是否鎖定 /// </summary> /// <param name="SettleMonth">結算月份</param> /// <returns></returns> public static bool GetIsLockBySettleMonth(string SettleMonth) { return Dao.GetIsLockBySettleMonth(SettleMonth); } public static List<IdentityCardMonthPay> GetListBySettleMonth(string ids) { return Dao.GetListBySettleMonth(ids); } /// <summary> /// 導出身份證月結excel /// </summary> /// <param name="excelPath">excel生成路徑</param> /// <param name="filter"></param> /// <param name="payOffMonthlist"></param> public static void ExportExcel(string excelPath, IdentityCardMonthPayFilter filter, string payOffMonthlist) { //總表 List<IdentityCardMonthPay> queryData = GetListBySettleMonth(filter.ListID); GenerateExcel genExcel = new GenerateExcel(); genExcel.SheetList.Add(new IdentityCardMonthPayOffSheet(queryData, "身份證月結總表")); string[] sArray = payOffMonthlist.Contains(",") ? payOffMonthlist.Split(',') : new string[] { payOffMonthlist }; for (int i = 0; i < sArray.Length; i++) { var identityCardMonthPayDetail = IdentityCardStatement.GetByFilter(new IdentityCardFilter { IsMonthPayOff = 1, SettleMonth = sArray[i], PageSize=int.MaxValue }).ToList(); //月結明細 genExcel.SheetList.Add(new IdentityCardMonthPayDetailSheet(identityCardMonthPayDetail, null, sArray[i] + "身份證月結代表細")); } genExcel.ExportExcel(excelPath); } #endregion } }
#region 導出身份證月結表 /// <summary> /// 導出月結表 /// </summary> /// <param name="filter"></param> /// <returns></returns> public JsonResult ExportExcelIdentityCard(IdentityCardMonthPayFilter filter, string payOffMonthlist) { string excelPath = this.Server.MapPath(string.Format(IdentityCardExcelDir + "身份證月結表_{0}.xlsx",
DateTime.Now.ToString("yyyyMMddHHmmss"))); MvcApplication._QueueIdentityCard.Enqueue(new IdentityCardMonthPayPara { ExcelPath = excelPath, Filter = filter,
PayOffMonthlist = payOffMonthlist }); //MvcApplication.OutputIdentityCardExcel(); var result = new { IsSuccess = true, Message = "成功" }; return Json(result); } /// <summary> /// 已生成的月結表列表 /// </summary> /// <returns></returns> public ActionResult LoadIdentityCardExcelList() { string myDir = Server.MapPath("~"+IdentityCardExcelDir); if (Directory.Exists(myDir) == false)//若是不存在就建立file文件夾 { Directory.CreateDirectory(myDir); } DirectoryInfo dirInfo = new DirectoryInfo(myDir); List<LinkEntity> list = LinkEntityExt.ForFileLength(dirInfo, IdentityCardExcelDir); return View("LoadExcelList", list); } #endregion
Global.asax.cs,在應用程序啓動時,監聽隊列,若是隊列裏面有數據,則進行導出操做,這樣的話,即便操做人員離開了當前頁面,也不影響生產excel操做。並且使用隊列,能夠防止併發產生的問題。
public static Queue<IdentityCardMonthPayPara> _QueueIdentityCard = new Queue<IdentityCardMonthPayPara>();
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
//BundleTable.EnableOptimizations = true;
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
RegisterContainer(ProjectBase.Data.IocContainer.Instance.Container);
log4net.Config.XmlConfigurator.Configure();
OutputIdentityCardExcel(); //這裏進行註冊
}
/// <summary> /// 導出身份證月結表excel列表 /// </summary> public static void OutputIdentityCardExcel() { IdentityCardMonthPayPara model = null; ThreadPool.QueueUserWorkItem(o => { while (true) { if (_QueueIdentityCard != null && _QueueIdentityCard.Count > 0) { model = _QueueIdentityCard.Dequeue(); if (model != null) { IdentityCardMonthPay.ExportExcel(model.ExcelPath, model.Filter, model.PayOffMonthlist); } else { Thread.Sleep(6000); } } else { Thread.Sleep(6000); } } }); }
實時導出有好幾種方式,我這裏採用FileResult 來進行導出,使用FileResult導出要求服務器上面必須存在excel文件。在這裏,若是沒有選中任何行,我就導出查詢到的全部數據,不然導出選中行的數據,因爲數據不是不少,就採用實時導出的方式。
前臺js代碼:
//導出Excel function exportExcel(table) { var nTrs = table.fnGetNodes();//fnGetNodes獲取表格全部行,nTrs[i]表示第i行tr對象 var row; var strdid = ''; var selectCounts = 0; for (var i = 0; i < nTrs.length; i++) { if ($(nTrs[i])[0].cells[0].children[0].checked) { row = table.fnGetData(nTrs[i]);//fnGetData獲取一行的數據 selectCounts++; strdid += "" + row.ID + ","; } } strdid = strdid.length > 0 ? strdid.substring(0, strdid.length - 1) : strdid; if (selectCounts < 1) { //按照查詢結果進行導出 window.location.href = '@Url.Action("ExportExcelByFilter", "Reconciliation")?' + "CusShortName=" + $("#CusShortName").val() +"&&LoadBillNum=" + $("#LoadBillNum").val() +"&&PostingTime=" + $("#PostingTime").val() + "&&PostingTimeTo=" + $("PostingTimeTo").val() +
"&&ExceptionType="+$("#ExceptionType").val(); } else { //導出選中行 //window.location.href = '@Url.Action("ExportExcelBySelect", "Reconciliation")?' + "ListID=" + strdid; 地址欄太長會超出 $.post('@Url.Action("ExportExcelBySelect", "Reconciliation")', { "ListID": strdid }, function (data) { window.location.href = data; }); } }
控制器代碼
/// <summary> /// 導出選中的異常記錄 /// </summary> /// <param name="ListID"></param> /// <returns></returns> public JsonResult ExportExcelBySelect(string ListID) { string url = "/Downloads/WayBillException/運單異常記錄.xls"; string excelUrl = Server.MapPath("~" + url); Core.Reconciliation.WayBillException.ExportExcel(excelUrl, ListID); return Json(url); } /// <summary> /// 導出查詢的異常記錄 /// </summary> /// <param name="filter"></param> /// <returns></returns> public FileResult ExportExcelByFilter(WayBillExceptionFilter filter) { filter.PageSize = int.MaxValue; string excelUrl = Server.MapPath("~/Downloads/WayBillException/運單異常記錄.xls"); Core.Reconciliation.WayBillException.ExportExcel(filter,excelUrl); return File(excelUrl, "application/ms-excel", "運單異常記錄.xls"); }
工做太忙了,無暇整理,還望見諒!之後抽空慢慢完善!至於園友提到完整Demo,這個比較費時,之後我會整理一個。涉及的東西比較多,諸如:Nhibernate3.3代碼映射、unity注入、倉儲模式、多層架構等等。以前有寫過前篇的一個系列,只是側重於UI和控制器交互這一塊,有興趣的朋友能夠去瞧一下。地址:ASP.NET MVC搭建項目後臺UI框架—一、後臺主框架
感觸:工做中項目裏一般使用了一種或幾種框架,而每一種框架都是一系列設計模式的集合,想要一會兒所有說明白,真的須要時間,有些東西更是難以用文字表述,只能本身慢慢領悟。