1.错误的实现方式
最初的时候我采用Spire.PDF将生成的word(如果导出报告到word可以查看这篇blog《.NET 利用NPOI导出报告到Word》)转成PDF,首先发现Spire.PDF是商用付费的组件,如果不购买的话会存在水印,不好清除掉。其次,如果数据量比较大,导出到word的时候本身已经用了比较长的时间了,再对word转PDF的时候,又是一个耗时的动作,所以果断抛弃了这个投机取巧的方式.
2.方案选型
之前让一个毕业没多久的小朋友,使用过iTextSharp实现过导出报告到PDF,由于那段时间精力在开发网关方面,没有太过于注重实现的效果。客户使用的时候,一塌糊涂,一个数据量很大的报告,他愣是将所有数据展示到一页上了,不用放大镜压根都看不出来那是个啥鬼东西。毕竟是刚出校门,我也没过多要求,暂时搁置。最近刚好有时间,就查看了一下iTextSharp一些源码,最终实现出了自己想要的效果。我这边使用的是ILSpy.exe来查看源码,有兴趣的小伙伴可以没事多了解一下第三方库的实现原理,里面还是有很多的方法与思路很值的学习。
发现一个有意思的事情是:居然是移植与Java的iText。
3.实现方法封装
3.1代码封装
public string DataTable2Pdf(DataTable dataTable, string cPath, string fileName, int language, bool isSetCName = true)
{
//设置纸张与边距
Document document = new Document(PageSize.A4, 5, 5, 5, 5);
//得到文件存储的目录
string filePath = System.Web.HttpContext.Current.Server.MapPath(cPath);
//如果不存在就创建file文件夹
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
//PDF文件名称
string pdfFileName = export.SetFileName(fileName, language) + ".pdf";
PdfWriter writer = PdfWriter.GetInstance(document, new System.IO.FileStream(Path.Combine(filePath, pdfFileName), System.IO.FileMode.Create));
//定义标题文字样式(华文行楷)
BaseFont bfTitle = BaseFont.CreateFont(System.Web.HttpContext.Current.Server.MapPath("/Fonts/STXINGKA.TTF"), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font ftitle = new Font(bfTitle, 28, Font.NORMAL, BaseColor.BLACK);
//定义导出内容文字样式
BaseFont bfTable = BaseFont.CreateFont(System.Web.HttpContext.Current.Server.MapPath("/Fonts/STKAITI.TTF"), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font footerChinese = new Font(bfTable, 12, Font.NORMAL, BaseColor.BLACK);
document.Open();
//始化标题元素
Paragraph title = new Paragraph(export.SetFileName(fileName, language), ftitle);
//初始化表格元素
PdfPTable table = new PdfPTable(dataTable.Columns.Count);
//标题居中显示
title.Alignment = Element.ALIGN_CENTER;
document.Add(title);
PdfPCell cellNumber = new PdfPCell(new Phrase("No." + DateTime.Now.ToString("yyyyMMddHHmmss"), footerChinese));
cellNumber.Colspan = dataTable.Columns.Count;
cellNumber.PaddingRight = 6;
cellNumber.HorizontalAlignment = PdfPCell.ALIGN_RIGHT;
cellNumber.BorderWidthTop = 0;
cellNumber.BorderWidthRight = 0;
cellNumber.BorderWidthBottom = 0;
cellNumber.BorderWidthLeft = 0;
table.AddCell(cellNumber);
//定义表格显示样式
table.DefaultCell.HorizontalAlignment = PdfPCell.ALIGN_CENTER;
table.DefaultCell.VerticalAlignment = PdfPCell.ALIGN_MIDDLE;
//设置表格宽度张页面的100%
table.WidthPercentage = 100;
//写入表头
for (int i = 0; i < dataTable.Columns.Count; i++)
{
if (isSetCName)
{
table.AddCell(new Phrase(export.SetColumnName(dataTable.Columns[i].ColumnName,language), footerChinese));
}
else
{
table.AddCell(new Phrase(dataTable.Columns[i].ColumnName, footerChinese));
}
}
//添加表格内容
for (int i = 0; i < dataTable.Rows.Count; i++)
{
for (int j = 0; j < dataTable.Columns.Count; j++)
{
table.AddCell(new Phrase(dataTable.Rows[i][j].ToString(), footerChinese));
}
}
document.Add(table);
document.Close();
return pdfFileName;
}
其中我这边针对文件名、标题、以及表格的表头做了自定义内容的展示,方法就是上述代码过程中使用到的SetFileName(string,int)与SetColumnName(string,int),因为DataTable返回的表头可能是我们数据库定义的字段名称,这个对于客户来说是不明确的,所以可以使用SetColumnName方法做一个转换,转换方法就是将数据库定义的字段名称来匹配对应的展示名称,还进行多语言的适配而已。
3.2 代码拆解
首先我们需要初始化文档(Document),Document是有3个重载的构造函数,我选择的是下面红框标注的,对纸张样式、边距进行自定义
iTextSharp给了很多的 pageSize格式,一般我们常用的就是A4,这个与word纸张样式一个意思。
另外一个需要注意的点就是关于BaseFont
在我们CreateFont的时候有三种方式,分别可以使用iTextSharp自定义的字体、Windows已经安装的字体、项目资源里面的字体
3.2.1使用iTextSharp自定义的字体
可以在BaseFont里面查找,比如:Courier, Courier Bold, Courier Italic, Courier Bold and Italic, Helvetica, Helvetica Bold...
使用示例:
BaseFont bfTable = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, false);
Font table= new Font(bfTable, 12, Font.NORMAL, BaseColor.BLACK);
Font也有很多的重载构造方法,我们可以根据自己的需要进行选择性的找到自己合适的方法生产这个字体样式
3.2.2 使用Windows系统已经安装的字体
首先我们可以在C:\Windows\Fonts目录下找到我们已经安装的所有字体
然后找到自己喜欢的,右键属性可以查看字体资源的名称
与上述类似生成一个字体
BaseFont bfTable = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\STXINGKA.TTF",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font table= new Font(bfTable, 12, Font.NORMAL, BaseColor.BLACK);
但是这种方式不建议使用,依赖环境不适用,如果我们既不想使用iTextSharp自带的字体,又不想依赖环境,那就使用下面的这种方式(项目资源文件),也是我在上述封装代码中使用的方式。
3.2.3 使用项目资源字体文件
首先我们找到自己喜欢的字体文件,可以在windows系统字体资源目录中找到自己喜欢的并拷贝到项目资源目录.
windows字体资源路径:C:\Windows\Fonts
比如我在自己的项目下创建了一个叫Fonts文件夹
找到自己喜欢的文字资源,拷贝到此目录下
在代码中这样初始化文字样式即可:
//定义标题文字样式(华文行楷)
BaseFont bfTitle = BaseFont.CreateFont(System.Web.HttpContext.Current.Server.MapPath("/Fonts/STXINGKA.TTF"), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
Font ftitle = new Font(bfTitle, 28, Font.NORMAL, BaseColor.BLACK);
更多的使用技巧可以参考其官方文档或者自己研究源码尝试使用。
4.实现效果图
喜欢物联网的同学可以加我微信,一起交流学习