最近项目中有同事用到word文档导出功能,遇到了一些导出失败问题,帮其看了下解决问题的同事,看了下之前的代码发现几个问题:
- 代码编写不规范,word导出功能未收口
- 重复代码导出都是
- 实现逻辑比较复杂,不易于维护及使用
在帮其解决问题后,写了下面这个ViewResult拓展,依赖Razor视图,能够直接转换页面为word文档,但是不支持外联样式表,样式可以定义在<head>头部
废话不多说,直接上代码:
public class WordFileResult : ViewResultBase { public string FileName { get; set; }
public WordFileResult(object model, string viewName, string fileName) { ViewData = new ViewDataDictionary(model); ViewName = viewName; FileName = fileName; }
public WordFileResult() : this(new ViewDataDictionary(), null, null) {
}
public WordFileResult(string fileName) : this(new ViewDataDictionary(), null, fileName) {
}
public WordFileResult(object model) : this(model, null, null) {
}
public WordFileResult(object model, string fileName) : this(model, null, fileName) {
}
protected override ViewEngineResult FindView(ControllerContext context) { context.HttpContext.Response.Charset = "utf-8"; context.HttpContext.Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8"); if (string.IsNullOrWhiteSpace(FileName)) { FileName = ViewName; } context.HttpContext.Response.AppendHeader("Content-Disposition", string.Format("filename={0}.doc", FileName)); context.HttpContext.Response.ContentType = "application/msword"; ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, string.Empty); if (result.View != null) { return result; } return null; } }
public static class ControllerExtensions { public static WordFileResult Word(this Controller controller, object model) { return new WordFileResult(model); }
public static WordFileResult Word(this Controller controller, object model, string fileName) { return new WordFileResult(model, fileName); }
public static WordFileResult Word(this Controller controller, string fileName) { return new WordFileResult(fileName); }
public static WordFileResult Word(this Controller controller, object model, string viewName, string fileName) { return new WordFileResult(model, viewName, fileName); }
} |
使用方式比较简单:
- 定义视图,使用Razor视图布局word内容,
@using RazorWord.Models @model List<LoginViewModel> @{ Layout = null; }
<!DOCTYPE html>
<html> <head> <meta name="viewport" content="width=device-width" /> <title>Export</title> <style type="text/css"> .table td, .table th { background-color: #fff !important; }
.table { border-collapse: collapse !important; background-color: #ffffff; width: 100%; margin-bottom: 20px; }
.table thead > tr > th, .table tbody > tr > th, .table tfoot > tr > th, .table thead > tr > td, .table tbody > tr > td, .table tfoot > tr > td { padding: 8px; line-height: 1.428571429; vertical-align: top; border-top: 1px solid #dddddd; }
.table thead > tr > th { vertical-align: bottom; border-bottom: 2px solid #dddddd; } </style> </head> <body> <div> <table class="table"> <tr> <th>电子邮件</th> <th>密码</th> <th>是否记住密码</th> </tr> @foreach (LoginViewModel item in Model) { <tr> <td>@item.Email</td> <td>@item.Password]</td> <td>@(item.RememberMe ? "Y" : "N")</td> </tr> } </table> </div> </body> </html> |
- 添加Action修改对应的Action方法返回值
public ActionResult Export() { List<LoginViewModel> models = new List<LoginViewModel>(); for (int i = 0; i < 20; i++) { models.Add(new LoginViewModel() { Email = $"{i}user@123.com", Password = new Random().Next(1, 10000).ToString(), RememberMe = i % 2 == 0 ? true : false }); }
return new WordFileResult(models, "下载文件名称"); }
public ActionResult Export1() { List<LoginViewModel> models = new List<LoginViewModel>(); for (int i = 0; i < 20; i++) { models.Add(new LoginViewModel() { Email = $"{i}user@123.com", Password = new Random().Next(1, 10000).ToString(), RememberMe = i % 2 == 0 ? true : false }); } return this.Word(models, "Export", "下载文件名称"); } |
还有一种更方便的方式:使用ActionFilterAttribute过滤器
直接上代码:
public class WordDocumentAttribute : ActionFilterAttribute { public string FileName { get; set; } public override void OnResultExecuted(ResultExecutedContext filterContext) { var result = filterContext.Result as ViewResult; if (string.IsNullOrWhiteSpace(FileName)) { FileName = result == null ? DateTime.Now.ToString("yyyy_MM_dd") : result.ViewName; } filterContext.HttpContext.Response.AppendHeader("Content-Disposition", string.Format("filename={0}.doc", FileName)); filterContext.HttpContext.Response.ContentType = "application/msword"; base.OnResultExecuted(filterContext); } } |
使用方式:在一个Action方法上面添加特性:WordDocumentAttribute
[WordDocument(FileName = "下载文件名称")] public ActionResult Index() { return View(); } |
搞定word导出功能,抛砖引玉,希望能够帮助到大家,也希望有更好实现方式的同学能够一起讨论!!!!!!