本文将重点介绍iTextSharp的使用方法和易踩的一些坑,顺便介绍了json转DataTable的简单快捷高效的方法及二进制流转换文件在线即时下载的方法。经测试生成40页的pdf仅需要1秒,大小不超过200k。性能与压缩率比较好。
最近接到个需求,就是把前端的表格数据用PDF的形式导出。用到的插件:
以上插件可在nuget中下载引用
前端的表如下:
前端的json数据结构如下:
说明:Hearder是数组,里面放的是每个列的参数,比如列宽,是否隐藏列(隐藏列不导出)等;DataList是数组,里面存放的是表格数据;Title存的表格名字
首先引入Newtonsoft.Json,目的是把前端传来的json数据转为DataTable。
本文用到了DeserializeObject
,该方法是反序列化JSON为对象,其中T是要反序列化的对象的类型,参数str为要反序列化的JSON字符串。
在了解以上方法后,我们首先根据上述的Json格式定义T的对象类型JsonObj,代码如下:
class JsonObj
{
public DataTable Header {
get; set; }
public DataTable DataList {
get; set; }
public string Title {
get; set; }
public string Code {
get; set; }
}
然后用JsonConvert.DeserializeObject
方法进行转换,代码如下:
JsonObj jsonObj = JsonConvert.DeserializeObject<JsonObj>(jsonText);
using System.Data;
using Newtonsoft.Json;
using SIE.Common.Helper.Tools;
using Newtonsoft.Json.Linq;
namespace SIE.Common.Web.Helper.File
{
///
/// 文件导出--Word,Pdf
///
public class FileExport
{
///
/// json数据处理
///
///
public static string JsonToDataTable(string jsonText)
{
JsonObj jsonObj = JsonConvert.DeserializeObject<JsonObj>(jsonText);
DataTable headerDt = jsonObj.Header;
DataTable dataDt = jsonObj.DataList;
string title = jsonObj.Title;
//调用第二节的方法ExportPDF
return ConvertPdf.ExportPDF(headerDt,dataDt,title);
}
class JsonObj
{
public DataTable Header {
get; set; }
public DataTable DataList {
get; set; }
public string Title {
get; set; }
}
}
}
这步我用到了iTextSharp,这个插件对应的是Java版本的iText,它是开源免费的。事实上,在本人实测的过程中,iTextSharp拥有强大的PDF操作能力,对于一些复杂的排版也能胜任,其排版语句类似于css方式排版,我使用iTextSharp版本为5.5的版本。有几点需要注意的是:
大多数pdf文件都是有页眉和页脚的,iTextSharp默认生成的pdf是没有页眉和页脚的,我们可以重写PdfPageEventHelper
进行自定义设置,在重写OnStartPage
方法设置页眉,重写OnEndPage方法设置页脚,代码如下:
///
/// 继承PdfPageEventHelper,重写页眉页脚
///
public class ItextPdfHeaderFooter : PdfPageEventHelper
{
PdfContentByte cb;
PdfTemplate template;
// 中文字体
BaseFont bf = BaseFont.CreateFont(@"C:\Windows\Fonts\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
// 打印时间
DateTime PrintTime = DateTime.Now;
float fontSize = 10; //字体大小
float leftMargins = 14;//左边距
float rightMargins = 14;//右边距
float bottomMargins = 12;//底部边距
float topMargins = 12;//顶部边距
#region 页眉基础属性
private string _Title;
public string Title
{
get {
return _Title; }
set {
_Title = value; }
}
public PdfPTable _Table;
public PdfPTable Table
{
get {
return _Table; }
set {
_Table=value; }
}
private string _HeaderLeft;
public string HeaderLeft
{
get {
return _HeaderLeft; }
set {
_HeaderLeft = value; }
}
private string _HeaderRight;
public string HeaderRight
{
get {
return _HeaderRight; }
set {
_HeaderRight = value; }
}
#endregion
// 重写onOpenDocument方法
public override void OnOpenDocument(PdfWriter writer, Document document)
{
try
{
PrintTime = DateTime.Now;
cb = writer.DirectContent;
template = cb.CreateTemplate(50, 50);
}
catch (DocumentException de)
{
}
catch (System.IO.IOException ioe)
{
}
}
///
/// 页眉--页头
///
///
///
public override void OnStartPage(PdfWriter writer, Document document)
{
base.OnStartPage(writer, document);
Rectangle pageSize = document.PageSize;
if (Title != null)
{
cb.BeginText();
cb.SetFontAndSize(bf, fontSize);
cb.SetRGBColorFill(50, 50, 200);
cb.SetTextMatrix(pageSize.GetLeft(leftMargins), pageSize.GetTop(topMargins));
cb.ShowText(Title);
cb.EndText();
}
iTextSharp.text.Font font = new Font(bf, 10, Font.NORMAL, new BaseColor(110, 84, 40));//标题
PdfPTable HeaderTable = new PdfPTable(2);
HeaderTable.DefaultCell.VerticalAlignment = Element.ALIGN_MIDDLE;
HeaderTable.TotalWidth = pageSize.Width - 28;
HeaderTable.SetWidthPercentage(new float[] {
45, 45 }, pageSize);
PdfPCell HeaderLeftCell = new PdfPCell(new Phrase(8, "xxxx公司", font));
HeaderLeftCell.BorderWidthLeft = 0;
HeaderLeftCell.BorderWidthTop = 0;
HeaderLeftCell.BorderWidthRight = 0;
HeaderTable.AddCell(HeaderLeftCell);
PdfPCell HeaderRightCell = new PdfPCell(new Phrase(8, "xxxx有限公司", font));
HeaderRightCell.HorizontalAlignment = PdfPCell.ALIGN_RIGHT;
HeaderRightCell.BorderWidthLeft = 0;
HeaderRightCell.BorderWidthRight = 0;
HeaderRightCell.BorderWidthTop = 0;
HeaderTable.AddCell(HeaderRightCell);
cb.SetRGBColorFill(0, 0, 0);
HeaderTable.WriteSelectedRows(0, -1, pageSize.GetLeft(14), pageSize.GetTop(8), cb);
}
///
/// 页脚--页码
///
///
///
public override void OnEndPage(PdfWriter writer, Document document)
{
base.OnEndPage(writer, document);
int pageN = writer.PageNumber;
String text = "第" + pageN + "页,";
float len = bf.GetWidthPoint(text, fontSize);
Rectangle pageSize = document.PageSize;
cb.SetRGBColorFill(100, 100, 100);
cb.BeginText();
cb.SetFontAndSize(bf, fontSize);
cb.SetTextMatrix(pageSize.GetLeft(leftMargins), pageSize.GetBottom(bottomMargins));
cb.ShowText(text);
cb.EndText();
cb.AddTemplate(template, pageSize.GetLeft(leftMargins) + len, pageSize.GetBottom(bottomMargins));
cb.BeginText();
cb.SetFontAndSize(bf, fontSize);
cb.ShowTextAligned(PdfContentByte.ALIGN_RIGHT,
"生成时间: " + PrintTime.ToString(),
pageSize.GetRight(rightMargins),
pageSize.GetBottom(bottomMargins), 0);
cb.EndText();
}
public override void OnCloseDocument(PdfWriter writer, Document document)
{
base.OnCloseDocument(writer, document);
template.BeginText();
template.SetFontAndSize(bf, fontSize);
template.SetTextMatrix(0, 0);
template.ShowText("共" + (writer.PageNumber - 1)+"页");
template.EndText();
}
}
当我们输出一个表格的时候,当表格超出一页时,iTextSharp默认是只在第一页显示表头而其他页不显示标题只显示数据,如果我们需要在每一页都显示表头就可以设置如下语句:
table.HeaderRows = 1;//比如说有两行表头就可以设置2
我们可以在创建文件时用MemoryStream
的形式,然后把MemoryStream
文件流转为base64字符编码,返回给前端直接下载。详见三。
using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Data;
using System.IO;
using System.Linq;
namespace SIE.Common.Helper.Tools
{
public class ConvertPdf
{
public static float _fontSize= 12; //字体大小
public static float _fontSize2 = 10;
public static Rectangle _pageSize = PageSize.A4;//设置pdf文档纸张大小
//字体读取的是windows系统宋体,
public static BaseFont basefont = BaseFont.CreateFont(@"C:\Windows\Fonts\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
///
/// DataTable导出到Excel的MemoryStream
///
/// 表头
/// 数据
///
///
public static string ExportPDF(DataTable dtStru, DataTable dtSource,string title)
{
MemoryStream mspdf = new MemoryStream();
string base64Code = null;
iTextSharp.text.Font font = new Font(basefont, _fontSize2, Font.BOLD);//标题
iTextSharp.text.Font font2 = new Font(basefont, _fontSize2);//普通列
Document document = new Document(_pageSize, 14, 14, 28, 24);
PdfWriter pdfWriter= PdfWriter.GetInstance(document, mspdf);
ItextPdfHeaderFooter headerFooter = new ItextPdfHeaderFooter();
pdfWriter.PageEvent = headerFooter;
document.Open();
document.AddTitle(title);
Paragraph element = new Paragraph(title, new Font(basefont, 14));
element.SpacingAfter = 10; //设置离后面内容的间距
element.Alignment = Element.ALIGN_CENTER;
document.Add(element);
PdfPTable table = new PdfPTable(dtStru.Rows.Count);
table.WidthPercentage = 100;//设置表格宽度占用百分比
var width = (from dt in dtStru.AsEnumerable() select float.Parse(dt["width"].ToString())).ToArray();
table.SetTotalWidth(width);
#region 表头
foreach (DataRow item in dtStru.Rows)
{
PdfPCell cell = new PdfPCell(new Paragraph(item["value"].ToString(), font));
//cell.Colspan = 2; //定义一个表格单元的跨度
cell.Rowspan = 2;
cell.BackgroundColor = new BaseColor(142,229,238);
cell.VerticalAlignment = PdfPCell.ALIGN_MIDDLE; //垂直居中
cell.HorizontalAlignment = PdfPCell.ALIGN_CENTER;//水平居中
table.AddCell(cell);
}
#endregion
var i = 0;
#region 数据载入
foreach (DataRow item in dtSource.Rows)
{
i++;
foreach (DataRow item2 in dtStru.Rows)
{
var fldname = item2["name"].ToString();
var df_value = item[fldname].ToString();
PdfPCell cell_data = new PdfPCell(new Paragraph(df_value, font2));
//隔行变色
if (i % 2 == 0)
{
cell_data.BackgroundColor = new BaseColor(253, 245, 230);
}
cell_data.VerticalAlignment = PdfPCell.ALIGN_MIDDLE; //垂直居中
cell_data.HorizontalAlignment = PdfPCell.ALIGN_CENTER;//水平居中
table.AddCell(cell_data);
}
}
#endregion
//设置表头的个数, 让它在每一页都显示出来
if (dtSource.Rows.Count == 0)
{
table.HeaderRows = 1;
}else
{
table.HeaderRows = 2;
}
document.Add(table);
document.Close();
//转换base64编码
base64Code = Convert.ToBase64String(mspdf.ToArray());
return base64Code;
}
}
///
/// 继承PdfPageEventHelper,重写页眉页脚
///
public class ItextPdfHeaderFooter : PdfPageEventHelper
{
PdfContentByte cb;
PdfTemplate template;
// 中文字体
BaseFont bf = BaseFont.CreateFont(@"C:\Windows\Fonts\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
// 打印时间
DateTime PrintTime = DateTime.Now;
float fontSize = 10; //字体大小
float leftMargins = 14;//左边距
float rightMargins = 14;//右边距
float bottomMargins = 12;//底部边距
float topMargins = 12;//顶部边距
#region 页眉基础属性
private string _Title;
public string Title
{
get {
return _Title; }
set {
_Title = value; }
}
public PdfPTable _Table;
public PdfPTable Table
{
get {
return _Table; }
set {
_Table=value; }
}
private string _HeaderLeft;
public string HeaderLeft
{
get {
return _HeaderLeft; }
set {
_HeaderLeft = value; }
}
private string _HeaderRight;
public string HeaderRight
{
get {
return _HeaderRight; }
set {
_HeaderRight = value; }
}
#endregion
// 重写onOpenDocument方法
public override void OnOpenDocument(PdfWriter writer, Document document)
{
try
{
PrintTime = DateTime.Now;
cb = writer.DirectContent;
template = cb.CreateTemplate(50, 50);
}
catch (DocumentException de)
{
}
catch (System.IO.IOException ioe)
{
}
}
///
/// 页眉--页头
///
///
///
public override void OnStartPage(PdfWriter writer, Document document)
{
base.OnStartPage(writer, document);
Rectangle pageSize = document.PageSize;
if (Title != null)
{
cb.BeginText();
cb.SetFontAndSize(bf, fontSize);
cb.SetRGBColorFill(50, 50, 200);
cb.SetTextMatrix(pageSize.GetLeft(leftMargins), pageSize.GetTop(topMargins));
cb.ShowText(Title);
cb.EndText();
}
iTextSharp.text.Font font = new Font(bf, 10, Font.NORMAL, new BaseColor(110, 84, 40));//标题
PdfPTable HeaderTable = new PdfPTable(2);
HeaderTable.DefaultCell.VerticalAlignment = Element.ALIGN_MIDDLE;
HeaderTable.TotalWidth = pageSize.Width - 28;
HeaderTable.SetWidthPercentage(new float[] {
45, 45 }, pageSize);
PdfPCell HeaderLeftCell = new PdfPCell(new Phrase(8, "xxxx公司", font));
HeaderLeftCell.BorderWidthLeft = 0;
HeaderLeftCell.BorderWidthTop = 0;
HeaderLeftCell.BorderWidthRight = 0;
HeaderTable.AddCell(HeaderLeftCell);
PdfPCell HeaderRightCell = new PdfPCell(new Phrase(8, "xxxx部门", font));
HeaderRightCell.HorizontalAlignment = PdfPCell.ALIGN_RIGHT;
HeaderRightCell.BorderWidthLeft = 0;
HeaderRightCell.BorderWidthRight = 0;
HeaderRightCell.BorderWidthTop = 0;
HeaderTable.AddCell(HeaderRightCell);
cb.SetRGBColorFill(0, 0, 0);
HeaderTable.WriteSelectedRows(0, -1, pageSize.GetLeft(14), pageSize.GetTop(8), cb);
}
///
/// 页脚--页码
///
///
///
public override void OnEndPage(PdfWriter writer, Document document)
{
base.OnEndPage(writer, document);
int pageN = writer.PageNumber;
String text = "第" + pageN + "页,";
float len = bf.GetWidthPoint(text, fontSize);
Rectangle pageSize = document.PageSize;
cb.SetRGBColorFill(100, 100, 100);
cb.BeginText();
cb.SetFontAndSize(bf, fontSize);
cb.SetTextMatrix(pageSize.GetLeft(leftMargins), pageSize.GetBottom(bottomMargins));
cb.ShowText(text);
cb.EndText();
cb.AddTemplate(template, pageSize.GetLeft(leftMargins) + len, pageSize.GetBottom(bottomMargins));
cb.BeginText();
cb.SetFontAndSize(bf, fontSize);
cb.ShowTextAligned(PdfContentByte.ALIGN_RIGHT,
"生成时间: " + PrintTime.ToString(),
pageSize.GetRight(rightMargins),
pageSize.GetBottom(bottomMargins), 0);
cb.EndText();
}
public override void OnCloseDocument(PdfWriter writer, Document document)
{
base.OnCloseDocument(writer, document);
template.BeginText();
template.SetFontAndSize(bf, fontSize);
template.SetTextMatrix(0, 0);
template.ShowText("共" + (writer.PageNumber - 1)+"页");
template.EndText();
}
}
}
从后端获取base64字符串,转换Uint8Array类型,再转为blob类型,最后进行下载。
/*res返回的字符串*/
function (res) {
var base64 = JSON.parse(res.Result);
base64 = base64.replace(/[\n\r]/g, '');
var raw = window.atob(base64);
let rawLength = raw.length;
//转换成pdf.js能直接解析的Uint8Array类型
let uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
// 字符内容转变成blob
var blob = new Blob([uInt8Array], {
type: 'application/pdf' });//转成pdf类型
// 创建隐藏的可下载链接
var eleLink = document.createElement('a');
eleLink.download = title + '.pdf';
eleLink.style.display = 'none';
eleLink.href = URL.createObjectURL(blob);
// 触发点击
document.body.appendChild(eleLink);
eleLink.click();
// 然后移除
document.body.removeChild(eleLink);
}
ps:创作不易,点个赞吧!!!