天天看點

MVC導出資料到EXCEL新方法:将視圖或分部視圖轉換為HTML後再直接傳回FileResult

導出EXCEL方法總結

MVC導出資料到EXCEL的方法有很多種,常見的是:

1.采用EXCEL COM元件來動态生成XLS檔案并儲存到伺服器上,然後轉到該檔案存放路徑即可;

優點:可設定豐富的EXCEL格式,缺點:需要依賴EXCEL元件,且EXCEL程序在伺服器中無法及時關閉,以及伺服器上會存留大量的不必要的XLS檔案;

2.設定輸出頭為:application/ms-excel,再輸出拼接的HTML TABLE資料;

優點:無需元件,可設定一些簡單的格式,缺點:拼接HTML TABLE過程較複雜,不夠直覺;

3.借助第三方元件(如:NPOI)

優點及缺點均依賴于第三方元件的易用性上面,在此不作說明;

大家也可以看我之前發表的一篇博文:我寫的一個ExcelHelper通用類,可用于讀取或生成資料

實作在MVC下新的導出EXCEL方法

這裡給大家分享一個在MVC下的新方法:将視圖或分部視圖轉換為HTML後再直接傳回FileResult即可輕松實作導出EXCEL功能,下面直接上代碼。

首先看一下分部視圖(IndexDataList)的内容:

@model IEnumerable<CCPS.Models.Data.CustomerCommentInfo>
@using PagedList.Mvc;

<table>
    <thead>
        <tr>
            <th>意見ID</th>
            <th>組 織</th>
            <th>車牌</th>
            <th>車型</th>
            <th>皇家版</th>
            <th>客戶</th>
            <th>客戶電話</th>
            <th>責任部門</th>
            <th>責任班組</th>
            <th>業務顧問</th>
            <th>意見類型</th>
            <th>狀态</th>
            <th>錄入員</th>
            <th>錄入時間</th>
        </tr>
    </thead>
    <tbody id="list-table-body">
        @foreach (var item in Model)
        {
            string className = "";
            if (item.Status == "已稽核未處理")
            {
                className = "uncl_yellow";
                if (item.AuditDatetime != null && DateTime.Now > ((DateTime)item.AuditDatetime).AddHours(24))
                {
                    className = "uncl_red";
                }
            }
            <tr class="@className" data-adt="@item.AuditDatetime">
                <td><a href="http://oa.pfcn.com/flow/[email protected]&flow_id=147" target="_blank">@item.Id</a></td>
                <td>@item.OrgName</td>
                <td>@item.PlateNo</td>
                <td>@item.Model</td>
                <td>@item.IsRoyalVer</td>
                <td>@item.CustomerName</td>
                <td>@item.CustomerPhoneNo</td>
                <td>@item.RelevantDept</td>
                <td>@item.RelevantGroup</td>
                <td>@item.Consultant</td>
                <td>@item.Type</td>
                <td>@item.Status</td>
                <td>@item.CreateBy</td>
                <td>@string.Format("{0:g}", item.CreateDatetime)</td>
            </tr>
        }
    </tbody>
</table>
@if(true!=ViewBag.NoPaging)
{ 
<div class="pager">
    @Html.PagedListPager(Model as PagedList.IPagedList<CCPS.Models.Data.CustomerCommentInfo>, page => string.Format("javascript:turnPage({0});", page), PagedListRenderOptions.ClassicPlusFirstAndLast)
</div>
}
      

我這裡的分部視圖不僅僅隻是為了導出EXCEL用,在搭配主視圖顯示資料時照樣可以可以用,是以我這裡有是否分頁判斷,如果導出EXCEL,那肯定就不需要分頁了。

下面是實作将視圖、分部視圖生成HTML的方法,代碼如下:

[NonAction]
        protected string RenderViewToString(Controller controller, string viewName, string masterName)
        {
            IView view = ViewEngines.Engines.FindView(controller.ControllerContext, viewName, masterName).View;
            using (StringWriter writer = new StringWriter())
            {
                ViewContext viewContext = new ViewContext(controller.ControllerContext, view, controller.ViewData, controller.TempData, writer);
                viewContext.View.Render(viewContext, writer);
                return writer.ToString();
            }
        }

        [NonAction]
        protected string RenderPartialViewToString(Controller controller, string partialViewName)
        {
            IView view = ViewEngines.Engines.FindPartialView(controller.ControllerContext, partialViewName).View;
            using (StringWriter writer = new StringWriter())
            {
                ViewContext viewContext = new ViewContext(controller.ControllerContext, view, controller.ViewData, controller.TempData, writer);
                viewContext.View.Render(viewContext, writer);
                return writer.ToString();
            }
        }
      

這兩個方法是按照其視圖呈現的步驟與原理來實作的,一般步驟是:找到視圖-->執行個體化視圖上下文-->呈現視圖到輸出容器

最後就是定義一個導出EXCEL的Action方法,并傳回FileResult,這樣就完成了導出EXCEL功能,代碼如下:

public ActionResult Export(DataFilter<CustomerCommentInfo>[] filters)
        {
            var resultList = DataProvider.GetCustomerCommentInfos(filters).OrderBy(t => t.CreateDatetime);
            ViewBag.NoPaging = true;
            ViewData.Model = resultList;
            string viewHtml = RenderPartialViewToString(this, "IndexDataList");
            return File(System.Text.Encoding.UTF8.GetBytes(viewHtml), "application/ms-excel", string.Format("ccpi_{0}.xls", Guid.NewGuid()));
        }
      

是不是很簡單呢?想要導出什麼樣的EXCEL格式内容,直接可以在視圖中設計好就可以了。