呈现 PDF 格式的 Visualforce 页面 文件

您可以使用 PDF 生成 Visualforce 页面的可下载、可打印的 PDF 文件 渲染服务。通过更改标签将页面转换为 PDF。

<apex:page>

<apex:page renderAs="pdf">

呈现的 Visualforce 页面 PDF文件要么显示在浏览器中,要么被下载,这取决于 浏览器的设置。具体行为取决于浏览器、版本、 和用户设置,并且不受 Visualforce 的控制。以下页面包含一些帐户详细信息,并以 PDF 格式呈现 文件。

<apex:page standardController="Account" renderAs="pdf">

<apex:stylesheet value="{!URLFOR($Resource.Styles,'pdf.css')}"/>

<h1>Welcome to Universal Samples!</h1>

<p>Thank you, <b><apex:outputText value=" {!Account.Name}"/></b>, for 
   becoming a new account with Universal Samples.</p>

<p>Your account details are:</p>

<table>
<tr><th>Account Name</th>
    <td><apex:outputText value="{!Account.Name}"/></td>
    </tr>
<tr><th>Account Rep</th>
    <td><apex:outputText value="{!Account.Owner.Name}"/></td>
    </tr>
<tr><th>Customer Since</th>
    <td><apex:outputText value="{0,date,long}">
        <apex:param value="{!Account.CreatedDate}"/>
        </apex:outputText></td>
    </tr>
</table>
    
</apex:page>

Visualforce 页面 呈现为 PDF 文件

将 Visualforce 页面渲染为 PDF 格式 顶点

您可以使用 Apex 中的方法将 Visualforce 页面呈现为 PDF 数据。然后使用 Apex 代码将该 PDF 数据转换为电子邮件附件、文档、 喋喋不休的帖子,等等。

PageReference.getContentAsPDF()下面的示例是一个简单的三元素窗体,用于选择帐户和报表 格式,然后将生成的报告发送到指定的电子邮件 地址。

<apex:page title="Account Summary" tabStyle="Account"
    controller="PdfEmailerController">

    <apex:pageMessages />

    <apex:form >
        <apex:pageBlock title="Account Summary">
    
        <p>Select a recently modified account to summarize.</p>
        <p/>
        
        <apex:pageBlockSection title="Report Format">
        
            <!-- Select account menu -->
            <apex:pageBlockSectionItem>
                <apex:outputLabel for="selectedAccount" value="Account"/> 
                <apex:selectList id="selectedAccount" value="{! selectedAccount }" 
                                 size="1">
                    <apex:selectOption /> <!-- blank by default -->
                    <apex:selectOptions value="{! recentAccounts }" />
                </apex:selectList>
            </apex:pageBlockSectionItem>

            <!-- Select report format menu -->
            <apex:pageBlockSectionItem >
                <apex:outputLabel for="selectedReport" value="Summary Format"/> 
                <apex:selectList id="selectedReport" value="{! selectedReport }" 
                                 size="1">
                    <apex:selectOptions value="{! reportFormats }" />
                </apex:selectList>
            </apex:pageBlockSectionItem>

            <!-- Email recipient input field -->
            <apex:pageBlockSectionItem >
                <apex:outputLabel for="recipientEmail" value="Send To"/> 
                <apex:inputText value="{! recipientEmail }" size="40"/>
            </apex:pageBlockSectionItem>

        </apex:pageBlockSection>
            
        <apex:pageBlockButtons location="bottom">
            <apex:commandButton action="{! sendReport }" value="Send Account Summary" />
        </apex:pageBlockButtons>
    
    </apex:pageBlock>
    </apex:form>

</apex:page>

此页面是一个简单的用户界面。当您从 Apex 生成 PDF 文件时,所有 该操作位于 Apex 代码中。在此示例中,该代码位于指定为页面的 控制器。

PdfEmailerController

public with sharing class PdfEmailerController {
    
    // Form fields
    public Id selectedAccount    { get; set; }  // Account selected on Visualforce page
    public String selectedReport { get; set; }  // Report selected
    public String recipientEmail { get; set; }  // Send to this email
    
    // Action method for the [Send Account Summary] button
    public PageReference sendReport() {

        // NOTE: Abbreviated error checking to keep the code sample short
        //       You, of course, would never do this little error checking
        if(String.isBlank(this.selectedAccount) || String.isBlank(this.recipientEmail)) {
            ApexPages.addMessage(new 
                ApexPages.Message(ApexPages.Severity.ERROR, 
               'Errors on the form. Please correct and resubmit.'));
            return null; // early out
        }
        
        // Get account name for email message strings
        Account account = [SELECT Name 
                           FROM Account 
                           WHERE Id = :this.selectedAccount 
                           LIMIT 1];
        if(null == account) {
            // Got a bogus ID from the form submission
            ApexPages.addMessage(new 
                ApexPages.Message(ApexPages.Severity.ERROR, 
               'Invalid account. Please correct and resubmit.'));
            return null; // early out
        }
        
        // Create email
        Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
        message.setToAddresses(new String[]{ this.recipientEmail });
        message.setSubject('Account summary for ' + account.Name);
        message.setHtmlBody('Here\'s a summary for the ' + account.Name + ' account.');
        
        // Create PDF
        PageReference reportPage = 
            (PageReference)this.reportPagesIndex.get(this.selectedReport);
        reportPage.getParameters().put('id', this.selectedAccount);
        Blob reportPdf;
        try {
            reportPdf = reportPage.getContentAsPDF();
        }
        catch (Exception e) {
            reportPdf = Blob.valueOf(e.getMessage());
        }
        
        // Attach PDF to email and send
        Messaging.EmailFileAttachment attachment = new Messaging.EmailFileAttachment();
        attachment.setContentType('application/pdf');
        attachment.setFileName('AccountSummary-' + account.Name + '.pdf');
        attachment.setInline(false);
        attachment.setBody(reportPdf);
        message.setFileAttachments(new Messaging.EmailFileAttachment[]{ attachment });
        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{ message });
        
        ApexPages.addMessage(new 
            ApexPages.Message(ApexPages.Severity.INFO,
           'Email sent with PDF attachment to ' + this.recipientEmail));

        return null; // Stay on same page, even on success
    }
    
    
    /***** Form Helpers *****/
    
    // Ten recently-touched accounts, for the Account selection menu
    public List<SelectOption> recentAccounts {
        get {
            if(null == recentAccounts){
                recentAccounts = new List<SelectOption>();
                for(Account acct : [SELECT Id,Name,LastModifiedDate 
                                    FROM Account 
                                    ORDER BY LastModifiedDate DESC 
                                    LIMIT 10]) {
                    recentAccounts.add(new SelectOption(acct.Id, acct.Name));
                }
            }
            return recentAccounts;
        }
        set;
    }
    
    // List of available reports, for the Summary Format selection menu
    public List<SelectOption> reportFormats {
        get {
            if(null == reportFormats) {
                reportFormats = new List<SelectOption>();
                for(Map <String,Object> report : reports) {
                    reportFormats.add(new SelectOption(
                        (String)report.get('name'), (String)report.get('label')));
                }
            }
            return reportFormats;
        }
        set;
    }

    
    /***** Private Helpers *****/
    
    // List of report templates to make available
    // These are just Visualforce pages you might print to PDF
    private Map<String,PageReference> reportPagesIndex;
    private List<Map<String,Object>> reports {
        get {
            if(null == reports) {
                reports = new List<Map<String,Object>>();
                // Add one report to the list of reports
                Map<String,Object> simpleReport = new Map<String,Object>();
                simpleReport.put('name',  'simple');
                simpleReport.put('label', 'Simple');
                simpleReport.put('page',   Page.ReportAccountSimple);
                reports.add(simpleReport);
                
                // Add your own, more complete list of PDF templates here

                // Index the page names for the reports
                this.reportPagesIndex = new Map<String,PageReference>();
                for(Map<String,Object> report : reports) {
                    this.reportPagesIndex.put(
                        (String)report.get('name'), (PageReference)report.get('page'));
                }
            }
            return reports;
        }
        set;
    }
}

这个 Apex 控制器在概念上可以分为四个部分。

  • 开头的三个公共属性捕获 表单上的三个输入元素。
  • 操作方法触发 单击“发送帐户摘要”按钮时。sendReport()
  • 两个公共帮助程序属性提供要在两个选择列表中使用的值 input 元素。
  • 末尾的私人帮助程序封装了可能的 PDF 报告列表 格式。您可以通过创建 Visualforce 页面来添加自己的报告,然后 在本节中为其添加一个条目。

当 action 方法触发时, 代码执行以下操作。

sendReport()

  • 它执行基本的错误检查,以确保表单字段具有 有用的值。注意对于必须 在与真人接触后幸存下来。在生产代码中执行更多 完成表单验证。
  • 接下来,它使用所选帐户的值来查找该帐户的名称 帐户。帐户名称用于添加到电子邮件的文本中。 此查找也是进一步验证表单值并确保 选择了真实账户。
  • 它使用该类来组合电子邮件,并设置“收件人”、“主题”和“正文”电子邮件 消息值。Messaging.SingleEmailMessage
  • 该代码为 选择报表格式,然后在其上设置页面请求参数。这 参数名为“id”,其值设置为所选帐户的 ID。这代表了一个特定的 请求在指定帐户的上下文中访问此页面。调用时, 引用 Visualforce 页面有权访问指定的帐户,并且页面将使用该帐户呈现 帐户的详细信息。PageReferencePageReferencegetContentAsPdf()
  • 最后,将 PDF 数据添加到附件中,并将附件添加到 之前创建的电子邮件。然后发送消息。

使用 时, 方法调用的返回类型为 ,其中 代表“二进制大对象”。在 Apex 中,数据类型表示非类型化二进制数据。只有当变量被添加到内容类型为 “application/pdf”,表示二进制数据成为 PDF 文件。PageReference.getContentAsPdf()BlobBlobreportPdfMessaging.EmailFileAttachment

此外,对 的调用是 包裹在块中。如果调用失败, 将希望的 PDF 数据替换为异常消息的版本 发短信。getContentAsPdf()try/catchcatchBlob

将 Visualforce 页面呈现为 PDF 数据在语义上被视为对各种外部服务的标注 原因。原因之一是渲染服务可能以与 外部服务可能会失败。例如,该页面引用了以下外部资源: 不可用。另一个例子是,当页面包含太多数据时,通常在 图像的形式 – 或渲染时间超过限制。因此,在将 Visualforce 页面渲染为 PDF 数据时,请始终将渲染调用包装在一个块中 顶点。getContentAsPdf()try/catch为了完整起见,下面是报告模板页面,该页面由 顶点 法典。

<apex:page showHeader="false" standardStylesheets="false"
    standardController="Account">
    
    <!-- 
    This page must be called with an Account ID in the request, e.g.:
    https://<salesforceInstance>/apex/ReportAccountSimple?id=001D000000JRBet
    -->

    <h1>Account Summary for {! Account.Name }</h1>
    
    <table>
        <tr><th>Phone</th>  <td><apex:outputText value="{! Account.Phone }"/></td></tr>
        <tr><th>Fax</th>    <td><apex:outputText value="{! Account.Fax }"/></td></tr>
        <tr><th>Website</th><td><apex:outputText value="{! Account.Website }"/></td></tr>
    </table>

    <p><apex:outputText value="{! Account.Description }"/></p>
        
</apex:page>

使用 Visualforce PDF 渲染时可用的字体

Visualforce PDF 渲染 支持一组有限的字体。要确保 PDF 输出按预期呈现,请使用 支持的字体名称。对于每种字体,列出的第一个名称是 推荐。

font-family

字体font-family
Arial Unicode MSArial Unicode MS
黑体无衬线无衬线对话
衬线次
邮差等宽邮差等宽DialogInput(对话输入)

注意

  • 这些规则适用于服务器端 PDF 呈现。在 Web 浏览器中查看页面 可以有不同的结果。
  • 使用此处未列出的值设置样式的文本使用“时间”。例如,如果您使用 单词“Helvetica”,它呈现为 Times,因为这不是 Helvetica 字体。我们建议使用“sans-serif”。
  • Arial Unicode MS 是唯一可用的多字节字体。这是唯一一种 为不使用 拉丁字符集。
  • Arial Unicode MS 不支持粗体或斜体。font-weight
  • 当页面呈现为 PDF 文件时,不支持 Web 字体。你可以使用 Visualforce 页面中的 Web 字体(当它们正常呈现时)。

测试字体呈现

您可以使用以下页面使用 Visualforce PDF 渲染测试字体渲染 发动机。

<apex:page showHeader="false" standardStylesheets="false" 
    controller="SaveToPDF" renderAs="{! renderAs }">

<apex:form rendered="{! renderAs != 'PDF' }" style="text-align: right; margin: 10px;">
    <div><apex:commandLink action="{! print }" value="Save to PDF"/></div>
    <hr/>
</apex:form>

<h1>PDF Fonts Test Page</h1>

<p>This text, which has no styles applied, is styled in the default font for the 
   Visualforce PDF rendering engine.</p>

<p>The fonts available when rendering a page as a PDF are as follows. The first 
listed <code>font-family</code> value for each typeface is the recommended choice.</p>

<table border="1" cellpadding="6">
<tr><th>Font Name</th><th>Style <code>font-family</code> Value to Use (Synonyms)</th></tr>
<tr><td><span style="font-family: Arial Unicode MS; font-size: 14pt; ">Arial 
    Unicode MS</span></td><td><ul>
   <li><span style="font-family: Arial Unicode MS; font-size: 14pt;">Arial Unicode MS</span></li>
    </ul></td></tr>
<tr><td><span style="font-family: Helvetica; font-size: 14pt;">Helvetica</span></td>
    <td><ul>
   <li><span style="font-family: sans-serif; font-size: 14pt;">sans-serif</span></li>
   <li><span style="font-family: SansSerif; font-size: 14pt;">SansSerif</span></li>
   <li><span style="font-family: Dialog; font-size: 14pt;">Dialog</span></li>
    </ul></td></tr>
<tr><td><span style="font-family: Times; font-size: 14pt;">Times</span></td><td><ul>
   <li><span style="font-family: serif; font-size: 14pt;">serif</span></li>
   <li><span style="font-family: Times; font-size: 14pt;">Times</span></li>
</ul></td></tr>
<tr><td><span style="font-family: Courier; font-size: 14pt;">Courier</span></td>
    <td><ul>
    <li><span style="font-family: monospace; font-size: 14pt;">monospace</span></li>
    <li><span style="font-family: Courier; font-size: 14pt;">Courier</span></li>
    <li><span style="font-family: Monospaced; font-size: 14pt;">Monospaced</span></li>
    <li><span style="font-family: DialogInput; font-size: 14pt;">DialogInput</span></li>
</ul></td></tr>
</table>

<p><strong>Notes:</strong>
<ul>
<li>These rules apply to server-side PDF rendering. You might see different results 
    when viewing this page in a web browser.</li>
<li>Text styled with any value besides those listed above receives the default font 
    style, Times. This means that, ironically, while Helvetica's synonyms render as 
    Helvetica, using "Helvetica" for the font-family style renders as Times. 
    We recommend using "sans-serif".</li>
<li>Arial Unicode MS is the only multibyte font available, providing support for the 
    extended character sets of languages that don't use the Latin character set.</li>
</ul>
</p>
 
</apex:page>

上一页使用以下控制器,该控制器提供了一个简单的“保存到 PDF” 功能。

public with sharing class SaveToPDF {

    // Determines whether page is rendered as a PDF or just displayed as HTML
    public String renderAs { get; set; }


    // Action method to "print" to PDF
    public PageReference print() {
        renderAs = 'PDF';
        return null;
    }

}

呈现为 PDF 时的组件行为

了解 Visualforce 如何 组件在转换为 PDF 时的行为对于创建呈现的页面至关重要 井。Visualforce PDF 渲染服务 呈现页面显式提供的静态 HTML 和基本 CSS。通常,不要使用 具有以下特点的组件:

  • 依靠 JavaScript 执行操作
  • 依赖 Salesforce 风格 床单
  • 使用样式表或图形等在页面本身或 静态资源

检查您的 Visualforce 页面 属于这些类别之一,右键单击页面上的任意位置并查看 HTML 源代码。如果 您会看到一个引用 JavaScript 的标记 (.js) 或引用 样式表 (.css),验证生成的 PDF 文件是否显示为 预期。

<script><link>

以 PDF 格式呈现时安全的组件

  • <apex:composition>(只要页面包含 PDF 安全组件)
  • <apex:dataList>
  • <apex:define>
  • <apex:facet>
  • <apex:include>(只要页面包含 PDF 安全组件)
  • <apex:insert>
  • <apex:image>
  • <apex:outputLabel>
  • <apex:outputLink>
  • <apex:outputPanel>
  • <apex:outputText>
  • <apex:page>
  • <apex:panelGrid>
  • <apex:panelGroup>
  • <apex:param>
  • <apex:repeat>
  • <apex:stylesheet>(只要 URL 不是 直接引用 Salesforce 风格 床单)
  • <apex:variable>

以 PDF 格式呈现时要谨慎使用的组件

  • <apex:attribute>
  • <apex:column>
  • <apex:component>
  • <apex:componentBody>
  • <apex:dataTable>

以 PDF 格式呈现时使用不安全的组件

  • <apex:actionFunction>
  • <apex:actionPoller>
  • <apex:actionRegion>
  • <apex:actionStatus>
  • <apex:actionSupport>
  • <apex:commandButton>
  • <apex:commandLink>
  • <apex:detail>
  • <apex:enhancedList>
  • <apex:flash>
  • <apex:form>
  • <apex:iframe>
  • <apex:includeScript>
  • <apex:inputCheckbox>
  • <apex:inputField>
  • <apex:inputFile>
  • <apex:inputHidden>
  • <apex:inputSecret>
  • <apex:inputText>
  • <apex:inputTextarea>
  • <apex:listViews>
  • <apex:message>
  • <apex:messages>
  • <apex:outputField>
  • <apex:pageBlock>
  • <apex:pageBlockButtons>
  • <apex:pageBlockSection>
  • <apex:pageBlockSectionItem>
  • <apex:pageBlockTable>
  • <apex:pageMessage>
  • <apex:pageMessages>
  • <apex:panelBar>
  • <apex:panelBarItem>
  • <apex:relatedList>
  • <apex:scontrol>
  • <apex:sectionHeader>
  • <apex:selectCheckboxes>
  • <apex:selectList>
  • <apex:selectOption>
  • <apex:selectOptions>
  • <apex:selectRadio>
  • <apex:tab>
  • <apex:tabPanel>
  • <apex:toolbar>
  • <apex:toolbarGroup>