1

我需要制作“导出到 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 个选项:

  1. 创建一个流并将其推送回 ajax 请求 - 但从我收集的信息来看,ajax 不能真正推送带有生成的二进制流的下载请求

  2. 将文件保存在服务器硬盘驱动器上,为其返回一个公共 url 并打开一个带有新 URL 的新弹出窗口,获取下载提示并以某种方式关闭窗口,这样它就不会看起来难看。

  3. 忘记ajax,将所有内容推送到一些隐藏的表单字段并将其发布到服务器,再次打开一个新窗口并等待响应,然后关闭它。

选项 #2 将要求我创建一个任务,该任务将不断清除生成的文件和 URL,这是一个巨大的麻烦,因为仅此功能平台就会获得大约 10-20k 次点击。

实现我需要的最佳方法是什么?

4

2 回答 2

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 的天/周 - 但你有它。

于 2013-11-05T15:03:08.157 回答
0

有很多这样的问题:

我可以继续这样做:)

<form>归根结底,他们都建议通过 a 、 an<iframe>或使用某种重定向window.location

这可能是要走的路,但是如果你有足够的冒险精神,我也会尝试一些 HTML5 Blob API、文件系统和/或类型化数组的组合。

于 2013-10-30T20:38:53.033 回答