.NET通过调用Office组件导出Word文档
最近做项目需要实现一个客户端下载word表格的功能,该功能是用户点击"下载表格",服务端将该用户的数据查询出来并生成数据到Word模板中,再反馈给客户端下载。
实现思路如下:
利用微软提供的Office的组件来完成,在服务器端指定目录放置一个word模板(该模板中需要替换的数据信息用书签标记好),当请求过来的时候,读取模板信息并将书签内容替换成从数据库获得的信息在返回给客户端下载即可,代码如下:
#region 根据申请单ID号和模板生成word下载文件(书签的形式) public void DownLoadWordOld(string id) { if (string.IsNullOrEmpty(id)) { id = "0"; } string sql = "SELECT ID,ProposerName,PhoneNo,ProposerAddress,HouseArea,HouseType,HouseNature,ApplyDate" + " from BettingStationApply where ID=@id "; SqlParameter[] parm = new SqlParameter[] { new SqlParameter("@id", int.Parse(id)) }; //根据ID号取得当前申请单的详细信息 DataTable dt = DBHelper.GetDataSet(sql, parm); if (dt.Rows.Count > 0) { DataRow dr = dt.Rows[0]; //1、先创建一个创建word的Application Word.Application wordApp = new Word.ApplicationClass(); //2、创建一个word文档 Word.Document docFile = null; try { wordApp.Visible = false; //模板对象 object objTemplete = Server.MapPath(@"/BettingStation/templete.docx"); object objTrue = true; object objFalse = false; object objDocType = Word.WdDocumentType.wdTypeDocument; //实例化word文档(已经读取到模板的word文档) docFile = wordApp.Documents.Add(ref objTemplete, ref objFalse, ref objDocType, ref objTrue); //定义书签变量 object ProposerName = "ProposerName"; object PhoneNo = "PhoneNo"; object ProposerAddress = "ProposerAddress"; object HouseArea = "HouseArea"; object HouseType = "HouseType"; object HouseNature = "HouseNature"; object ApplyDate = "ApplyDate"; //获取所有的书签 Word.Bookmarks books = docFile.Bookmarks; //给书签赋值 if (books.Exists("ProposerName")) { books.get_Item(ref ProposerName).Range.Text = dr["ProposerName"].ToString(); } if (books.Exists("PhoneNo")) { books.get_Item(ref PhoneNo).Range.Text = dr["PhoneNo"].ToString(); } if (books.Exists("ProposerAddress")) { books.get_Item(ref ProposerAddress).Range.Text = dr["ProposerAddress"].ToString(); } if (books.Exists("HouseArea")) { books.get_Item(ref HouseArea).Range.Text = dr["HouseArea"].ToString(); } if (books.Exists("HouseType")) { books.get_Item(ref HouseType).Range.Text = dr["HouseType"].ToString(); } if (books.Exists("HouseNature")) { books.get_Item(ref HouseNature).Range.Text = dr["HouseNature"].ToString(); } if (books.Exists("ApplyDate")) { if (dr["ApplyDate"] != DBNull.Value) { books.get_Item(ref ApplyDate).Range.Text = Convert.ToDateTime(dr["ApplyDate"].ToString()).ToString("yyyy-MM-dd HH:mm:ss"); } } object fileName = Server.MapPath(@"/BettingStation/投注站申请表.docx"); object nothing = Type.Missing; //将当前文件保存到临时文件中 docFile.SaveAs2(ref fileName, ref nothing, ref nothing, ref nothing, ref nothing, ref nothing , ref nothing, ref nothing, ref nothing, ref nothing, ref nothing, ref nothing , ref nothing, ref nothing, ref nothing, ref nothing, ref nothing); //关闭当前word文档 docFile.Close(ref nothing, ref nothing, ref nothing); //退出当前word程序的调用 wordApp.Quit(ref nothing, ref nothing, ref nothing); docFile = null; //从服务器临时文件夹中下载文件返回给客户端 ExtWord(fileName.ToString(), dr["ProposerName"].ToString() + "_投注站申请表.docx"); //调用客户端js方法 } catch (Exception ex) { writeLog.WriteErrorLog("根据模板生成Word文件出错!错误信息:" + ex.Message); //出异常记得释放相关资源 object nothing = Type.Missing; //关闭当前word文档 docFile.Close(ref nothing, ref nothing, ref nothing); //退出当前word程序的调用 wordApp.Quit(ref nothing, ref nothing, ref nothing); docFile = null; Message.show("根据模板生成Word文件出错!错误信息:" + ex.Message); } } else { writeLog.WriteErrorLog("id=" + id + "没有查找到任何数据!"); Message.show("id=" + id + "没有查找到任何数据!"); } } #endregion
调用offic组件需要添加Interop.Microsoft.Office.Interop.Word.dll的引用,我电脑上装的Office2010,所以添加Microsoft Word 14.0 Object Library的引用
Word模板在服务器端生成好后,在利用Response方法将生成的word文档发送给客户端下载,代码如下:
#region 从服务器指定路径下载Word /// <summary> /// 从服务器指定路径下载Word /// </summary> /// <param name="fileFullName">临时文件在服务器上的完整路径</param> /// <param name="wordname">下载的Word文件名</param> public void ExtWord(string fileFullName, string wordname) { //输出word FileInfo file = new System.IO.FileInfo(fileFullName); HttpContext.Current.Response.Clear(); HttpContext.Current.Response.Charset = "GB2312"; HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8; // 添加头信息,为"文件下载/另存为"对话框指定默认文件名 HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(wordname, System.Text.Encoding.UTF8)); // 添加头信息,指定文件大小,让浏览器能够显示下载进度 HttpContext.Current.Response.AddHeader("Content-Length", file.Length.ToString()); // 指定返回的是一个不能被客户端读取的流,必须被下载 HttpContext.Current.Response.ContentType = "application/ms-word"; // 把文件流发送到客户端 HttpContext.Current.Response.WriteFile(file.FullName); // 停止页面的执行 HttpContext.Current.ApplicationInstance.CompleteRequest(); } #endregion
测试,运行没问题。
将开发环境测试OK的程序发布到正式的服务器环境后发现,不能运行,导出会出现错误。解决方法如下:
1、确保服务器上已经安装了并激活word程序(建议安装word2010);
2、当开发的通过word模板生成word程序完成后,部署在windows相关的服务器上时,如果出现以下的错误(读取word组件的Com权限问题):
3、查看错误的字面意思,应该是COM组件的配置有问题,网上查阅相关资料发现是权限的配置的问题!
4、以下步骤重点是给iis授予com组件的访问权限:
步骤一:找到导出word所用到的com组件;
(1)控制面板-》管理工具-》组件服务-》计算机-》我的电脑-》DCOM配置-》Mircosoft Word文档;
注:如果这样操作找不到Mircosoft word相关文档,不用慌,尝试以下方法:
Cmd-》mmc -32-》文件-》添加/删除管理单元-》选择组件服务-》确定-》计算机-》我的电脑-》DCOM配置-》找到Mircosoft Word 97-2003文档,按照以下的方法操作即可;
步骤二:找到word文档后,在它上面点击右键,然后点击"属性",
弹出"Microsoft word 应用程序属性"对话框,
步骤一:点击"标识"标签,选择"交互式用户"
步骤三:点击"安全"标签,在"启动和激活权限"上点击"自定义",然后点击对应的"编辑"按钮,在弹出的"安全性"对话框中填加 IIS_IUSRS账户(IIS账户),并按照如下图所示授予相关权限:
,
步骤四:依然是"安全"标签,在"访问权限"上点击"自定义",然后点击"编辑",配置的账号和方法和上一步操作一样;
六:重启网站并运行,点击下载表格按钮即成功。