Magcodes.WeiChat——經過CsvFileResult以及DataAnnotations實現導出CSV文件

咱們先來看看效果圖:html

image

image

從上圖中能夠看出,導出的文件中列名與表格名稱保持一致,而且忽略了某些字段。git

相關代碼實現

咱們來看相關代碼:github

頁面代碼:微信

@using (Html.BeginForm("Index", @Request.RequestContext.RouteData.GetRequiredString("controller"), FormMethod.Get))
                    {
                        <div class="row">
                            <div class="col-sm-3">

                                <div class="input-group">
                                    @Html.TextBox("q", ViewBag.q as string, new { @placeholder = "請輸入關鍵字", @class = "input-sm form-control" })
                                    <span class="input-group-btn">
                                        <button type="submit" class="btn btn-sm btn-primary"><i class="fa fa-search"></i>&nbsp;搜索</button>
                                    </span>
                                </div>

                            </div>
                            @*<div class="col-sm-2">
                                    <a class="btn btn-primary btn-sm" href="@Url.Action("Create")" id="btnAdd"><i class="fa fa-plus"></i>&nbsp;新建</a>
                                </div>*@

                            <div class="col-sm-3">
                                <div class="input-group">
                                    @Html.DropDownList("UserGroups", null, htmlAttributes: new { @class = "input-sm form-control" })
                                    <span class="input-group-btn">
                                        <a class="btn btn-success btn-sm" id="btnMove" data-action="Move" data-comfirmmessage="肯定要移動所選用戶麼?"><i class="fa  fa-arrow-circle-o-right"></i>&nbsp;移動分組</a>
                                    </span>
                                </div>

                            </div>
                            <a class="btn btn-info btn-sm" href="@Url.Action("Sync")"><i class="fa fa-circle-o"></i>&nbsp;全量同步</a>
                            <a class="btn btn-warning btn-sm" href="@Url.Action("Index","WeiChatUsers")"><i class="fa fa-chevron-up"></i>&nbsp;切換視圖</a>
                            <button type="submit" class="btn btn-sm btn-primary" name="exportType" value="1"><i class="fa fa-file-archive-o"></i>&nbsp;導出CSV</button>
                            @*<button type="submit" class="btn btn-sm btn-primary" name="exportType" value="2"><i class="fa fa-file-excel-o"></i>&nbsp;導出Excel</button>*@
                        </div>
                    }

控制器代碼:app

// GET: WeiChat_User
        public async Task<ActionResult> Index(string q, int pageIndex = 1, int pageSize = 10, ExportTypes exportType = ExportTypes.None)
        {
            var syncHelper = new SyncHelper();
            //同步微信用戶組
            await syncHelper.Sync(WeiChat_SyncTypes.Sync_WeiChat_User, TenantId, true, UserId);
            var queryable = db.WeiChat_Users.AsQueryable();
            if (!string.IsNullOrWhiteSpace(q))
            {
                //請替換爲相應的搜索邏輯
                queryable = queryable.Where(p => p.NickName.Contains(q) || p.City.Contains(q) || p.Country.Contains(q) || p.Province.Contains(q) || p.Remark.Contains(q));
            }
            queryable = queryable.OrderByDescending(p => p.SubscribeTime);
            switch (exportType)
            {
                case Helpers.ExportTypes.Csv:
                    return Csv(queryable.ToList());
                //case Helpers.ExportTypes.Excel:
                //    return Excel(queryable.ToList());

            }
            var pagedList = new PagedList<WeiChat_User>(
                             await queryable
                             .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync(),
                             pageIndex, pageSize, await queryable.CountAsync());
            var myGroups = db.WeiChat_UserGroups.Where(p => p.TenantId == TenantId).ToList();
            foreach (var item in pagedList)
            {
                item.UserGroup = myGroups.FirstOrDefault(p => p.GroupId == item.GroupId);
            }
            ViewBag.UserGroups = new SelectList(myGroups, "GroupId", "Name");
            return View(pagedList);
        }

注意上述代碼中的Csv方法,經過該方法能夠將當前List導出爲CSV。並且支持查詢結果導出。微信公衆平臺

CSV方法封裝在TenantBaseController<TEntry>中,具體實現以下:框架

/// <summary>
        /// 導出CSV
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>

        public ActionResult Csv(IEnumerable<TEntry> data)
        {
            return new CsvFileResult<TEntry>(data);
        }

CsvFileResult<T>代碼以下:async

/// <summary>
    /// 導出CSV格式文件
    /// </summary>
    /// <typeparam name="T">實體數據類型</typeparam>
    //http://joshclose.github.io/CsvHelper/
    public class CsvFileResult<T> : FileResult where T : class
    {
        private IEnumerable<T> _data;

        public CsvFileResult(IEnumerable<T> data)
            : base("text/csv")
        {
            this.FileDownloadName = string.Format("{0}.csv",DateTime.Now.ToString("yyyyMMddHHmmss"));
            _data = data;
        }

        protected override void WriteFile(HttpResponseBase response)
        {
            var outPutStream = response.OutputStream;
            using (var streamWriter = new StreamWriter(outPutStream, System.Text.Encoding.UTF8))
            using (var writer = new CsvWriter(streamWriter))
            {
                writer.WriteHeader<T>();
                foreach (var item in _data)
                {
                    writer.WriteRecord(item);
                }
                streamWriter.Flush();
                response.Flush();
            }
        }
    }

這裏使用到了CsvHelper。框架對CsvHelper進行了修改,以支持Display特性以及ExportIgnore特性。ide

ExportIgnoreAttribute測試

導出時忽略此屬性

DisplayAttribute

指定本地化顯示的字符串,這裏使用其Name屬性做爲導出內容的字段友好名稱

如前面導出內容所示,WeiChat_User定義以下:

/// <summary>
    /// 微信用戶信息
    /// </summary>
    public class WeiChat_User : ITenantId
    {
        /// <summary>
        /// 用戶的標識,對當前公衆號惟一
        /// </summary>
        [Key]
        [Display(Name = "OpenId")]
        public string OpenId { get; set; }
        /// <summary>
        /// 用戶是否訂閱該公衆號標識
        /// </summary>
        [Display(Name = "是否訂閱")]
        public bool Subscribe { get; set; }

        /// <summary>
        /// 用戶的暱稱
        /// </summary>
        [Display(Name = "暱稱")]
        public string NickName { get; set; }
        /// <summary>
        /// 用戶的性別,值爲1時是男性,值爲2時是女性,值爲0時是未知
        /// </summary>
        [Display(Name = "性別")]
        public WeChatSexTypes Sex { get; set; }
        /// <summary>
        /// 用戶所在城市
        /// </summary>
        [Display(Name = "所在城市")]
        public string City { get; set; }
        /// <summary>
        /// 用戶所在國家
        /// </summary>
        [Display(Name = "所在國家")]
        public string Country { get; set; }
        /// <summary>
        /// 用戶所在省份
        /// </summary>
        [Display(Name = "所在省份")]
        public string Province { get; set; }

        /// <summary>
        /// 用戶的語言,簡體中文爲zh_CN
        /// </summary>
        [Display(Name = "語言")]
        public string Language { get; set; }
        /// <summary>
        /// 用戶頭像,最後一個數值表明正方形頭像大小(有0、4六、6四、9六、132數值可選,0表明640*640正方形頭像),用戶沒有頭像時該項爲空。若用戶更換頭像,原有頭像URL將失效。
        /// </summary>
        [Display(Name = "頭像")]
        public string HeadImgUrl { get; set; }
        /// <summary>
        /// 用戶關注時間,爲時間戳。若是用戶曾屢次關注,則取最後關注時間
        /// </summary>
        [Display(Name = "關注時間")]
        public DateTime SubscribeTime { get; set; }
        /// <summary>
        /// 只有在用戶將公衆號綁定到微信開放平臺賬號後,纔會出現該字段。詳見:獲取用戶我的信息(UnionID機制)
        /// </summary>
        [Display(Name = "UnionId")]
        public string UnionId { get; set; }
        /// <summary>
        /// 公衆號運營者對粉絲的備註,公衆號運營者可在微信公衆平臺用戶管理界面對粉絲添加備註
        /// </summary>
        [Display(Name = "備註")]
        public string Remark { get; set; }
        /// <summary>
        /// 用戶所在的分組ID
        /// </summary>
        [Display(Name = "分組Id")]
        public int? GroupId { get; set; }
        /// <summary>
        /// 所在用戶組
        /// </summary>
        [Display(Name = "所在用戶組")]
        [NotMapped]
        [ExportIgnore]
        public WeiChat_UserGroup UserGroup { get; set; }
        /// <summary>
        /// 是否容許測試
        /// </summary>
        [Display(Name = "測試用戶")]
        [ExportIgnore]
        public bool AllowTest { get; set; }
        [ExportIgnore]
        public int TenantId { get; set; }
}

注意:字段「UserGroup」,「AllowTest」,「TenantId「將在導出時被忽略,同時導出字段名使用Display特性中的Name屬性。

總結:經過封裝CsvFileResult能夠極大的簡化導出CSV的編碼工做,只須要在Action中return Csv(queryable.ToList())便可。再結合數據特性配套使用,極大的提升了導出內容與格式的靈活性。

相關文章
相關標籤/搜索