【背景概要】
项目中,有很多地方涉及到需要打印各种表格,静态的,动态的,都有。而之前利用锐浪报表实现了显示表格的需求,但在进行条件筛选后,报表中的数据并不能显示了。这个问题一直搁置了很久,一直得不到解决。
【问题解决】
在放下报表问题实现其它需求期间,偶然发现,我们可以动态的将表格嵌入到word文件中,利用word将各种表格显示打印。这里用到的就是Aspose Word控件,不但可以帮助我们实现在word中插入必要的参数,也可以帮助我们在word中插入必要的表格。
【项目环境】
项目前台利用的MVC框架,EasyUI样式,VS2012开发环境。
【实现步骤】
1.在本地新建一个word模板,在项目中添加现有项,把制作好的word模板添加到项目中。
word模板如下图所示,
参数说明:模板{}中的字段都是灵活的,所以在此写成这样作为参数,在项目中通过代码动态加载。
2.前台页面已经实现通过按条件搜索,将查询到的数据显示在datagrid表格中,具体效果如下图所示:
3.查询结果出来后,下面真正开始利用代码实现将表格嵌入word模板中。关键步骤如下:
第一,获取招标文件制作模板:
//获得程序集根目录 string rootPath = AppDomain.CurrentDomain.BaseDirectory; //招标文件模板路径 var mainDocPath = rootPath + "/Content/评委签到记录表/" + "评委签到表.doc"; Aspose.Words.Document docMain = new Aspose.Words.Document(mainDocPath); DocumentBuilder builder = new DocumentBuilder(docMain);第二,通过前台页面和后台方法,获取各个参数:
//获取招标项目编号 string BidProjectId = Request["BidProjectId"].ToString(); //获取招标项目名称 string BidCompanyName = iBidZRecordInfoService.GetBidNameByBidProjectId(BidProjectId);第三,将获取到的参数值替换到模板中:
//获取系统当前时间 DateTime now = DateTime.Now; //替换招标编号 docMain.Range.Replace("{BidProjectId}", BidProjectId, false, false); //替换项目名称 docMain.Range.Replace("{ProjectName}", BidCompanyName, false, false); //替换评标报告生成日期 docMain.Range.Replace("{Now}", now.Year + "年" + now.Month + "月" + now.Day + "日", false, false);第四,嵌入表格的表头:
//开始添加值,书签设置,控制表格的起始位置 builder.MoveToBookmark("table"); //添加表头数据 ArrayList tableHeadArray = new ArrayList(); //添加固定的前两列表头信息 tableHeadArray.Add("姓名"); tableHeadArray.Add("工作单位"); tableHeadArray.Add("职称"); tableHeadArray.Add("到达时间"); tableHeadArray.Add("备注"); for (int j = 0; j < tableHeadArray.Count; j++) { //插入单元格 builder.InsertCell(); //设置单元格边框样式及颜色 builder.CellFormat.Borders.LineStyle = LineStyle.Single; builder.CellFormat.Borders.Color = System.Drawing.Color.Black; //设置单元格宽度 builder.CellFormat.Width = 100; //将值填入表格 builder.Write(tableHeadArray[j].ToString()); } builder.EndRow();第五,将查询到的数据动态嵌入word中:
//获取条件查询后的结果,返回值为List<ViewModel> List<SpecialistInfoViewModel> SpecialistInfo = iSpecialistService.GetSpecialInfo(BidProjectId); //定义一个新的List集合,以便最后直接将记录整行填充 IList<IList<string>> temp= new List<IList<string>>(); //控制表格的行数,即为查询到结果的count值 for (int n = 0; n < SpecialistInfo.Count; n++) { //定义一个新的List集合,存储各行各字段的值 List<string> newspecialist = new List<string>(); newspecialist.Add(SpecialistInfo[n].SpecialistName.ToString()); newspecialist.Add(""); newspecialist.Add(SpecialistInfo[n].SpecialistType.ToString()); newspecialist.Add(""); newspecialist.Add(SpecialistInfo[n].SpecialistComment.ToString()); //temp这个list中已经存放了每一行的记录值 temp.Add(newspecialist); } //行数 for (int i = 0; i < SpecialistInfo.Count; i++) { //控制列数 for (int m = 0; m < tableHeadArray.Count; m++) { // 添加一个单元格 builder.InsertCell(); //设置单元格的样式和颜色 builder.CellFormat.Borders.LineStyle = LineStyle.Single; builder.CellFormat.Borders.Color = System.Drawing.Color.Black; builder.CellFormat.VerticalMerge = Aspose.Words.Tables.CellMerge.None; builder.CellFormat.VerticalAlignment = CellVerticalAlignment.Center;//垂直居中对齐 builder.ParagraphFormat.Alignment = ParagraphAlignment.Center;//水平居中对齐 //通过test这个List集合,填充每个单元格 builder.Write(test[i][m].ToString()); } builder.EndRow(); }第六,设置保存文件的路径和文件名,最终返回给视图:
//将替换后的评委签到表保存在以下路径 string outputPath = rootPath + "/Content/评委签到表.doc"; //生成的评委签到表的名称 string filename = "评委签到表" + now.ToString("yyyy年mm月dd日") + ".doc"; //保存文件 docMain.Save(outputPath); //将文件返回给视图 return File(outputPath, "application/msword", filename);4.以上各步是Controller下的方法,最后通过js在点击按钮后,调用该方法即可,js代码如下:
//生成评委签到记录表 function ExportSpecialistSign() { //获取查询的招标编号 var BidProjectId = document.getElementById('BidProjectId').value; //调用Controller中对应的方法 window.location.href = '/SpecialistSign/ExportSpecialistSign?BidProjectId=' + BidProjectId; }【效果展示】
通过以上步骤,终于实现了一直搁置的报表问题。下面是从word中截取的报表信息:
【编程总结】
在实现这一功能的过程中,最复杂的是数组那部分的逻辑。另外,在巨人的肩膀上,也让我见识到了List的强大。一个List不仅仅是一个List那么简单,我们可以通过自己的创建,实现对List的拼接,实现对List的重组,从而完美得到自己想要的那一行行记录。积累,思考,应用,这都是自己在以后的学习需要特别值得注意的。