前言

本文将重点介绍iTextSharp的使用方法和易踩的一些坑,顺便介绍了json转DataTable的简单快捷高效的方法及二进制流转换文件在线即时下载的方法。经测试生成40页的pdf仅需要1秒,大小不超过200k。性能与压缩率比较好。

最近接到个需求,就是把前端的表格数据用PDF的形式导出。用到的插件:

  • Newtonsoft.Json
  • iTextSharp

以上插件可在nuget中下载引用

一、json转DataTable

前端的表如下:

前端的json数据结构如下:


说明:Hearder是数组,里面放的是每个列的参数,比如列宽,是否隐藏列(隐藏列不导出)等;DataList是数组,里面存放的是表格数据;Title存的表格名字

1.定义接收类

首先引入Newtonsoft.Json,目的是把前端传来的json数据转为DataTable。
本文用到了DeserializeObject<T>(string str),该方法是反序列化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; }}

2.转换json

然后用JsonConvert.DeserializeObject<T>(string str)方法进行转换,代码如下:

JsonObj jsonObj = JsonConvert.DeserializeObject<JsonObj>(jsonText);

3.完整代码

using System.Data;
using Newtonsoft.Json;
using SIE.Common.Helper.Tools;
using Newtonsoft.Json.Linq;namespace SIE.Common.Web.Helper.File
{/// <summary>/// 文件导出--Word,Pdf/// </summary>public class FileExport{/// <summary>/// json数据处理/// </summary>/// <param name="jsonText"></param>public static string JsonToDataTable(string jsonText){JsonObj jsonObj = JsonConvert.DeserializeObject<JsonObj>(jsonText);DataTable headerDt = jsonObj.Header;DataTable dataDt = jsonObj.DataList;            string title = jsonObj.Title; //调用第二节的方法ExportPDFreturn ConvertPdf.ExportPDF(headerDt,dataDt,title);        }class JsonObj{public DataTable Header { get; set; }public DataTable DataList { get; set; }public string Title { get; set; }}}
}

二、DataTable转PDF

这步我用到了iTextSharp,这个插件对应的是Java版本的iText,它是开源免费的。事实上,在本人实测的过程中,iTextSharp拥有强大的PDF操作能力,对于一些复杂的排版也能胜任,其排版语句类似于css方式排版,我使用iTextSharp版本为5.5的版本。有几点需要注意的是:

1.PDF的页眉和页脚:

大多数pdf文件都是有页眉和页脚的,iTextSharp默认生成的pdf是没有页眉和页脚的,我们可以重写PdfPageEventHelper进行自定义设置,在重写OnStartPage方法设置页眉,重写OnEndPage方法设置页脚,代码如下:

/// <summary>/// 继承PdfPageEventHelper,重写页眉页脚/// </summary>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){}}/// <summary>/// 页眉--页头/// </summary>/// <param name="writer"></param>/// <param name="document"></param>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);}/// <summary>/// 页脚--页码/// </summary>/// <param name="writer"></param>/// <param name="document"></param>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();}}

生成的pdf效果如下:页眉和页脚

2.PDF分页的表头

当我们输出一个表格的时候,当表格超出一页时,iTextSharp默认是只在第一页显示表头而其他页不显示标题只显示数据,如果我们需要在每一页都显示表头就可以设置如下语句:

table.HeaderRows = 1;//比如说有两行表头就可以设置2

3.PDF生成下载

我们可以在创建文件时用MemoryStream的形式,然后把MemoryStream文件流转为base64字符编码,返回给前端直接下载。详见三。

4.完整代码:

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);/// <summary>/// DataTable导出到Excel的MemoryStream/// </summary>/// <param name="dtStru">表头</param>/// <param name="dtSource">数据</param>/// <param name="title"></param>/// <returns></returns>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);}#endregionvar 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;}}/// <summary>/// 继承PdfPageEventHelper,重写页眉页脚/// </summary>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){}}/// <summary>/// 页眉--页头/// </summary>/// <param name="writer"></param>/// <param name="document"></param>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);}/// <summary>/// 页脚--页码/// </summary>/// <param name="writer"></param>/// <param name="document"></param>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();}}}

三、前端JS下载PDF文件

从后端获取base64字符串,转换Uint8Array类型,再转为blob类型,最后进行下载。

1.JS函数:

/*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);}// 字符内容转变成blobvar 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);}

2.最终效果:

ps:创作不易,点个赞吧!!!

C# Json数据转DataTable并生成PDF在线下载--iTextSharp生成PDF实例(文件下载,json数据转换,PDF排版一步到位)相关推荐

  1. @ResponseBody返回JSON数据,360安全浏览器弹出下载页面

    文章目录 问题重现 解决方法 成功解决 问题重现 Controller中使用@ResponseBody返回JSON数据. @Controller public class StudentControl ...

  2. 大数据之眼:无所不知的数字幽灵 - 电子书下载 -(百度网盘 高清版PDF格式)...

    大数据之眼:无所不知的数字幽灵-[德]尤夫娜·霍夫施泰特 在线阅读                   百度网盘下载(bsz3) 书名:大数据之眼:无所不知的数字幽灵 作者:[德]尤夫娜·霍夫施泰特 ...

  3. HTML的数据 转成 JSON数据中的 因HTML有大量及其它特殊符号会把JSON字符串截断该怎么...

    2019独角兽企业重金招聘Python工程师标准>>> 调用这个方法即可: EncodeJsString 详情链接 转载于:https://my.oschina.net/u/1266 ...

  4. PDF电子书下载 和 企业物联网实例 视频讲解——实践类

    <AIoT 物联网开发实战>PDF: 上册: 文件下载-阿里云开发者社区 下册: 文件下载-阿里云开发者社区 当我们购买企业物联网平台时,会看到3个核心指标:设备量,消息上下行TPS,规则 ...

  5. Python 自动化指南(繁琐工作自动化)第二版:十六、使用 CSV 文件和 JSON 数据

    原文:https://automatetheboringstuff.com/2e/chapter16/ 在第 15 章,你学习了如何从 PDF 和 Word 文档中提取文本.这些文件是二进制格式的,需 ...

  6. Android JSON数据解析(GSON方式)

    要创建和解析JSON数据,也可以使用GSON来完成.GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库.使用GSON,可以很容易的将一串JSON数据转换为一个Jav ...

  7. AJAX 跨域请求 - JSONP获取JSON数据

    Asynchronous JavaScript and XML (Ajax ) 是驱动新一代 Web 站点(流行术语为 Web 2.0 站点)的关键技术.Ajax 允许在不干扰 Web 应用程序的显示 ...

  8. $get服务器上的json文件,Web前端:$.getJSON获取json数据失败

    JSON(JavaScriptObjectNotation,JS对象简谱)是一种轻量级的数据交换格式.它基于ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本 ...

  9. python操作json_如何使用Python处理JSON数据

    如何使用Python处理JSON数据?本篇文章就给大家介绍使用Python处理JSON数据的基本方法.有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所帮助. 在介绍使用Python处理JSO ...

最新文章

  1. 应用设计模式进行重构来消除坏味道
  2. Leetcode PHP题解--D49 821. Shortest Distance to a Character
  3. 【论文笔记】Sparse filtering
  4. LeetCode——树:层次遍历、前中后序遍历
  5. 阿里Sentinel控制台源码修改-对接Apollo规则持久化
  6. 减小程序规模!稀疏数组Sparsearray,数据结构二维数组与稀疏数组转换,Java实现
  7. where里能用max吗_超市里四五元钱的速冻饺子能买吗?
  8. flex4的新数据类型ArrayList
  9. 200 行代码,一行行教你自制微信机器人
  10. Rocket - tilelink - AtomicAutomata
  11. python中英文切换_Python方法完成转换英文字符操作
  12. 在Deepin v20系统中安装RTL8821CE无线网卡驱动的步骤
  13. 大连商务英语培训百家外语国际部怎样提高商务英语阅读技能?
  14. 关于批量添加用户和域用户
  15. java实习第一周周报,大学生实习周报
  16. 国内外抠图平台性能调研
  17. b树的表示形式_B.Com的完整形式是什么?
  18. 结构体变量和结构体指针的区别,
  19. 网站劫持后通过什么好办法可以修复?
  20. UOS永久挂载smb共享文件夹

热门文章

  1. Java线程模仿电影院买票
  2. python的变量、运算符与数据类型(day1)
  3. Pytorch填充、步幅及多通道输入输出的理论分析及代码实现
  4. 外包出去找工作被歧视,投几个简历都说介意外包,不考虑外包。
  5. 举个栗子!Tableau 技巧(193):创建箭头环形进度图
  6. python爬虫高级知识分子的风骨_Python程序员爬取《万物理论》10万影评,带你解读霍金的有趣故事...
  7. 小程序毕业设计 基于微信点餐外卖小程序毕业设计开题报告功能参考
  8. Vue项目修改浏览器滚动条样式
  9. AWS-SS配置过程
  10. ATMEL SAMC20J多通道ADC问题