使用 ASP.NET MVC 和 Open Office 生成弹出 PDF 表单






4.50/5 (7投票s)
使用 Open Office 和 Sun PDF Import 插件创建 PDF 表单并在 ASP.NET MVC 中显示
引言
此演示展示了如何在 ASP.NET MVC 中生成和填充弹出 PDF 表单。生成的 PDF 表单将在新窗口中打开,但错误将显示在父窗口中。该演示还展示了如何使用免费的开源工具(如 Open Office 3.2 和 iTextSharp)创建和生成 PDF 表单,因此您不需要 Acrobat Pro 等付费工具。
设置您的环境
如果您没有 Acrobat Pro 来创建 PDF 表单,此演示将向您展示如何使用 Open Office 3.2 和 Sun PDF Import 扩展。
- 下载并安装 Open Office(它是免费且开源的):http://download.openoffice.org
- 下载并安装 Sun 的免费 PDF 导入 Open Office 扩展:http://extensions.services.openoffice.org/project/pdfimport
此演示中包含的内容
演示项目包括 iTextSharp 5.0.2.0 的免费开源 DLL,以及 jquery 1.3.2 和 query 插件的 JS 文件。
使用 OpenOffice 创建 PDF 表单
如果您没有 Acrobat Pro 来创建 PDF 表单,您可以使用免费的开源 Open Office 和 PDF Import 插件。
- 打开 OpenOffice Draw,创建您的表单。您还可以使用 PDF Import 插件导入现有的 PDF。
- 如果看不到“表单控件”工具栏,请转到“视图”-->“工具栏”-->“表单控件”将其添加。
- 对于您想要在表单中填充的每个字段,
- 在“表单控件”工具栏上选择“文本框”按钮,然后将其绘制在表单上。
- 选择该“文本框”,然后按“表单控件”工具栏上的“控件”按钮。格式化“文本框”
- 将边框更改为“无边框”,以便在生成时与表单融合。
- 将“文本框”的名称更改为有意义的名称。
- 将对齐方式更改为居中。
- 调整字体大小、粗细等。
- 保存文件,然后通过转到“文件”-->“导出为 PDF”将其导出为 PDF。
- 确保选择了“创建 PDF 表单”常规选项,并将“提交格式”设置为 PDF。
- 刷新您的“表单”文件夹,并将这两个文件添加到您的项目中。
- 如果您稍后想更改表单,则需要保留 ODG 文件,因为导出的 PDF 在导入回 Open Office 时会丢失“文本框”。如果您稍后打开 ODG 文件进行更改,请务必按“表单控件”工具栏上的“设计模式开/关”按钮,以在布局中查看和选择文本框。
创建 Controller GET 操作
在 `HomeController` 中,您将看到 `MyFormLetter` 的 `get` 和 `post` 操作。在 `get` 操作中,您将看到一个默认业务对象被创建并传递给视图。
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult MyFormLetter()
{
// by setting the Company property on the model,
// the form will be filled out with the company name,
// but not the applicant name
Applicant defaultApplicant = new Applicant()
{
Company = "My Company"
};
return View(defaultApplicant);
}
创建 View
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
表单操作指定了 post 操作,并在新浏览器窗口中打开 PDF。
<form action="<%= Url.Action("MyFormLetter", "Home") %>" method="post"
target="_blank"><!-- popup pdf to new window -->
输入字段会使用 `get` 操作中设置的业务对象属性进行预填充。
<input id="Company" name="Company" value="<%= Model.Company %>" />
创建 Controller Post 操作
`MyFormLetter` 视图会将用户填充的业务对象发布到 `MyFormLetter` post 操作。业务对象会根据业务逻辑进行修改,并填充 PDF 表单字段。PDF 文件由 `GetPdfFileStreamResult` 方法加载、生成和填充。如果发生错误,错误将返回到父页面,弹出表单将关闭。
/// <summary>
/// The MyFormLetter form posts to this action
/// </summary>
/// <param name="applicant"></param>
/// <returns></returns>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult MyFormLetter(Applicant applicant)
{
try
{
// uncomment this to test error handling
// throw new NullReferenceException("OH NOOOOOO");
// this is where you would get further info by calling business logic,
// data access, etc.
applicant.Company = "My Company";
// populate the value of each form field in the pdf form
Dictionary<string,> formFields = new Dictionary<string,>
{
{"ApplicantName", applicant.Name},
{"CompanyName", applicant.Company}
};
string fileName = "MyFormLetter.pdf";
// we don't want the user to see "MyFormLetter.pdf"
// when they save the file,
// we want them to see "YourFormLetter.pdf" when they save the PDF
// so we alias the name simply by passing it to another action
// named YourFormLetter
// pass the file stream result to the alias action
TempData["MyFormLetter_FileStreamResult"] =
GetPdfFileStreamResult(fileName, formFields);
return RedirectToAction("YourFormLetter");
}
catch (Exception ex)
{
return HandleErrorForPopup(ex, applicant);
}
}
为表单名称设置别名
当用户保存 PDF 文档时,文件的默认名称将设置为控制器操作名称。如果我们不想让用户看到“MyFormLetter.pdf”,而是希望他们看到“YourFormLetter.pdf”,我们可以简单地将 `FileStreamResult` 传递给一个名为 `YourFormLetter` 的新控制器操作。/// <summary>
/// When the user saves the pdf, the default name of the
/// file will be "YourFormLetter.pdf".
/// </summary>
/// <returns></returns>
public FileStreamResult YourFormLetter()
{
return (FileStreamResult) TempData["MyFormLetter_FileStreamResult"];
}
生成和填充 PDF 表单
`GetPdfFileStreamResult` 和 `GeneratePdf private` 方法从服务器加载 PDF 表单文件,并使用 iTextSharp 填充表单字段。
private FileStreamResult GetPdfFileStreamResult
(string fileName, Dictionary<string,> formFields)
{
MemoryStream memoryStream = GeneratePdf(fileName, formFields);
// create a new return stream because the
// MemoryStream from the file is closed
MemoryStream returnStream = new MemoryStream();
returnStream.Write(memoryStream.GetBuffer(), 0,
memoryStream.GetBuffer().Length);
returnStream.Flush();
// rewind stream back to beginning so it can be rendered to the page
returnStream.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(returnStream, "application/pdf");
}
private MemoryStream GeneratePdf(string fileName, Dictionary<string,> formFields)
{
string formFile = HttpContext.Server.MapPath("~/Forms/" + fileName);
PdfReader reader = new PdfReader(formFile);
MemoryStream memoryStream = new MemoryStream();
PdfStamper stamper = new PdfStamper(reader, memoryStream);
AcroFields fields = stamper.AcroFields;
// set form fields
foreach (KeyValuePair<string,> formField in formFields)
{
fields.SetField(formField.Key, formField.Value);
}
stamper.FormFlattening = true;
// release file
stamper.Close();
reader.Close();
return memoryStream;
}
将错误发送回父窗口
由于我们不希望错误显示在弹出窗口中,而是希望它们显示在父窗口中,然后关闭弹出窗口。错误会传递给 `TempData`,并调用 `ParentError` 操作。
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult HandleErrorForPopup(Exception ex, object inputData)
{
//TODO: log and/or email error
// close the popup browser window and display the error in the parent window
TempData["ErrorMessage"] = ex.Message;
return RedirectToAction("ParentError");
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult ParentError()
{
return View();
}
ParentError.aspx 视图使用 JavaScript 将错误传递回父窗口并关闭弹出窗口。如果您只调用 `window.close`,Internet Explorer 会提示您是否允许关闭页面。使用下面的代码,页面会在 Internet Explorer 和 Firefox 中无提示地关闭。
function HandleError() {
opener.window.location =
'/Public/Error.html?error=<%= TempData["ErrorMessage"].ToString() %>';
// close the form window without a prompt
window.open('', '_self');
window.close();
}
请注意,Error.html 页面位于Public文件夹中,而不是任何Views文件夹中。这是因为它旨在处理应用程序中发生的任何错误,包括登录错误,因此即使用户未授权,也会显示错误。
错误通过 JQuery 显示给用户
<script src="/Content/jquery-1.3.2.min.js" type="text/javascript"></script>
<script src="/Content/jquery.query.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$("div#lblErrorMessage").html($.query.get("error"))
});
</script>
试一试
按 Ctrl-F5 查看 My Form Letter 页面。输入一个姓名,提交表单,然后在新浏览器窗口中查看 PDF 弹出窗口。要测试错误处理,请取消注释 `MyFormLetter` 控制器操作中的 `throw new NullReferenceException("OH NOOOOOO")` 行,按 Ctrl-F5,然后按提交。
历史
- 2010年6月9日:初始发布