使用Coldfusion和iText通过onEndPage向PDF添加页脚/页眉

时间:2018-05-04 09:36:06

标签: coldfusion itext pdf-generation

我正在使用ColdFusion和iText生成PDF文档,我希望能够在iText决定进行分页时“自动”向PDF添加页眉和页脚。 我已经看到了如何在Java中执行此操作的示例,以下是执行此操作的基本方法:

public class MyHeaderFooterPageEvent extends PdfPageEventHelper {
    public void onEndPage(PdfWriter writer, Document document) {
        //add your content here
    }
} 

然后,在开始撰写PDF文档之前,您将“注册”您的活动,如:

    MyHeaderFooterPageEvent event = new HeaderFooterPageEvent();
    writer.setPageEvent(event);

(至少据我所知。)

我已成功设法将类PdfPageEventHelper加载到ColdFusion中,所以我知道它在那里:

<cfset local.PdfPageEventHelper=CreateObject("java","com.lowagie.text.pdf.PdfPageEventHelper")>

当我转储local.PdfPageEventHelper时,我得到:

enter image description here

那么如何在调用onEndPage时告诉ColdFusion该怎么做,以及如何注册该事件以便调用它?

我在Linux服务器上使用Coldfusion 11。

1 个答案:

答案 0 :(得分:1)

此解决方案主要基于this old blog post at cfSearching.blogspot.se

虽然该解决方案使用 javaloader动态代理库,但此解决方案使用较新的(?)函数CreateDynamicProxy(我认为可以从ColdFusion 10获得), Ageax (非常感谢!)让我意识到了。

已在Linux服务器上的 ColdFusion 11 中成功测试。

自己尝试一下:

  1. 将以下内容复制并粘贴到一个cfm文件和一个cfc文件中。虽然您可以根据需要为cfm文件命名,但cfc文件必须命名为 PdfPageEventHandler.cfc 才能使此代码正常工作。
  2. 将文件放在ColdFusion服务器上的www根目录中的同一文件夹中。
  3. 通过浏览cfm文件运行代码。
  4. 浏览器应显示包含正文文本和页脚的3页PDF。
  5. cfm文件的内容:

    <!---call function--->
    <cfset _createPdf()>
    <!---function for creating pdf with footer that is created via an event handler in onEndPage--->
    <cffunction name="_createPdf" output="no" returntype="void">
        <cfargument name="pdfFile" type="string" default="document.pdf" hint="the file name to write to disc">
        <cfargument name="writeToBrowser" type="boolean" default="true" hint="will open the pdf document in the browser and delete the file when done">
        <cfscript>
            //set filePath for document
            local.filePath = ExpandPath('.')&"/"&arguments.pdfFile;
            //get BaseFont
            local.BaseFont = CreateObject("java", "com.lowagie.text.pdf.BaseFont");
            //get CMYK color
            local.CMYKColor = CreateObject("java", "com.lowagie.text.pdf.CMYKColor");
            //create color
            local.color = local.CMYKColor.init(JavaCast("int",0),JavaCast("int",0),JavaCast("int",0),JavaCast("int",256));
            //create font
            local.font = local.BaseFont.createFont(local.BaseFont.COURIER, local.BaseFont.CP1252, true);
            //compose custom config to make accessable in PdfPageEventHandler.cfc
            local.config = {myCustomFooter = {text = "Page number", color = local.color, font = local.font, size = 20}};
            //init the event handler (make sure the PdfPageEventHandler.cfc is present in the same folder as this template)
            local.eventHandler = CreateObject("component", "PdfPageEventHandler").init(config = local.config); 
            //we can pass in an array of strings which name all the interfaces we want out dynamic proxy to implement
            local.interfaces = ["com.lowagie.text.pdf.PdfPageEvent"];
            //create a dynamic proxy that we will pass to the iText writer
            local.eventHandlerProxy = CreateDynamicProxy(local.eventHandler, local.interfaces);
            //init success flag
            local.success = true;
            try {
                //init document
                local.document = CreateObject("java", "com.lowagie.text.Document").init();
                //init outstream
                local.outputStream = CreateObject("java", "java.io.FileOutputStream").init(local.filePath);
                //init writer
                local.writer = CreateObject("java", "com.lowagie.text.pdf.PdfWriter").getInstance(local.document, local.outputStream);
                //register the PROXY as the page event handler
                local.writer.setPageEvent(local.eventHandlerProxy);
                //open document
                local.document.open();
                //init paragraph
                local.paragraph = CreateObject("java", "com.lowagie.text.Paragraph");
                //output some pages with a simple text message. NOTE that our eventHandler will take care of adding footers on every page - that's the whole point with this example by the way :)
                for (local.i = 1; local.i lte 3; local.i = local.i + 1) {
                    //add paragraph with text
                    local.document.add(local.paragraph.init("This page should have a footer with a page number on it!"));
                    //trigger new page
                    local.document.newPage();
                }
            } catch (any e) {
                //an error occured
                WriteOutput("Error: " & e.message);
                //set success flag to false
                local.success = false;
            }
            if (StructKeyExists(local, "document")) {
                //close document
                local.document.close();
            }
            if (StructKeyExists(local, "outStream")) {
                //close outStream
                local.outputStream.close();
            }
            if (local.success && arguments.writeToBrowser) {
                _openPdf(filePath=local.filePath);
            }
        </cfscript>
    </cffunction>
    <!---function for opening pdf in browser--->
    <cffunction name="_openPdf" output="no" returntype="void">
        <cfargument name="filePath" type="string" required="yes">
        <cfcontent type="application/pdf" file="#arguments.filePath#" deletefile="yes">
    </cffunction>
    

    cfc文件的内容,应命名为 PdfPageEventHandler.cfc

    <cfcomponent output="false" hint="iText Event handler used to add headers, footers, etc.">
    <!---1. INIT FUNCTION--->
        <cffunction name="init" access="public" returntype="PdfPageEventHandler" output="false">
            <!---come up with your own arguments that you want to have access to in onEndPage etc--->
            <cfargument name="config" type="any" required="true" hint="custom config" />
            <!---make sure the config is accessable by other functions--->
            <cfset variables.config = arguments.config>
            <cfreturn this />
        </cffunction>
    <!---2. ON END PAGE - the function that is in focus in this example--->
        <cffunction name="onEndPage" access="public" returntype="void" output="true" hint="Called when a page is finished, just before being written to the document.">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <!---edit below to make your own header / footer--->
            <cfscript>
                local.cb = arguments.writer.getDirectContent();
                local.cb.saveState();
                local.cb.beginText();
                local.cb.setColorFill(variables.config.myCustomFooter.color);
                local.cb.setFontAndSize(variables.config.myCustomFooter.font, variables.config.myCustomFooter.size);
                local.cb.setTextMatrix(arguments.document.left(), arguments.document.bottom() - 10);
                local.text = "#variables.config.myCustomFooter.text# #arguments.writer.getPageNumber()#";
                local.cb.showText(local.text);
                local.cb.endText();
                local.cb.restoreState();
            </cfscript>
        </cffunction>
    <!---3. OTHER FUNCTIONS THAT MUST EXIST (at least in this example)--->
        <cffunction name="onOpenDocument" access="public" returntype="void" output="false" hint="Called when the document is opened.">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <!---To be implemented: Code called when the document is opened--->
        </cffunction>
        <cffunction name="onCloseDocument" access="public" returntype="void" output="false" hint="Called when the document is closed">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <!---To be implemented: Code called when the document is closed--->
        </cffunction>
        <cffunction name="onStartPage" access="public" returntype="void" output="false" hint="Called when a page is initialized.">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <!---To be implemented: Code called when a page is initialized--->
        </cffunction>
        <cffunction name="onParagraph" access="public" returntype="void" output="false" hint="Called when a Paragraph is written">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
            <!---To be implemented: Code called when paragraph is written --->
        </cffunction>
        <cffunction name="onParagraphEnd" access="public" returntype="void" output="false" hint="Called when a Paragraph is written">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
            <!---To be implemented: Code called on end of paragraph is written--->
        </cffunction>
    <!---4. FUNCTIONS THAT ONLY NEEDS TO EXIST IF YOU DO SOMETHING THAT TRIGGERS THEM
        <cffunction name="OnChapter" access="public" returntype="void" output="false" hint="Called when a Chapter is written">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
            <cfargument name="title" type="any" required="true" hint="Title of the chapter. Instance of com.lowagie.text.Paragraph" />
            <!---To be implemented: Code called when a Chapter is written--->
        </cffunction>
        <cffunction name="onChapterEnd" access="public" returntype="void" output="false" hint="Called when the end of a Chapter is reached">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <cfargument name="position" type="numeric" required="true" hint="The position of the end of the chapter. Value is a java float" />
            <!---To be implemented: Code called when the end of a Chapter is reached--->
        </cffunction>
        <cffunction name="onGenericTag" access="public" returntype="void" output="false" hint="Called when a Chunk with a generic tag is written">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <cfargument name="rect" type="any" required="true" hint="The Rectangle containing the Chunk. Instance of com.lowagie.text.Rectangle" />
            <cfargument name="text" type="string" required="true" hint="The text of the tag" />
            <!---To be implemented: Code called when a Chunk with a generic tag is written--->
        </cffunction>
        <cffunction name="onSection" access="public" returntype="void" output="false" hint="Called when a Section is written">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
            <cfargument name="depth" type="numeric" required="true" hint="The number depth of the Section. Value is a java int" />
            <cfargument name="title" type="any" required="true" hint="Title of the section. Instance of com.lowagie.text.Paragraph" />
            <!---To be implemented: Code called when a Section is written--->
        </cffunction>
        <cffunction name="onSectionEnd" access="public" returntype="void" output="false" hint="Called when the end of a Section is reached.">
            <cfargument name="writer" type="any" required="true" hint="Writer for the target pdf. Instance of com.lowagie.text.pdf.PdfWriter" />
            <cfargument name="document" type="any" required="true" hint="Document for target pdf. Instance of com.lowagie.text.Document" />
            <cfargument name="paragraphPosition" type="numeric" required="true" hint="The position the chapter will be written to. Value is a java float" />
            <cfargument name="depth" type="numeric" required="true" hint="The number depth of the Section. Value is a java int" />
            <cfargument name="title" type="numeric" required="true" hint="Title of the section. Instance of com.lowagie.text.Paragraph" />
            <!---To be implemented: Code called when the end of a Section is reached--->
        </cffunction>
        --->
    </cfcomponent>
    

    <强>更新<!/强>

    这里有相同的cfc,但在纯cfscript中,对你而言更喜欢:

    <cfscript>
        component output="false"  hint="iText Event handler used to add headers, footers, etc." {
            property name="config" type="struct";
            //1. INIT FUNCTION
            public PdfPageEventHandler function init(required any config) {
                //make sure the config is accessable by other functions
                variables.config = arguments.config;
                return this;
            }
        //2. ON END PAGE - the function that is in focus in this example
            public void function onEndPage(required any writer, required any document) {
                //Called when a page is finished, just before being written to the document
                //edit below to make your own header / footer
                local.cb = arguments.writer.getDirectContent();
                local.cb.saveState();
                local.cb.beginText();
                local.cb.setColorFill(variables.config.myCustomFooter.color);
                local.cb.setFontAndSize(variables.config.myCustomFooter.font, variables.config.myCustomFooter.size);
                local.cb.setTextMatrix(arguments.document.left(), arguments.document.bottom() - 10);
                local.text = "#variables.config.myCustomFooter.text# #arguments.writer.getPageNumber()#";
                local.cb.showText(local.text);
                local.cb.endText();
                local.cb.restoreState();
            }
        //3. OTHER FUNCTIONS THAT MUST EXIST (at least in this example)
            public void function onOpenDocument(required any writer, required any document) {
                //Called when the document is opened
            }
            public void function onCloseDocument(required any writer, required any document) {
                //Called when the document is closed
            }
            public void function onStartPage(required any writer, required any document) {
                //Called when a page is initialized
            }
            public void function onParagraph(required any writer, required any document, required numeric paragraphPosition) {
                //Called when a Paragraph is written
                //paragraphPosition - The position the chapter will be written to. Value is a java float
            }
            public void function onParagraphEnd(required any writer, required any document, required numeric paragraphPosition) {
                //Called when a Paragraph is written
                //paragraphPosition - The position the chapter will be written to. Value is a java float
            }
        //4. FUNCTIONS THAT ONLY NEEDS TO EXIST IF YOU DO SOMETHING THAT TRIGGERS THEM
            public void function OnChapter(required any writer, required any document, required numeric paragraphPosition, required any title) {
                //Called when a Chapter is written
                //paragraphPosition - The position the chapter will be written to. Value is a java float
                //title - Title of the chapter. Instance of com.lowagie.text.Paragraph
            }
            public void function onChapterEnd(required any writer, required any document, required numeric position) {
                //Called when the end of a Chapter is reached
                //position - The position of the end of the chapter. Value is a java float
            }
            public void function onGenericTag(required any writer, required any document, required any rect, required string text) {
                //Called when a Chunk with a generic tag is written
                //rect - The Rectangle containing the Chunk. Instance of com.lowagie.text.Rectangle
                //text - The text of the tag
            }
            public void function onSection(required any writer, required any document, required numeric paragraphPosition, required numeric depth, required any title) {
                //Called when a Section is written
                //paragraphPosition - The position the section will be written to. Value is a java float
                //depth - The number depth of the Section. Value is a java int
                //title - Title of the section. Instance of com.lowagie.text.Paragraph
            }
            public void function onSectionEnd(required any writer, required any document, required numeric paragraphPosition, required numeric depth, required any title) {
                //Called when the end of a Section is reached
                //paragraphPosition - The position the section will be written to. Value is a java float
                //depth - The number depth of the Section. Value is a java int
                //title - Title of the section. Instance of com.lowagie.text.Paragraph
            }
        }
    </cfscript>