c语言word类型操作(中word导出功能骚操作)

需求:企业填报自己的企业信息到系统中,最后需要将数据以给定word模板形式导出,功能简单,就是要开发快,赶及

分析:主要费时间的工作是设计企业填报表单设计实现,以及根据提供的word模板导出数据这块儿,因为涉及到的表单比较多,一个表单最少也有差不多150多个字段,一个一个对,头发也得一把一把的掉

想到的解决法案:在导出word这个功能模块儿,写一些通用的方法,减少一些工作量。

        word数据导出功能,思路就是在word模板中每一个需要填数据的地方命名一个标签,代码中找到对应命名的标签,插入数值

传统做法,第一步:在word模板中填写标签 第二步:程序中每个插入字段数据和word模板标签对应,最后插值,这样做有一个问题就是比较耗时间,而且很容易出错

        我的做法,第一步:给数据字段一个自定义特性,在自定义特性中写上对应的标签地址,应用反射的方法将数据最终插入到word模板中。这样就省去了第一步在word中写标签这样繁杂的操作。这样做的问题就是性能比较差,但是可以忽略不计

大体思路就这样,我就单独写一个demo供大家参考,之后能用就用,重在思路和想法的分享和讨论

开写:

新建一个项目:ExportWordModel

c语言word类型操作(中word导出功能骚操作)(1)

c语言word类型操作(中word导出功能骚操作)(2)

最终项目简易结构:

c语言word类型操作(中word导出功能骚操作)(3)

将没用的东西全部去掉,修改Index.cshtml页面成这样:

1 @{ 2 ViewBag.Title = "Home Page"; 3 } 4 <div class="jumbotron" style="text-align: center"> 5 @*<h1>ASP.NET</h1>*@ 6 <input type="button" value="导出" onclick="location.href = '@Url.Action("GetExport","Home")'" /> 7 </div>

在 HomeController 中创建:GetExport

创建一个类ExportFileOperator(所有的word操作),此类需要继承Controller,因为有返回File操作方法

c语言word类型操作(中word导出功能骚操作)(4)

1、 在GetExport中首先命名一个导出word标题就叫:测试导出Word文件

string title = "测试导出Word文件";

创建doc:

var doc = ExportFileOperator.CreateBuilder("GroupForm.doc");

2、CreateBuilder方法实现为(此处操作需要Aspose.Word组件,是操作word的,这个需要大家自己去找一下,或者网上找个破解的):

1 private static string _tempPath = AppDomain.CurrentDomain.BaseDirectory; 2 public static (Document doc, DocumentBuilder builder) CreateBuilder(string tempFileName) 3 { 4 string tempPath = $"{_tempPath}{tempFileName}"; 5 Document doc = new Document(tempPath); 6 return (doc, new DocumentBuilder(doc)); 7 }

3、插入标题(需要在word中写一个标签,作为标题插入的地址):

c语言word类型操作(中word导出功能骚操作)(5)

最终可以显示结果为这样:

c语言word类型操作(中word导出功能骚操作)(6)

方法:

ExportFileOperator.InsertTitle(ref doc.Item2, title);//插入标题

public static void InsertTitle(ref DocumentBuilder builder, string fileName, string tempBookMarkName = "title") { builder.MoveToBookmark(tempBookMarkName); builder.Write(fileName); }

4、根据业务实体,将实体数据写入到word中,也是核心所在

首先命名一个数据类:

c语言word类型操作(中word导出功能骚操作)(7)

View Code

其中重要的地方是:需要给每个字段一个Description,这里面的值对应的就是word模板中的名称,如下:

c语言word类型操作(中word导出功能骚操作)(8)

这里因为数据是保密的,我就将一些字段删除了,包括word模板中的一些也删除了,就拿出一部分。

和数据库交互的部分我也没写,就将查出来的数据先命名一个_enterpriseStr,最后用Newtonsoft转换成实体这样操作了哈:

EnterpriseEntity enterprise = JsonConvert.DeserializeObject<EnterpriseEntity>(_enterpriseStr);

c语言word类型操作(中word导出功能骚操作)(9)

5、将查出来的数据,插入到word中,完成最终的导出:

1 ExportFileOperator.InsertFormData(enterprise, ref doc.Item1);//实体数据插入 2 return new ExportFileOperator().FileResult(title, doc.Item1);

其中最重要的方法就是InsertFormData这个,他的实现如下:

1 public static void InsertFormData<T>(T objFormData, ref Document document) 2 { 3 NodeCollection allTables = document.GetChildNodes(NodeType.Table, true); 4 List<string> headDescribeNameList = GetObjectHeadDescription<T>();//获取实体中每个Description中的值 5 foreach (Table tableFirst in allTables) 6 { 7 for (int headIndex = 0; headIndex < headDescribeNameList.Count; headIndex )//循环实体中的每个DescribeName 8 { 9 for (int rowIndex = 0; rowIndex < tableFirst.Rows.Count; rowIndex )//遍历word模板中所有的table 10 { 11 for (int cellIndex = 0; cellIndex < tableFirst.Rows[rowIndex].Cells.Count; cellIndex )//遍历模板中所有的table每行的列数 12 { 13 if (tableFirst.Rows[rowIndex].Cells[cellIndex].GetText() != null && tableFirst.Rows[rowIndex].Cells[cellIndex].GetText().Contains(headDescribeNameList[headIndex]) && 14 ((tableFirst.Rows[rowIndex].Cells.Count > cellIndex && tableFirst.Rows[rowIndex].Cells[cellIndex 1] != null && tableFirst.Rows[rowIndex].Cells[cellIndex 1].GetText().Equals("\a")) || (tableFirst.Rows.Count > rowIndex && tableFirst.Rows[rowIndex 1] != null && tableFirst.Rows[rowIndex 1].Cells[cellIndex] != null && tableFirst.Rows[rowIndex 1].Cells[cellIndex].GetText().Equals("\a"))))//如果遍历的cell不为空、其中的值能和DescribeName匹配上,并且这个单元的右边的cell或者下边cell有占位,而且是空,就在此处插入值 15 { 16 var objValue = GetObjectValueByPropName(objFormData, headDescribeNameList[headIndex]);//根据DescribeName获取对应的值 17 if (tableFirst.Rows[rowIndex].Cells.Count > cellIndex && tableFirst.Rows[rowIndex].Cells[cellIndex 1] != null && tableFirst.Rows[rowIndex].Cells[cellIndex 1].GetText().Equals("\a")) 18 { 19 InsertCell(objValue, document, tableFirst.Rows[rowIndex].Cells[cellIndex 1]);//优先在右变空位插入值 20 break; 21 } 22 InsertCell(objValue, document, tableFirst.Rows[rowIndex 1].Cells[cellIndex]);//右侧如果没有就在下边空位插入值 23 break; 24 } 25 } 26 } 27 } 28 } 29 }

1 public static List<string> GetObjectHeadDescription<T>() 2 { 3 var obj = Activator.CreateInstance<T>(); 4 MethodInfo method = obj.GetType().GetMethod("GetThisDescriptionName", new Type[] { });//每个实体需要有GetThisDescriptionName这个方法 5 return (List<string>)(method?.Invoke(obj, null)); 6 }

其中GetThisDescriptionName方法需求在每个实体类中有实现:

c语言word类型操作(中word导出功能骚操作)(10)

根据descriptionName获取实体中的值:

1 private static string GetObjectValueByPropName<T>(T objFormData, string descriptionName) 2 { 3 try 4 { 5 var properties = objFormData.GetType().GetProperties(); 6 foreach (var propertyInfo in properties) 7 { 8 var descriptionAttributes = (DescriptionAttribute[])propertyInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 9 if (descriptionAttributes.Length > 0 && !string.IsNullOrWhiteSpace(descriptionAttributes[0].Description) && descriptionAttributes[0].Description.Equals(descriptionName)) 10 { 11 return propertyInfo.GetValue(objFormData) == null ? "无" : propertyInfo.GetValue(objFormData).ToString(); 12 } 13 } 14 return "无"; 15 } 16 catch (Exception e) 17 { 18 Console.WriteLine(e); 19 throw; 20 } 21 }

在cell中插入值:

1 private static void InsertCell(string value, Document doc, Cell cell) 2 { 3 Cell insertCell = cell; 4 insertCell.FirstParagraph.Remove(); 5 Paragraph p = new Paragraph(doc); 6 p.AppendChild(new Run(doc, (value == null ? "" : value))); 7 p.ParagraphFormat.Alignment = ParagraphAlignment.Center; 8 insertCell.CellFormat.VerticalAlignment = CellVerticalAlignment.Center; 9 insertCell.AppendChild(p); 10 }

最后一个方法FileResult:

1 public FileResult FileResult(string fileName, Document doc) 2 { 3 var filePathName = $"{fileName}.doc"; 4 doc.Save(Path.Combine(_tempPath, "temp", filePathName), SaveFormat.Doc); //保存word 5 filePathName = Path.Combine(_tempPath, "temp", filePathName); 6 return File(filePathName, "application/doc", $"{fileName}.Doc"); 7 }

最终效果:

c语言word类型操作(中word导出功能骚操作)(11)

c语言word类型操作(中word导出功能骚操作)(12)

最后说一下,其中有一些细节的地方还是需要做一些处理,暂时没时间写,后期有时间补,先就这样了

大家有什么好的想法或者更好地实现方式,尽管提出来,共同进步

git地址:https://github.com/Binzm/ExportWorkdModel.git

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页