word嵌入表格,完美解决报表
【背景概要】

项目中,有很多地方涉及到需要打印各种表格,静态的,动态的,都有。而之前利用锐浪报表实现了显示表格的需求,但在进行条件筛选后,报表中的数据并不能显示了。这个问题一直搁置了很久,一直得不到解决。
【问题解决】
在放下报表问题实现其它需求期间,偶然发现,我们可以动态的将表格嵌入到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的重组,从而完美得到自己想要的那一行行记录。积累,思考,应用,这都是自己在以后的学习需要特别值得注意的。