通用的web系统数据导出功能设计实现(导出excel2003/2007 word pdf zip等)前言我们在做web系统中,导出也是很常用的一个功能,如果每一个数据列表都要对应写一个导出的方法不太现实。现在就想设计一个共通的功能来实现这个导出。 需求分析在开始之前我们先要明白我们要实现怎样一个功能
技术分析设计1、生成文件基本可以使用开源的组件实现
com.exporter(grid) 把grid对象传递给前台导出对象,取得题头的相关信息及grid的url和queryParams传给后台重新取数据 .paging(2,20) 分页处理表示每页20条,导出第2页,如果第两个参数为0则表示不分页 .compress('zip’) 文件生成之后压缩成zip文件 .download(‘xlsx’); 导出excel2007格式的文件 设计成这样基本足够,但是有可能我的grid中没有exporter需要的信息,不能直接com.exporter(grid)这种写法,或者大家不喜欢linq的这种写法,我们再设计另一种参数的写法: com.exporter({ fileType:’xls’, compressType:’none’, dataGetter:’api’, 因为我们数据基本要到后台重新取数据,所以怎么取数据可能有很多种方法,dataGetter就是定义用哪一种方式取数据 dataUrl:’/mms/api/recive’ 接下来的dataUrl及dataParams都是dataGetter=‘api’中用到的参数 dataParams:{BillNo:’20130701’,Supplier:’huawei’,page:1,rows:0}, titles: [[]] 多行的表头数据,跟easyui的多行表头格式设计一致 }).download(); 那么前台基本就可以这样,有了这两种写法,使用起来就很方便了。
new Exporter() .Data(new ApiData()) 定义数据取得方式 .AddFormatter("sex",new SexFormatter()) 添加sex列的formatter .Export(new PdfExport()) 设置导出pdf .Compress(new ZipCompress()) 压缩为zip .Download(); 下载文件向浏览器输出 我们要设计一个Exporter的类,它下面有Data Export Compress 等方法
public Exporter Data(IDataGetter data) { } 我在具体取数据的方法中继承IDataGetter接口并实现 public class ApiData : IDataGetter { public object GetData(HttpContext context) { .... return data; } } 这样的话,假如我的取数据方式不太一样,我只要 new Exporter().Data(new XXDataGetter())就行了
public interface IExport { string suffix { get;} void MergeCell(int x1,int y1,int x2,int y2); void FillData(int x, int y,string field, object data); void Init(object data); Stream SaveAsStream(); void SetHeadStyle(int x1, int y1, int x2, int y2); void SetRowsStyle(int x1, int y1, int x2, int y2); } 然后在 XlsExport XlsxExporter DocExporter PdfExporter中实现这个接口就可,然后就可以实现导出不同格式的文档的
new Exporter() .Data("api") .Export("xlsx") .Compress("zip") .Download(); 这样的话后台这个exporter类也挺好用的了,那么接下来我们再来谈谈如何具体实现吧
技术实现设计时我们先实现后台 public class Column { public Column() { rowspan = 1; colspan = 1; } public string field { get; set; } public string title { get; set; } public int rowspan { get; set; } public int colspan { get; set; } public bool hidden { get; set; } } 定义压缩接口 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Zephyr.Core { public interface ICompress { string Suffix(string orgSuffix); Stream Compress(Stream fileStream,string fullName); } } 定义数据获取的接口 using System.Web; namespace Zephyr.Core { public interface IDataGetter { object GetData(HttpContext context); } } 定义文件导出的接口 using System.IO; namespace Zephyr.Core { public interface IExport { string suffix { get;} void MergeCell(int x1,int y1,int x2,int y2); void FillData(int x, int y,string field, object data); void Init(object data); Stream SaveAsStream(); void SetHeadStyle(int x1, int y1, int x2, int y2); void SetRowsStyle(int x1, int y1, int x2, int y2); } } 定义格式化接口 namespace Zephyr.Core { public interface IFormatter { object Format(object value); } }
2、基本的元素都定义好了,我们再来实现Exporter导出类,关键性的代码就在这里了 using System; using System.Collections.Generic; using System.IO; using System.Web; using Newtonsoft.Json; using Zephyr.Utils; namespace Zephyr.Core { public class Exporter { const string DEFAULT_EXPORT = "xls"; const string DEFAULT_DATAGETTER = "api"; const string DEFAULT_COMPRESS = "none"; private Dictionary<string, Type> _compress = new Dictionary<string, Type>() { { "zip", typeof(ZipCompress)}, {"none",typeof(NoneCompress)} }; private Dictionary<string, Type> _dataGetter = new Dictionary<string, Type>() { { "api", typeof(ApiData) } }; private Dictionary<string, Type> _export = new Dictionary<string, Type>() { { "xls", typeof(XlsExport) }, { "xlsx", typeof(XlsxExport) } , { "doc", typeof(HtmlDocExport) }, { "pdf", typeof(PdfExport) } }; private Dictionary<string,IFormatter> _fieldFormatter = new Dictionary<string,IFormatter>(); private object _data; private List<List<Column>> _title; private Stream _fileStream = null; private string _fileName = string.Empty; private string _suffix = string.Empty; public static Exporter Instance() { var export = new Exporter(); var context = HttpContext.Current; if (context.Request.Form["titles"]!=null) export.Title(JsonConvert.DeserializeObject<List<List<Column>>>(context.Request.Form["titles"])); if (context.Request.Form["dataGetter"] != null) export.Data(context.Request.Form["dataGetter"]); if (context.Request.Form["fileType"] != null) export.Export(context.Request.Form["fileType"]); if (context.Request.Form["compressType"] != null) export.Compress(context.Request.Form["compressType"]); return export; } public Exporter Data(IDataGetter data) { _data = data.GetData(HttpContext.Current); return this; } public Exporter Data(string type) { var dataGetter = GetActor<IDataGetter>(_dataGetter, DEFAULT_DATAGETTER,type); return Data(dataGetter); } public Exporter Data(object data) { _data = data; return this; } public Exporter AddFormatter(string field,IFormatter formatter) { _fieldFormatter[field] = formatter; return this; } public Exporter Title(List<List<Column>> title) { _title = title; return this; } public Exporter FileName(string fileName) { _fileName = fileName; return this; } public Exporter Export(string type) { var export = GetActor<IExport>(_export, DEFAULT_EXPORT, type); return Export(export); } public Exporter Export(IExport export) { if (_title == null) { _title = new List<List<Column>>(); _title.Add(new List<Column>()); EachHelper.EachListHeader(_data, (i, field, type) => _title[0].Add(new Column() { title = field, field = field, rowspan = 1, colspan = 1 })); } Dictionary<int, int> currentHeadRow = new Dictionary<int, int>(); Dictionary<string, List<int>> fieldIndex = new Dictionary<string, List<int>>(); Func<int, int> GetCurrentHeadRow = cell => currentHeadRow.ContainsKey(cell) ? currentHeadRow[cell] : 0; var currentRow = 0; var currentCell = 0; export.Init(_data); //生成多行题头 for (var i = 0; i < _title.Count; i++) { currentCell = 0; for (var j = 0; j < _title[i].Count; j++) { var item = _title[i][j]; if (item.hidden) continue; while (currentRow < GetCurrentHeadRow(currentCell)) currentCell++; export.FillData(currentCell, currentRow, "title_" + item.field, item.title); if (item.rowspan + item.colspan > 2) export.MergeCell(currentCell, currentRow, currentCell + item.colspan - 1, currentRow + item.rowspan - 1); if (!string.IsNullOrEmpty(item.field)) { if (!fieldIndex.ContainsKey(item.field)) fieldIndex[item.field] = new List<int>(); fieldIndex[item.field].Add(currentCell); } for (var k = 0; k < item.colspan; k++) currentHeadRow[currentCell] = GetCurrentHeadRow(currentCell++) + item.rowspan; } currentRow++; } //设置题头样式 export.SetHeadStyle(0, 0, currentCell - 1, currentRow - 1); //设置数据样式 var dataCount = 0; EachHelper.EachListRow(_data, (i, r) => dataCount++); export.SetRowsStyle(0, currentRow, currentCell - 1, currentRow + dataCount - 1); //填充数据 EachHelper.EachListRow(_data, (rowIndex, rowData) => { EachHelper.EachObjectProperty(rowData, (i, name, value) => { if (fieldIndex.ContainsKey(name)) foreach (int cellIndex in fieldIndex[name]) { if (_fieldFormatter.ContainsKey(name)) value = _fieldFormatter[name](value); export.FillData(cellIndex, currentRow, name, value); } }); currentRow++; }); _fileStream = export.SaveAsStream(); _suffix = export.suffix; if (string.IsNullOrEmpty(_fileName)) _fileName = DateTime.Now.ToString("yyyyMMddHHmmss"); return this; } public Exporter Compress(string type) { var compress = GetActor<ICompress>(_compress, DEFAULT_COMPRESS, type); return Compress(compress); } public Exporter Compress(ICompress compress) { _fileStream = compress.Compress(_fileStream,string.Format("{0}.{1}",_fileName,_suffix)); _suffix = compress.Suffix(_suffix); return this; } public void Download() { if (_fileStream != null && _fileStream.Length > 0) ZFiles.DownloadFile(HttpContext.Current, _fileStream, string.Format("{0}.{1}",_fileName,_suffix), 1024 * 1024 * 10); } private T GetActor<T>(Dictionary<string, Type> dict, string defaultKey, string key) { if (!dict.ContainsKey(key)) key = defaultKey; return (T)Activator.CreateInstance(dict[key]); } } }
3、Exporter类实现之后我们还要实现一些接口才能使用 using System; using System.Dynamic; using System.Linq; using System.Web; using Newtonsoft.Json; namespace Zephyr.Core { public class ApiData : IDataGetter { public object GetData(HttpContext context) { dynamic data = null; var url = context.Request.Form["dataAction"]; var param = JsonConvert.DeserializeObject<dynamic>(context.Request.Form["dataParams"]); var route = url.Replace("/api/", "").Split('/'); // route[0]=mms,route[1]=send,route[2]=get var type = Type.GetType(String.Format("Zephyr.Areas.{0}.Controllers.{1}ApiController,Zephyr.Web", route), false, true); if (type != null) { var instance = Activator.CreateInstance(type); var action = route.Length > 2 ? route[2] : "Get"; var methodInfo = type.GetMethod(action); var parameters = new object[] { new RequestWrapper().SetRequestData(param) }; data = methodInfo.Invoke(instance, parameters); if (data.GetType() == typeof(ExpandoObject)) { if ((data as ExpandoObject).Where(x => x.Key == "rows").Count() > 0) data = data.rows; } } return data; } } }
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Drawing; using Zephyr.Utils; using Zephyr.Utils.EPPlus; using Zephyr.Utils.EPPlus.Style; namespace Zephyr.Core { public class XlsxExport:IExport { public string suffix { get {return "xlsx"; } } private ExcelPackage package; private ExcelWorksheet sheet; public void Init(object data) { package = new ExcelPackage(); sheet = package.Workbook.Worksheets.Add("sheet1"); } public void MergeCell(int x1,int y1,int x2,int y2) { sheet.Cells[y1+1, x1+1, y2+1, x2+1].Merge = true; } public virtual void FillData(int x, int y,string field, object value) { if (ZGeneric.IsTypeIgoreNullable<DateTime>(value)) sheet.Cells[y + 1, x + 1].Style.Numberformat.Format = "yyyy-MM-dd hh:mm:ss"; sheet.Cells[y + 1, x + 1].Value = value; } public virtual void SetHeadStyle(int x1, int y1, int x2, int y2) { using (var head = sheet.Cells[y1 + 1, x1 + 1, y2 + 1, x2 + 1]) // set head style { head.Style.Font.Bold = true; head.Style.Font.Size = 12; head.Style.Font.Name = "Arial"; head.Style.Border.Top.Style = ExcelBorderStyle.Thin; head.Style.Border.Top.Color.SetColor(Color.Gray); head.Style.Border.Right.Style = ExcelBorderStyle.Thin; head.Style.Border.Right.Color.SetColor(Color.Gray); head.Style.Border.Bottom.Style = ExcelBorderStyle.Thin; head.Style.Border.Bottom.Color.SetColor(Color.Gray); head.Style.Border.Left.Style = ExcelBorderStyle.Thin; head.Style.Border.Left.Color.SetColor(Color.Gray); head.Style.VerticalAlignment = ExcelVerticalAlignment.Center; head.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center; head.Style.Fill.PatternType = ExcelFillStyle.Solid; head.Style.Fill.BackgroundColor.SetColor(Color.LightBlue); } } public virtual void SetRowsStyle(int x1, int y1, int x2, int y2) { using (var data = sheet.Cells[y1 + 1, x1 + 1, y2 + 1, x2 + 1])// set data style { data.Style.Font.Name = "Arial"; data.Style.Font.Size = 11; data.Style.Border.Top.Style = ExcelBorderStyle.Thin; data.Style.Border.Top.Color.SetColor(Color.Gray); data.Style.Border.Right.Style = ExcelBorderStyle.Thin; data.Style.Border.Right.Color.SetColor(Color.Gray); data.Style.Border.Bottom.Style = ExcelBorderStyle.Thin; data.Style.Border.Bottom.Color.SetColor(Color.Gray); data.Style.Border.Left.Style = ExcelBorderStyle.Thin; data.Style.Border.Left.Color.SetColor(Color.Gray); } } public Stream SaveAsStream() { var ms = new MemoryStream(); package.SaveAs(ms); package = null; sheet = null; return ms; } } }
using System.IO; using Zephyr.Utils; using Zephyr.Utils.NPOI.HSSF.UserModel; using Zephyr.Utils.NPOI.SS.UserModel; using Zephyr.Utils.NPOI.HSSF.Util; using Zephyr.Utils.NPOI.SS.Util; namespace Zephyr.Core { public class XlsExport:IExport { public string suffix { get {return "xls"; } } private HSSFWorkbook workbook; private ISheet sheet; public void Init(object data) { workbook = new HSSFWorkbook(); sheet = workbook.CreateSheet("sheet1"); sheet.DefaultRowHeight = 200 * 20; } public void MergeCell(int x1,int y1,int x2,int y2) { CellRangeAddress range = new CellRangeAddress(y1, y2, x1, x2); sheet.AddMergedRegion(range); } public virtual void FillData(int x, int y,string field, object value) { var row = sheet.GetRow(y) ?? sheet.CreateRow(y); var cell = row.GetCell(x) ?? row.CreateCell(x); switch ((value ?? string.Empty).GetType().Name.ToLower()) { case "int32": case "int64": case "decimal": cell.CellStyle.Alignment = HorizontalAlignment.RIGHT; cell.SetCellValue(ZConvert.To<double>(value, 0)); break; default: cell.SetCellValue(ZConvert.ToString(value)); break; } } public virtual void SetHeadStyle(int x1, int y1, int x2, int y2) { var style = GetHeadStyle(); for (var y = y1; y <= y2; y++) { var row = sheet.GetRow(y) ?? sheet.CreateRow(y); for (var x = x1; x <= x2; x++) { var cell = row.GetCell(x) ?? row.CreateCell(x); cell.CellStyle = style; } } } public virtual void SetRowsStyle(int x1, int y1, int x2, int y2) { var style = GetDataStyle(); for (var y = y1; y <= y2; y++) { var row = sheet.GetRow(y) ?? sheet.CreateRow(y); for (var x = x1; x <= x2; x++) { var cell = row.GetCell(x) ?? row.CreateCell(x); cell.CellStyle = style; } } } public Stream SaveAsStream() { var ms = new MemoryStream(); workbook.Write(ms); ms.Flush(); ms.Position = 0; workbook = null; sheet = null; return ms; } private ICellStyle GetHeadStyle() { //表头样式 var headStyle = workbook.CreateCellStyle(); headStyle.Alignment = HorizontalAlignment.CENTER;//居中对齐 headStyle.VerticalAlignment = VerticalAlignment.CENTER; //表头单元格背景色 headStyle.FillForegroundColor = HSSFColor.LIGHT_GREEN.index; headStyle.FillPattern = FillPatternType.SOLID_FOREGROUND; //表头单元格边框 headStyle.BorderTop = BorderStyle.THIN; headStyle.TopBorderColor = HSSFColor.BLACK.index; headStyle.BorderRight = BorderStyle.THIN; headStyle.RightBorderColor = HSSFColor.BLACK.index; headStyle.BorderBottom = BorderStyle.THIN; headStyle.BottomBorderColor = HSSFColor.BLACK.index; headStyle.BorderLeft = BorderStyle.THIN; headStyle.LeftBorderColor = HSSFColor.BLACK.index; //表头字体设置 var font = workbook.CreateFont(); font.FontHeightInPoints = 12;//字号 font.Boldweight = 600;//加粗 //font.Color = HSSFColor.WHITE.index;//颜色 headStyle.SetFont(font); return headStyle; } private ICellStyle GetDataStyle() { //数据样式 var dataStyle = workbook.CreateCellStyle(); dataStyle.Alignment = HorizontalAlignment.LEFT;//左对齐 //数据单元格的边框 dataStyle.BorderTop = BorderStyle.THIN; dataStyle.TopBorderColor = HSSFColor.BLACK.index; dataStyle.BorderRight = BorderStyle.THIN; dataStyle.RightBorderColor = HSSFColor.BLACK.index; dataStyle.BorderBottom = BorderStyle.THIN; dataStyle.BottomBorderColor = HSSFColor.BLACK.index; dataStyle.BorderLeft = BorderStyle.THIN; dataStyle.LeftBorderColor = HSSFColor.BLACK.index; //数据的字体 var datafont = workbook.CreateFont(); datafont.FontHeightInPoints = 11;//字号 dataStyle.SetFont(datafont); return dataStyle; } } }
using System; using System.Collections.Generic; using System.IO; using System.Drawing; using Zephyr.Utils; using Zephyr.Utils.Gios.Pdf; using System.Data; namespace Zephyr.Core { public class PdfExport:IExport { public string suffix { get {return "pdf"; } } private DataTable table; private List<string> title; public void Init(object data) { var type = ZGeneric.GetGenericType(data); var tableName = ZGeneric.IsDynamicType(type) ? string.Empty : type.Name; table = new DataTable(tableName); EachHelper.EachListHeader(data, (rowIndex, name, cellType) => { string typeName = cellType.ToString(); if (cellType.IsGenericType) typeName = cellType.GetGenericArguments()[0].ToString(); Type newType = Type.GetType(typeName, false); if (newType != null) table.Columns.Add(name, newType); }); table.BeginLoadData(); title = new List<string>(); } public void MergeCell(int x1,int y1,int x2,int y2) { throw new Exception("pdf未实现多选title"); } public virtual void FillData(int x, int y,string field, object value) { if (field.StartsWith("title_")) { title.Add(field.Split('_')[1]); return; } if (table.Rows.Count< y) table.Rows.Add(table.NewRow()); if (value != null && (Type.GetType(value.GetType().ToString(), false) != null)) table.Rows[y-1][field] = value; } public virtual void SetHeadStyle(int x1, int y1, int x2, int y2) { } public virtual void SetRowsStyle(int x1, int y1, int x2, int y2) { } public Stream SaveAsStream() { table.EndLoadData(); table.AcceptChanges(); var removes = new List<string>(); foreach (DataColumn dc in table.Columns) if (title.IndexOf(dc.ColumnName) == -1) var pdfTitle = table.TableName; // Starting instantiate the document. // Remember to set the Docuement Format. In this case, we specify width and height. PdfDocument myPdfDocument = new PdfDocument(PdfDocumentFormat.InCentimeters(21, 29.7)); // Now we create a Table of 100 lines, 6 columns and 4 points of Padding. PdfTable myPdfTable = myPdfDocument.NewTable(new Font("Arial", 12), table.Rows.Count, table.Columns.Count, 4); // Importing datas from the datatables... (also column names for the headers!) //myPdfTable.ImportDataTable(Table); myPdfTable.ImportDataTable(table); // Sets the format for correct date-time representation //myPdfTable.Columns[2].SetContentFormat("{0:dd/MM/yyyy}"); // Now we set our Graphic Design: Colors and Borders... myPdfTable.HeadersRow.SetColors(Color.White, Color.Navy); myPdfTable.SetColors(Color.Black, Color.White, Color.Gainsboro); myPdfTable.SetBorders(Color.Black, 1, BorderType.CompleteGrid); //// With just one method we can set the proportional width of the columns. //// It's a "percentage like" assignment, but the sum can be different from 100. //myPdfTable.SetColumnsWidth(new int[] { 5, 25, 16, 20, 20, 15 }); //// You can also set colors for a range of cells, in this case, a row: //myPdfTable.Rows[7].SetColors(Color.Black, Color.LightGreen); // Now we set some alignment... for the whole table and then, for a column. myPdfTable.SetContentAlignment(ContentAlignment.MiddleCenter); myPdfTable.Columns[1].SetContentAlignment(ContentAlignment.MiddleLeft); // Here we start the loop to generate the table... while (!myPdfTable.AllTablePagesCreated) { // we create a new page to put the generation of the new TablePage: PdfPage newPdfPage = myPdfDocument.NewPage(); PdfTablePage newPdfTablePage = myPdfTable.CreateTablePage(new PdfArea(myPdfDocument, 48, 120, 500, 670)); // we also put a Label PdfTextArea pta = new PdfTextArea(new Font("Arial", 26, FontStyle.Bold), Color.Red , new PdfArea(myPdfDocument, 0, 20, 595, 120), ContentAlignment.MiddleCenter, pdfTitle); // nice thing: we can put all the objects in the following lines, so we can have // a great control of layer sequence... newPdfPage.Add(newPdfTablePage); newPdfPage.Add(pta); // we save each generated page before start rendering the next. newPdfPage.SaveToDocument(); } //myPdfDocument.SaveToFile("Example1.pdf"); var stream = new MemoryStream(); myPdfDocument.SaveToStream(stream); return stream; } } }
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Zephyr.Core { public class HtmlDocExport:IExport { public string suffix { get {return "doc"; } } private StringBuilder sBuilder; private int rowIndex; private Dictionary<int,object> row; public void Init(object data) { rowIndex = 0; row = new Dictionary<int, object>(); sBuilder = new StringBuilder(); sBuilder.Append("<table cellspacing=\"0\" rules=\"all\" border=\"1\" style=\"border-collapse:collapse;\">"); sBuilder.Append("<tr>"); } public void MergeCell(int x1,int y1,int x2,int y2) { throw new Exception("htmldoc未实现多选title"); } public virtual void FillData(int x, int y,string field, object value) { if (rowIndex < y) { AppendRow(row.OrderBy(m => m.Key).Select(m => m.Value).ToArray()); row = new Dictionary<int, object>(); rowIndex++; } row[x] = value; } public virtual void SetHeadStyle(int x1, int y1, int x2, int y2) { } public virtual void SetRowsStyle(int x1, int y1, int x2, int y2) { } public Stream SaveAsStream() { AppendRow(row.OrderBy(m => m.Key).Select(m => m.Value).ToArray()); sBuilder.Append("</table"); byte[] byteArray = Encoding.Default.GetBytes(sBuilder.ToString()); var stream = new MemoryStream(byteArray); return stream; } private void AppendRow(object [] values) { sBuilder.Append("<tr>"); foreach(var value in values) sBuilder.Append(string.Format("<td>{0}</td>", value??string.Empty )); sBuilder.Append("</tr>"); } } } ZipCompress利用Ionic.Zip实现压缩 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Zephyr.Utils.Ionic.Zip; namespace Zephyr.Core { public class ZipCompress: ICompress { public string Suffix(string orgSuffix) { return "zip"; } public Stream Compress(Stream fileStream,string fullName) { using (var zip = new ZipFile()) { zip.AddEntry(fullName, fileStream); Stream zipStream = new MemoryStream(); zip.Save(zipStream); return zipStream; } } } } Formatter实现示例 using System; namespace Zephyr.Core { public class SexFormatter:IFormatter { public object Format(object value) { switch(Convert.ToString(value)) { case "0": return "纯爷们"; case "1": return "女汉子"; default: return "春哥"; } } } }
实现了以上这样接口,那么这个Exporter类的功能基本就OK了,如果要拓展一些其它格式以及自定义一些只要实现这些接口就可以,使用很方便了。
public void Download() { Exporter.Instance().Download(); } 除了在设计中说的到那些功能,这个Instance方法要再说一下,可以参照Exporter中的代码看,Instance中我有去请求中取参数titles dataGetter fileType compressType等参数并且实现。所以下载action中只需要这么简单的一句代码就搞定了。我们继续看前台吧 二、前台实现 com.exporter = function (opt) { var self = this; var defaultOptions = { action: "/home/download", dataGetter: "api", dataAction: "", dataParams: {}, titles: [[]], fileType: 'xls', compressType: 'none' }; this.paging = function (page,rows) { self.params.dataParams.page = page; self.params.dataParams.rows = rows; return self; }; this.compress = function () { self.params.compressType = 'zip'; return self; }; this.title = function (filed,title) { self.params.titles[0][filed] = title; return self; }; this.download = function (suffix) { self.params.fileType = suffix || "xls"; self.params.dataParams = JSON.stringify(self.params.dataParams); self.params.titles = JSON.stringify(self.params.titles); var downloadHelper = $('<iframe style="display:none;" id="downloadHelper"></iframe>').appendTo('body')[0]; var doc = downloadHelper.contentWindow.document; if (doc) { doc.open(); doc.write('')//微软为doc.clear()有时会出bug doc.writeln(utils.formatString("<html><body><form id='downloadForm' name='downloadForm' method='post' action='{0}'>" , self.params.action)); for (var key in self.params) doc.writeln(utils.formatString("<input type='hidden' name='{0}' value='{1}'>", key, self.params[key])); doc.writeln('<\/form><\/body><\/html>'); doc.close(); var form = doc.forms[0]; if (form) { form.submit(); } } }; initFromGrid = function (grid) { var options = grid.$element().datagrid('options'); if (grid.treegrid) options.url = options.url || grid.treegrid('options').url; var titles = [[]], length = Math.max(options.frozenColumns.length, options.columns.length); for (var i = 0; i < length; i++) titles[i] = (options.frozenColumns[i] || []).concat(options.columns[i] || []) self.params = $.extend(true, {}, defaultOptions, { dataAction: options.url, dataParams: options.queryParams, titles: titles }); }; if (opt.$element) initFromGrid(opt); else self.params = $.extend(true, {}, defaultOptions, opt); return self; }; 大家基本都能看懂,不需要我再解释了。下载的原理是动态创建了一个iframe把参数写到input中提交到后台。
|
|