我需要制作一个'export to excel'功能。
Excel是一个二进制文件,如果您使用其XML格式,它会在msExcel上发送警告。
我目前正在做的是保存一个状态对象(因为我需要知道用户正在进行的各种更改)和我的所有数据,并使用ajax将其传递给.net MVC控制器,它使用了一个库创建* .xlsx文件。
客户方:
$.ajax({
type: "POST",
url: "/path/to/exportController",
data: exporter.getData(),
success: success,
error: error,
dataType: 'json'
});
服务器端:
public ActionResult Excel(mySpecialandIrrelevantDescriptiveClass jsonData)
{
//excel generation logic
.....
}
从我看到它的方式来看,我在这里有3个选项:
创建一个流并将其推回到ajax请求 - 但是从我收集的内容来看,ajax无法真正推动使用生成的二进制流的下载请求
将文件保存在服务器硬盘上,为其返回一个公共URL并打开一个带有新URL的新弹出窗口,获取下载提示并以某种方式关闭窗口,这样看起来不会很难看。
忘记了ajax,将所有内容推送到一些隐藏的表单字段并将其发布到服务器,再次打开一个新窗口并等待响应,然后关闭它。
选项#2将要求我创建一个不断清除生成的文件和URL的任务,这是一个巨大的麻烦,因为该平台将单独获得大约10-20k的点击量。
达到我需要的最佳方式是什么?
答案 0 :(得分:3)
所以这就是我最终得到它的方式:
您不能使用ajax返回二进制文件 - 您将收到其数据 - 但无法显示二进制文件
我使用EPPlus作为excel库,并通过一般HTML表单隐藏字段中的post方法传递数据。 使用流作为返回值生成输出,从而使用户保持在页面上而不刷新/重定向
服务器:
//the expected data description - automatic tool @ http://json2csharp.com/
public class ExpectedJSON
{
public class SomeDataSet
{
public string dude{ get; set; }
public string what { get; set; }
public string foo { get; set; }
public string bar { get; set; }
public string baz { get; set; }
public int asd { get; set; }
public string someDate { get; set; }
public string wat { get; set; }
public string grrr { get; set; }
}
public class AnotherDataSet
{
public int type { get; set; }
public string date { get; set; }
public string dancing { get; set; }
public double camels { get; set; }
public int are { get; set; }
public int crying { get; set; }
public double _for { get; set; }
public double some { get; set; }
public double beer { get; set; }
}
public class MoreData
{
public int dark { get; set; }
public double side { get; set; }
public int of { get; set; }
public int the { get; set; }
public double moon { get; set; }
public double iz { get; set; }
public double da { get; set; }
public string bomb { get; set; }
}
}
public class ExportToController : Controller
{
public ActionResult Excel([FromUri(Name= "someData")] string someDataSet,
[FromUri(Name = "anotherData")] string anotherDataSet,
[FromUri(Name = "moreData")] string moreData)
{
ExpectedJSON.SomeDataSet someDataSetJson = JsonConvert.DeserializeObject<ExpectedJSON.SomeDataSet>(someData);
ExpectedJSON.AnotherDataSet[] anotherDataSetJson = JsonConvert.DeserializeObject<Campaign.OnlineComulativeDailyBuildChart[]>(anotherData);
ExpectedJSON.MoreData[] moreDataJson = JsonConvert.DeserializeObject<Campaign.OnlineSitesGrid[]>(moreData);
string fileName = "file.xlsx";
ExcelPackage p = new ExcelPackage();
p.Workbook.Worksheets.Add("Some Sheet");
ExcelWorksheet ws = p.Workbook.Worksheets[1];
//excel library logic follows...
//...
//..
//stream logic
MemoryStream stream = new MemoryStream(p.GetAsByteArray());
FileStreamResult result = new FileStreamResult(stream, "application/vnd.ms-excel")
{
FileDownloadName = fileName
};
return result;
}
}
HTML:
<form id="exportToExcel" action="../ExportTo/Excel/" target="_blank" method="post">
<input type="hidden" id="someData" name="someData" />
<input type="hidden" id="anotherData" name="anotherData" />
<input type="hidden" id="moreData" name="moreData" />
<button type="submit">export</button>
</form>
我的所有数据组件(需要导出)都将其数据对象签名为通用对象,以便在提交时使用JSON.stringify使用json表示填充value属性:
function bindEvents() {
var exportForm = $("#exportToExcel");
var someData= exportForm.find("#someData");
var anotherData= exportForm.find("#anotherData");
var moreData = exportForm.find("#moreData");
exportForm.on('submit', function (e) {
someData.attr("value", JSON.stringify(exporter.getData().someData));
anotherData.attr("value", JSON.stringify(exporter.getData().anotherData));
moreData .attr("value", JSON.stringify(exporter.getData().moreData));
});
}
使用rails / sinatra / nodeJS的分钟数 - 使用.net的天/周 - 但是你有它。
答案 1 :(得分:0)
这样的问题很多:
我可以继续这样做:)
他们都建议使用<form>
,<iframe>
或window.location
进行某种重定向。
这可能是要走的路,但如果你有足够的冒险精神,我也会尝试HTML5 Blob API,文件系统和/或类型数组的组合。