通过 Web 导出表格数据为 PDF 格式
本文提供了一个通过 Web 以 PDF 格式导出表格数据的示例。
引言
本文提供了一个通过 Web 以 PDF 格式导出表格数据的示例。
背景
有时,您可能希望以 PDF 格式导出一些数据。本文将通过 Web,使用“iTextSharp”提供一个以 PDF 格式导出表格数据的示例。该示例将使用一个“MVC”控制器来导出生成的 PDF 文件,因此我将假定读者对“ASP.NET MVC”有一定的基础知识。

附件是使用 Visual Studio 2010 开发的一个“MVC”应用程序。此示例使用“iTextSharp”创建 PDF 文档。您可以从此处下载“iTextSharp”。
- “Utilities”文件夹中的“PdfTabularReport.cs”和“ReportConfiguration.cs”文件实现了用于生成 PDF 文档的一些实用类。
- “Models”文件夹中的“StudentRepository.cs”文件是应用程序的数据模型。
- “Controllers”文件夹中的“HomeController.cs”文件是“MVC”应用程序的控制器。其主要功能是调用 PDF 实用类来创建 PDF 文档并将其发送到 Web 浏览器。
- “Default.htm”是用户可以下载 PDF 文档的网页。
我将首先介绍这些实用类,然后向您展示如何使用这些类来创建 PDF 文档以及如何将它们发送到 Web 浏览器。
实用类
实用类实现在两个文件中。以下是“ReportConfiguration.cs”文件。
using iTextSharp.text;
namespace iTextTabularReport.Utilities
{
public class ReportColumn
{
public string ColumnName { get; set; }
public int Width { get; set; }
private string headerText;
public string HeaderText { set { headerText = value; }
get { return headerText ?? ColumnName; } }
}
public class ReportConfiguration
{
// Overall page layout, orientation and margins
private Rectangle pageOrientation = PageSize.LETTER;
private int marginLeft = 30;
private int marginTop = 20;
private int marginRight = 30;
private int marginBottom = 30;
public Rectangle PageOrientation { get { return pageOrientation; }
set { pageOrientation = value; } }
public int MarginLeft { get { return marginLeft; } set { marginLeft = value; } }
public int MarginTop { get { return marginTop; } set { marginTop = value; } }
public int MarginRight
{ get { return marginRight; } set { marginRight = value; } }
public int MarginBottom
{ get { return marginBottom; } set { marginBottom = value; } }
// Logo - Logo is always placed at the top left corner
private int logImageScalePercent = 100;
public string LogoPath { get; set; }
public int LogImageScalePercent { get { return logImageScalePercent; }
set { logImageScalePercent = value; } }
// Title and subtitle. Titles are always center aligned at the top.
public string ReportTitle { get; set; }
public string ReportSubTitle { get; set; }
}
}
此文件中实现了两个类。这两个类由“PdfTabularReport.cs”文件中实现的类用于配置 PDF 文档。
- “
ReportColumn
”类定义了表格数据的列的宽度和标题文本。 - “
ReportConfiguration
”类定义了 PDF 文档的通用布局。
“PdfTabularReport.cs”文件的实现如下:
using System;
using System.Linq;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Data;
using System.Collections.Generic;
namespace iTextTabularReport.Utilities
{
// The main class used to generate Pdf tabular report.
public class PdfTabularReport
{
// Configurations
public ReportConfiguration ReportConfiguration { get; set; }
// Internal properties, not set outside of the class
public Image LogoImage { get; private set; }
public PdfPTable Title { get; private set; }
public PdfPTable PageNumberLabel { get; private set; }
public float HeaderSectionHeight { get; private set; }
public int PageCount { get; private set; }
// Private instance variables
Document PdfDocument = null;
PdfWriter PdfWriter = null;
MemoryStream PdfStream = null;
// Constructor
public PdfTabularReport(ReportConfiguration configuration = null)
{
// If configuration is not provided, the default will be used
ReportConfiguration = configuration ?? new ReportConfiguration();
}
private void InitiateDocument()
{
PdfStream = new MemoryStream();
PdfDocument = new Document(ReportConfiguration.PageOrientation);
PdfDocument.SetMargins(ReportConfiguration.MarginLeft,
ReportConfiguration.MarginRight,
ReportConfiguration.MarginTop, ReportConfiguration.MarginBottom);
PdfWriter = PdfWriter.GetInstance(PdfDocument, PdfStream);
// create logo, header and page number objects
PdfPCell cell;
HeaderSectionHeight = 0;
LogoImage = null;
if (ReportConfiguration.LogoPath != null)
{
LogoImage = Image.GetInstance(ReportConfiguration.LogoPath);
LogoImage.ScalePercent(ReportConfiguration.LogImageScalePercent);
LogoImage.SetAbsolutePosition(PdfDocument.LeftMargin,
PdfDocument.PageSize.Height - PdfDocument.TopMargin
- LogoImage.ScaledHeight);
HeaderSectionHeight = LogoImage.ScaledHeight;
}
Title = null;
float titleHeight = 0;
if ((ReportConfiguration.ReportTitle != null) ||
(ReportConfiguration.ReportSubTitle != null))
{
Title = new PdfPTable(1);
Title.TotalWidth = PdfDocument.PageSize.Width
- (PdfDocument.LeftMargin + PdfDocument.RightMargin);
if (ReportConfiguration.ReportTitle != null)
{
cell = new PdfPCell(new Phrase(ReportConfiguration.ReportTitle,
new Font(ReportFonts.HelveticaBold, 12)));
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.Border = 0;
Title.AddCell(cell);
}
if (ReportConfiguration.ReportSubTitle != null)
{
cell = new PdfPCell(new Phrase(ReportConfiguration.ReportSubTitle,
new Font(ReportFonts.Helvetica, 10)));
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.PaddingTop = 5;
cell.Border = 0;
Title.AddCell(cell);
}
// Get the height of the title section
for (int i = 0; i < Title.Rows.Count; i++)
{
titleHeight = titleHeight + Title.GetRowHeight(i);
}
}
HeaderSectionHeight = (HeaderSectionHeight > titleHeight)
? HeaderSectionHeight : titleHeight;
PageNumberLabel = new PdfPTable(1);
PageNumberLabel.TotalWidth = PdfDocument.PageSize.Width
- (PdfDocument.LeftMargin + PdfDocument.RightMargin);
cell = new PdfPCell(new Phrase
("Page Label", new Font(ReportFonts.Helvetica, 8)));
cell.Border = 0;
float pagenumberHeight = PageNumberLabel.GetRowHeight(0);
HeaderSectionHeight = (HeaderSectionHeight > pagenumberHeight)
? HeaderSectionHeight : pagenumberHeight;
}
private MemoryStream RenderDocument(ReportTable reportTable)
{
PdfWriter.PageEvent = new PageEventHelper { Report = this };
PdfDocument.Open();
reportTable.RenderTable(PdfDocument, PdfWriter);
PdfDocument.Close();
PdfWriter.Flush();
return PdfStream;
}
// Method to get the pdf stream
public MemoryStream GetPdf<T>(List<T> data, List<ReportColumn> displayColumns)
{
InitiateDocument();
// Add the report data
var top = (HeaderSectionHeight == 0)
? PdfDocument.PageSize.Height - PdfDocument.TopMargin
: PdfDocument.PageSize.Height - PdfDocument.TopMargin
- HeaderSectionHeight - 10;
var reportTable = ReportTable.CreateReportTable<T>(data,
displayColumns, top, PdfDocument);
PageCount = reportTable.PageCount;
return RenderDocument(reportTable);
}
// Overloaded method to get the pdf stream. It takes that data as DataTable
public MemoryStream GetPdf(DataTable data, List<ReportColumn> displayColumns)
{
List<DataRow> list = data.AsEnumerable().ToList();
return GetPdf<DataRow>(list, displayColumns);
}
}
// Fonts used by the tabular report
public class ReportFonts
{
public static BaseFont Helvetica {
get { return BaseFont.CreateFont(BaseFont.HELVETICA,
BaseFont.CP1252, false); } }
public static BaseFont HelveticaBold {
get { return BaseFont.CreateFont(BaseFont.HELVETICA_BOLD,
BaseFont.CP1252, false); } }
}
// Utility class to render the Pdf table to the report document
internal class ReportTable
{
private PdfPTable headerTable;
private PdfPTable dataTable;
private List<Tuple<int, int>> pageSplitter;
private float width;
private float top;
private float height;
public int PageCount
{
get { return (pageSplitter.Count == 0) ? 1 : pageSplitter.Count; }
}
// Private constructor. The instances need to use "CreateReportTable"
// method to create.
private ReportTable(List<ReportColumn> displayColumns,
Document document, float top)
{
pageSplitter = new List<Tuple<int, int>>();
this.top = top;
width = document.PageSize.Width
- document.LeftMargin - document.RightMargin;
height = top - document.BottomMargin;
float[] columnWidths =
(from c in displayColumns select (float)c.Width).ToArray();
headerTable = new PdfPTable(columnWidths);
headerTable.TotalWidth = width;
dataTable = new PdfPTable(columnWidths);
dataTable.TotalWidth = width;
foreach (var column in displayColumns)
{
AddCell(headerTable, column.HeaderText,
new Font(ReportFonts.HelveticaBold, 10), BaseColor.WHITE, 5f);
}
}
private static void AddCell(PdfPTable table, string Text, Font font,
BaseColor backgroundColor = null, float padding = 3f)
{
PdfPCell cell = new PdfPCell(new Paragraph(Text, font));
cell.Padding = padding;
cell.Border = 0;
cell.VerticalAlignment = Element.ALIGN_MIDDLE;
cell.BackgroundColor = backgroundColor ?? BaseColor.WHITE;
table.AddCell(cell);
}
private static void AddRow(Object dataitem, System.Type type,
List<ReportColumn> displayColumns, BaseColor color, PdfPTable table)
{
foreach (var column in displayColumns)
{
var text = string.Empty;
if (type.FullName == "System.Data.DataRow")
{
text = ((DataRow) dataitem)[column.ColumnName].ToString();
}
else
{
var propertyInfo = type.GetProperty(column.ColumnName);
text = (propertyInfo.GetValue(dataitem, null) == null)
? ""
: propertyInfo.GetValue(dataitem, null).ToString();
}
AddCell(table, text, new Font(ReportFonts.Helvetica, 8), color);
}
}
// Static method to create & return an instance object
public static ReportTable CreateReportTable<T>(List<T> data,
List<ReportColumn> displayColumns, float top, Document document)
{
// Construct an instance object
var reportTable = new ReportTable(displayColumns, document, top);
var type = typeof(T);
// Add each data item into the PdfPTable.
int srartRow = 0;
int pageRowIndex = 0;
float headerHeight = reportTable.headerTable.GetRowHeight(0);
float actualHeight = headerHeight;
for (int i = 0; i < data.Count; i++)
{
var dataItem = data[i];
BaseColor color = (pageRowIndex++ % 2 == 0)
? BaseColor.LIGHT_GRAY : BaseColor.WHITE;
AddRow(dataItem, type, displayColumns, color, reportTable.dataTable);
actualHeight = actualHeight + reportTable.dataTable.GetRowHeight(i);
var lastRowReached = i == data.Count - 1;
if ((actualHeight > reportTable.height) || lastRowReached)
{
reportTable.pageSplitter.Add(new Tuple<int, int>(srartRow,
lastRowReached ? -1 : i));
if (!lastRowReached)
{
reportTable.dataTable.DeleteLastRow();
AddRow(dataItem, type, displayColumns, BaseColor.LIGHT_GRAY,
reportTable.dataTable);
pageRowIndex = 1;
}
actualHeight = headerHeight + reportTable.dataTable.GetRowHeight(i);
srartRow = i;
}
}
return reportTable;
}
// Render the table to the Pdf document.
public void RenderTable(Document document, PdfWriter writer)
{
float left = (document.PageSize.Width - headerTable.TotalWidth)/2;
var pageCount = pageSplitter.Count;
float headerHeight = headerTable.GetRowHeight(0);
for (int i = 0; i < pageCount; i++)
{
var rownumbers = pageSplitter[i];
headerTable.WriteSelectedRows(0, 1, left, top, writer.DirectContent);
dataTable.WriteSelectedRows(rownumbers.Item1, rownumbers.Item2,
left, top - headerHeight, writer.DirectContent);
if (i != pageCount - 1)
{
document.NewPage();
}
}
}
}
// PdfPageEventHelper: logo, title, sub-title, and page numbers.
public class PageEventHelper: PdfPageEventHelper
{
public PdfTabularReport Report { get; set; }
private void AddHeader(Document document, PdfWriter writer)
{
// Add logo
if (Report.LogoImage != null)
{
document.Add(Report.LogoImage);
}
// Add titles
if (Report.Title != null)
{
Report.Title.WriteSelectedRows(0, -1, document.LeftMargin,
document.PageSize.Height - document.TopMargin, writer.DirectContent);
}
// Add page number
Report.PageNumberLabel.DeleteLastRow();
var cell = new PdfPCell(new Phrase("Page " + document.PageNumber.ToString()
+ " of "
+ Report.PageCount.ToString(), new Font(ReportFonts.Helvetica, 8)));
cell.Border = 0;
cell.HorizontalAlignment = Element.ALIGN_RIGHT;
Report.PageNumberLabel.AddCell(cell);
var cellHeight = Report.PageNumberLabel.GetRowHeight(0);
Report.PageNumberLabel.WriteSelectedRows(0, -1, document.LeftMargin,
document.PageSize.Height - document.TopMargin - Report.HeaderSectionHeight
+ cellHeight, writer.DirectContent);
}
public override void OnStartPage(PdfWriter writer, Document document)
{
base.OnStartPage(writer, document);
AddHeader(document, writer);
}
}
}
“PdfTabularReport.cs”文件实现了四个类:
- “
PdfTabularReport
”类是我们用于生成 PDF 文档的主要类。 - “
ReportFonts
”定义了 PDF 文档中使用的字体。 - “
ReportTable
”类是“PdfTabularReport
”类用于渲染表格数据的一个辅助类。 - “
PageEventHelper
”类扩展了“PdfPageEventHelper”类。它在文档的每个 PDF 页面上渲染 Logo 图片、报表标题和页码。
在本文的其余部分,我将向您展示如何使用这些实用类来导出您的表格数据。
数据模型
此应用程序中的数据模型实现在“Models\StudentRepository.cs”文件中。
using System;
using System.Collections.Generic;
using System.Data;
namespace iTextTabularReport.Models
{
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Enrollment { get; set; }
public int Score { get; set; }
}
public static class StudentRepository
{
public static List<Student> GetStudentList(int NoOfStudents)
{
var students = new List<Student>();
var rand = new Random();
for (int i = 1; i <= NoOfStudents; i++)
{
var student = new Student();
student.Id = i;
student.Name = "Student Name No." + i.ToString();
student.Enrollment = DateTime.Now;
student.Score = 60 + (int)(rand.NextDouble() * 40);
students.Add(student);
}
return students;
}
public static DataTable GetStudentsTable(int NoOfStudents)
{
var students = new DataTable();
students.Columns.Add(new DataColumn("ID", Type.GetType("System.Int32")));
students.Columns.Add(new DataColumn("Name", Type.GetType("System.String")));
students.Columns.Add(new DataColumn("Enrollment",
Type.GetType("System.DateTime")));
students.Columns.Add(new DataColumn("Score", Type.GetType("System.Int32")));
var rand = new Random();
for (int i = 1; i <= NoOfStudents; i++)
{
Object[] data = new Object[4];
data[0] = i;
data[1] = "Student Name No." + i.ToString();
data[2] = DateTime.Now;
data[3] = 60 + (int)(rand.NextDouble() * 40);
students.Rows.Add(data);
}
return students;
}
}
}
“HomeController.cs”实现了两个类:
- “
Student
”类定义了一个学生。 - “
StudentRepository
”实现了两个static
方法来返回一组学生的信息。其中一个方法以“List<Student>
”形式返回学生,另一个方法以“DataTable”形式返回学生。
示例应用程序将使用“StudentRepository
”类的数据来渲染表格 PDF 文档并将其发送到 Web 浏览器。
MVC 控制器
“MVC”控制器实现在“Controllers\HomeController.cs”文件中。
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using iTextSharp.text;
using iTextTabularReport.Utilities;
using iTextTabularReport.Models;
namespace iTextTabularReport.Controllers
{
[HandleError]
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return new RedirectResult("~/Default.htm");
}
[HttpGet]
public void GetPdf()
{
var configuration = new ReportConfiguration();
configuration.PageOrientation = PageSize.LETTER_LANDSCAPE.Rotate();
configuration.LogoPath
= Server.MapPath(Url.Content("~/Content/Images/Logo.jpg"));
configuration.LogImageScalePercent = 50;
configuration.ReportTitle
= "Export Tabular Data in Pdf Format through the Web";
configuration.ReportSubTitle = "Created by iText Report Tool";
var report = new PdfTabularReport();
report.ReportConfiguration = configuration;
List<ReportColumn> columns = new List<ReportColumn>();
columns.Add(new ReportColumn { ColumnName = "Id", Width = 100 });
columns.Add(new ReportColumn { ColumnName = "Name", Width = 100 });
columns.Add(new ReportColumn { ColumnName = "Enrollment", Width = 100 });
columns.Add(new ReportColumn { ColumnName = "Score", Width = 100 });
var stream = report.GetPdf(StudentRepository.GetStudentsTable(1000), columns);
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition",
"attachment;filename=ExampleReport.pdf");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.BinaryWrite(stream.ToArray());
Response.End();
}
}
}
要在此示例中使用实用类生成 PDF 文档,我们需要执行以下步骤:
- 创建一个包含相同信息的“
List<Student>
”对象或“DataTable
”。在本文中,我使用“DataTable
”为实用类“PdfTabularReport
”提供数据。 - 创建一个“
ReportConfiguration
”对象,并为 PDF 文档应用所需的配置。 - 创建一个“
List<ReportColumn>
”来配置表格数据中的每一列。如果“Student
”对象中的任何属性或“DataTable
”中的任何列未包含在此“List
”中,则相应的列不会在 PDF 文档中显示。“ReportColumn
”类中的“Width
”属性是列的相对宽度。表格的总宽度始终覆盖文档的总宽度。 - “
PdfTabularReport
”中的“GetPdf”方法返回生成的 PDF 文档,形式为“MemoryStream
”。
当获取到 PDF “MemoryStream
”后,我们可以将其保存到文件或发送到 Web 浏览器。在此示例中,我只是将其发送到了 Web 浏览器。
“Default.htm”页面
“Default.htm”页面的实现如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>iText Tabular Report</title>
<link href="Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div>
<a href="Home/GetPdf" class="button">Get Pdf Report</a>
</div>
</body>
</html>
这个简单的“html
”页面只有一个指向“MVC”操作方法“GetPdf
”的“超链接”。单击它将触发动态生成的“PDF”文档的生成和下载。
运行应用程序
我们现在完成了此示例应用程序的开发。让我们对其进行测试。

应用程序启动时,会加载“Default.htm”文件。应用程序中的 CSS 样式使“超链接”看起来像一个按钮。单击“Get Pdf Report”按钮,PDF 文档将生成并下载到 Web 浏览器。下图显示了文档的第 6 页。

您可以看到,Logo 图片、标题、页码、总页数和数据列标题都显示在 PDF 文档的每一页上。
关注点
- 本文提供了一个通过 Web 以 PDF 格式导出表格数据的示例。
- 虽然此示例仅向您展示了如何将 PDF 文档发送到 Web 浏览器,但您也可以毫无问题地使用这些实用类来创建 PDF 文件并将其保存到您的硬盘驱动器。
- 您可以准备您的数据,格式为“
List<Object>
”或“DataTable
”。本示例中的实用类可以处理这两种格式。 - 我将通过本文来纪念并致敬“Dennis Ritchie”,他是我辈所见过最伟大的人之一。
- 我希望您喜欢我的文章,希望本文能以某种方式帮助您。
历史
- 首次修订 - 2011/10/13