zoukankan      html  css  js  c++  java
  • 【Itext】7步制作Itext5页眉页脚pdf实现第几页共几页

    itext5页眉页脚工具类,实现page x of y 完美兼容各种格式大小文档A4/B5/B3,兼容各种文档格式自动计算页脚XY轴坐标

     

    鉴于没人做的这么细致,自己就写了一个itext5页眉页脚工具类,实现第几页/共几页,方便各位刚进入itext的童鞋调用。2013年9月16日 14:51:01

    背景:网上流传的都是一些简单的demo,直接扔个A4文档就说实现了,其实很坑的,换个A4横版打印,那些代码就不行了,所以自己搞了这个出来。

    如果页面看着排版不好,请移步我的百度空间 :http://hi.baidu.com/ae6623/item/08abce3ce29359119dc65ecf

    工具类PdfReportM1HeaderFooter.java

    [java] view plaincopy
     
    1. <span style="font-family:Microsoft YaHei; font-size:12px">/** 
    2.  * Project Name:report 
    3.  * File Name:PdfReportM1HeaderFooter.java 
    4.  * Package Name:com.riambsoft.report.pdf 
    5.  * Date:2013-9-16上午08:59:00 
    6.  * Copyright (c) 2013, riambsoft All Rights Reserved. 
    7.  * 
    8.  */  
    9.     
    10. package com.riambsoft.report.pdf;  
    11.     
    12. import java.io.IOException;  
    13.     
    14. import com.itextpdf.text.Document;  
    15. import com.itextpdf.text.DocumentException;  
    16. import com.itextpdf.text.Element;  
    17. import com.itextpdf.text.Font;  
    18. import com.itextpdf.text.PageSize;  
    19. import com.itextpdf.text.Phrase;  
    20. import com.itextpdf.text.Rectangle;  
    21. import com.itextpdf.text.pdf.BaseFont;  
    22. import com.itextpdf.text.pdf.ColumnText;  
    23. import com.itextpdf.text.pdf.PdfContentByte;  
    24. import com.itextpdf.text.pdf.PdfPageEventHelper;  
    25. import com.itextpdf.text.pdf.PdfTemplate;  
    26. import com.itextpdf.text.pdf.PdfWriter;  
    27.     
    28. /** 
    29.  * ClassName:PdfReportM1HeaderFooter <br/> Function: TODO ADD FUNCTION. <br/> Reason: TODO ADD REASON. <br/> Date: 2013-9-13 上午08:59:00 <br/> 
    30.  * 
    31.  * @author 落雨 
    32.  * @version 394263788(QQ) 
    33.  * @since JDK 1.5 
    34.  * @see http://hi.baidu.com/ae6623 
    35.  */  
    36. public class PdfReportM1HeaderFooter extends PdfPageEventHelper {  
    37.     
    38.     /** 
    39.      * 页眉 
    40.      */  
    41.     public String header = "";  
    42.     
    43.     /** 
    44.      * 文档字体大小,页脚页眉最好和文本大小一致 
    45.      */  
    46.     public int presentFontSize = 12;  
    47.     
    48.     /** 
    49.      * 文档页面大小,最好前面传入,否则默认为A4纸张 
    50.      */  
    51.     public Rectangle pageSize = PageSize.A4;  
    52.     
    53.     // 模板  
    54.     public PdfTemplate total;  
    55.     
    56.     // 基础字体对象  
    57.     public BaseFont bf = null;  
    58.     
    59.     // 利用基础字体生成的字体对象,一般用于生成中文文字  
    60.     public Font fontDetail = null;  
    61.     
    62.     /** 
    63.      * 
    64.      * Creates a new instance of PdfReportM1HeaderFooter 无参构造方法. 
    65.      * 
    66.      */  
    67.     public PdfReportM1HeaderFooter() {  
    68.     
    69.     }  
    70.     
    71.     /** 
    72.      * 
    73.      * Creates a new instance of PdfReportM1HeaderFooter 构造方法. 
    74.      * 
    75.      * @param yeMei 
    76.      *            页眉字符串 
    77.      * @param presentFontSize 
    78.      *            数据体字体大小 
    79.      * @param pageSize 
    80.      *            页面文档大小,A4,A5,A6横转翻转等Rectangle对象 
    81.      */  
    82.     public PdfReportM1HeaderFooter(String yeMei, int presentFontSize, Rectangle pageSize) {  
    83.         this.header = yeMei;  
    84.         this.presentFontSize = presentFontSize;  
    85.         this.pageSize = pageSize;  
    86.     }  
    87.     
    88.     public void setHeader(String header) {  
    89.         this.header = header;  
    90.     }  
    91.     
    92.     public void setPresentFontSize(int presentFontSize) {  
    93.         this.presentFontSize = presentFontSize;  
    94.     }  
    95.     
    96.     /** 
    97.      * 
    98.      * TODO 文档打开时创建模板 
    99.      * 
    100.      * @see com.itextpdf.text.pdf.PdfPageEventHelper#onOpenDocument(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document) 
    101.      */  
    102.     public void onOpenDocument(PdfWriter writer, Document document) {  
    103.         total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高  
    104.     }  
    105.     
    106.     /** 
    107.      * 
    108.      * TODO 关闭每页的时候,写入页眉,写入'第几页共'这几个字。 
    109.      * 
    110.      * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document) 
    111.      */  
    112.     public void onEndPage(PdfWriter writer, Document document) {  
    113.     
    114.         try {  
    115.             if (bf == null) {  
    116.                 bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);  
    117.             }  
    118.             if (fontDetail == null) {  
    119.                 fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体  
    120.             }  
    121.         } catch (DocumentException e) {  
    122.             e.printStackTrace();  
    123.         } catch (IOException e) {  
    124.             e.printStackTrace();  
    125.         }  
    126.     
    127.         // 1.写入页眉  
    128.         ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, new Phrase(header, fontDetail), document.left(), document.top() + 20, 0);  
    129.            
    130.         // 2.写入前半部分的 第 X页/共  
    131.         int pageS = writer.getPageNumber();  
    132.         String foot1 = "第 " + pageS + " 页 /共";  
    133.         Phrase footer = new Phrase(foot1, fontDetail);  
    134.     
    135.         // 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len  
    136.         float len = bf.getWidthPoint(foot1, presentFontSize);  
    137.     
    138.         // 4.拿到当前的PdfContentByte  
    139.         PdfContentByte cb = writer.getDirectContent();  
    140.     
    141.         // 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F 再给偏移20F适合人类视觉感受,否则肉眼看上去就太偏左了 ,y轴就是底边界-20,否则就贴边重叠到数据体里了就不是页脚了;注意Y轴是从下往上累加的,最上方的Top值是大于Bottom好几百开外的。  
    142.         ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, footer, (document.rightMargin() + document.right() + document.leftMargin() - document.left() - len) / 2.0F + 20F, document.bottom() - 20, 0);  
    143.     
    144.         // 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F + len , y 轴和之前的保持一致,底边界-20  
    145.         cb.addTemplate(total, (document.rightMargin() + document.right() + document.leftMargin() - document.left()) / 2.0F + 20F, document.bottom() - 20); // 调节模版显示的位置  
    146.     
    147.     }  
    148.     
    149.     /** 
    150.      * 
    151.      * TODO 关闭文档时,替换模板,完成整个页眉页脚组件 
    152.      * 
    153.      * @see com.itextpdf.text.pdf.PdfPageEventHelper#onCloseDocument(com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document) 
    154.      */  
    155.     public void onCloseDocument(PdfWriter writer, Document document) {  
    156.         // 7.最后一步了,就是关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。  
    157.         total.beginText();  
    158.         total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色  
    159.         String foot2 = " " + (writer.getPageNumber() - 1) + " 页";  
    160.         total.showText(foot2);// 模版显示的内容  
    161.         total.endText();  
    162.         total.closePath();  
    163.     }  
    164. }</span>  

    如何调用?

    这样调用即可,下面的代码就是 第几页/共几页的实现方式!推荐大家使用,直接扔到自己的工程,在创建pdf的时候,直接把此event set进去即可。

    [java] view plaincopy
     
    1. <span style="font-family:Microsoft YaHei; font-size:12px">/** 
    2. * Project Name:report 
    3. * File Name:PDFBuilder.java 
    4. * Package Name:com.riambsoft.report.itext 
    5. * Date:2013-9-13下午03:35:53 
    6. * Copyright (c) 2013, riambsoft All Rights Reserved. 
    7. */  
    8.     
    9. package com.riambsoft.report.itext;  
    10.     
    11. import java.io.FileOutputStream;  
    12. import java.io.IOException;  
    13.     
    14. import com.itextpdf.text.Document;  
    15. import com.itextpdf.text.DocumentException;  
    16. import com.itextpdf.text.PageSize;  
    17. import com.itextpdf.text.Rectangle;  
    18. import com.itextpdf.text.pdf.ColumnText;  
    19. import com.itextpdf.text.pdf.PdfContentByte;  
    20. import com.itextpdf.text.pdf.PdfWriter;  
    21. import com.riambsoft.report.pdf.PdfReportM1HeaderFooter;  
    22.     
    23. /** 
    24. * ClassName:PDFBuilder <br/> 
    25. * Function: TODO ADD FUNCTION. <br/> 
    26. * Reason:   TODO ADD REASON. <br/> 
    27. * Date: 2013-9-13 下午03:35:53 <br/> 
    28. * @author Administrator 
    29. * @version 
    30. * @since JDK 1.5 
    31. * @see   
    32. */  
    33. public class PDFBuilder {  
    34. private int pageHeight;  
    35. private int pageWidth;  
    36. private PDFBuilder(){  
    37. }  
    38. public static PDFBuilder getInstance(){  
    39. return new PDFBuilder();  
    40. }  
    41. public void generatePDF()throws Exception {  
    42. Document document = new Document(new Rectangle(pageWidth, pageHeight));  
    43. PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(""));  
    44. this.setFooter(writer);  
    45. writer.setFullCompression();  
    46. writer.setPdfVersion(PdfWriter.VERSION_1_4);  
    47. document.open();  
    48. // Set pdf version to 1.4  
    49. PdfContentByte cb = writer.getDirectContent();  
    50. ColumnText ct=new ColumnText(cb);  
    51. for(int i=0;i<10;i++){  
    52. document.newPage();  
    53. //如果不设置 空白页无法单独显示  
    54. writer.setPageEmpty(false);  
    55. }  
    56. document.close();  
    57. }  
    58.     
    59. private void setFooter(PdfWriter writer) throws DocumentException, IOException {  
    60. //HeaderFooter headerFooter = new HeaderFooter(this);  
    61. //更改事件,瞬间变身 第几页/共几页 模式。  
    62. PdfReportM1HeaderFooter headerFooter = new PdfReportM1HeaderFooter();//就是上面那个类  
    63. writer.setBoxSize("art",PageSize.A4);  
    64. writer.setPageEvent(headerFooter);  
    65. }  
    66. public int getPageHeight() {  
    67. return pageHeight;  
    68. }  
    69. public void setPageHeight(int pageHeight) {  
    70. this.pageHeight = pageHeight;  
    71. }  
    72. public int getPageWidth() {  
    73. return pageWidth;  
    74. }  
    75. public void setPageWidth(int pageWidth) {  
    76. this.pageWidth = pageWidth;  
    77. }  
    78. public static void main(String[] args) throws Exception {  
    79. PDFBuilder builder=new PDFBuilder();  
    80. builder.setPageHeight(400);  
    81. builder.setPageWidth(600);  
    82. builder.generatePDF();  
    83. }  
    84. }</span>  

    核心算法:就是计算文档的长宽,算出中点,记得中文字体是需要占用宽度的,所以也要计算进去,其次没什么重点,研究一下中点的计算吧,初中知识。

    paga x 这种好做,page x of y 按照官方 itext in action 2这本书上面说的那种办法,无法准确计算各种文档的x轴和y轴坐标。

    我按照书上所写的实现方式如下,不推荐使用,因为只适合于A4纸张。

    PdfReportM1HeaderFooter2.java

    [java] view plaincopy
     
    1. <span style="font-family:Microsoft YaHei; font-size:12px">/** 
    2. * Project Name:report 
    3. * File Name:PdfReportM1HeaderFooter.java 
    4. * Package Name:com.riambsoft.report.pdf 
    5. * Date:2013-9-13上午08:59:00 
    6. * Copyright (c) 2013, riambsoft All Rights Reserved. 
    7. */  
    8.   
    9. package com.riambsoft.report.pdf;  
    10.   
    11. import java.io.IOException;  
    12.   
    13. import com.itextpdf.text.Document;  
    14. import com.itextpdf.text.DocumentException;  
    15. import com.itextpdf.text.Element;  
    16. import com.itextpdf.text.ExceptionConverter;  
    17. import com.itextpdf.text.Font;  
    18. import com.itextpdf.text.Image;  
    19. import com.itextpdf.text.Phrase;  
    20. import com.itextpdf.text.Rectangle;  
    21. import com.itextpdf.text.pdf.BaseFont;  
    22. import com.itextpdf.text.pdf.ColumnText;  
    23. import com.itextpdf.text.pdf.PdfPCell;  
    24. import com.itextpdf.text.pdf.PdfPTable;  
    25. import com.itextpdf.text.pdf.PdfPageEventHelper;  
    26. import com.itextpdf.text.pdf.PdfTemplate;  
    27. import com.itextpdf.text.pdf.PdfWriter;  
    28.   
    29. /** 
    30. * ClassName:PdfReportM1HeaderFooter2 <br/> Function: TODO ADD FUNCTION. <br/> Reason: TODO ADD REASON. <br/> Date: 2013-9-13 上午08:59:00 <br/> 
    31. *  
    32. * @author Administrator 
    33. * @version  
    34. * @since JDK 1.5 
    35. * @see  
    36. */  
    37. public class PdfReportM1HeaderFooter2 extends PdfPageEventHelper {  
    38.   
    39. String header;  
    40. int presentFontSize = 12;  
    41. PdfTemplate total;  
    42. BaseFont bf = null;  
    43. Font fontDetail = null;  
    44.   
    45. public void setHeader(String header) {  
    46. this.header = header;  
    47. }  
    48.   
    49. public void onOpenDocument(PdfWriter writer, Document document) {  
    50. total = writer.getDirectContent().createTemplate(30, 16);  
    51. }  
    52.   
    53. public void onEndPage(PdfWriter writer, Document document) {  
    54.   
    55. Rectangle pageSize = writer.getBoxSize("art");  
    56.   
    57. try {  
    58. if (bf == null) {  
    59. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);  
    60. }  
    61. if (fontDetail == null) {  
    62. fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体  
    63. }  
    64. catch (DocumentException e) {  
    65. e.printStackTrace();  
    66. catch (IOException e) {  
    67. e.printStackTrace();  
    68. }  
    69. int pageN = writer.getPageNumber();  
    70. String text = "第 " + pageN + "页/共 ";  
    71.   
    72. // 页眉  
    73. ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, new Phrase("我是页眉,土豪我们做朋友吧",fontDetail), document.left(), document.top() + 20, 0);  
    74.   
    75. PdfPTable table = new PdfPTable(2);  
    76.   
    77. try {  
    78. table.setWidths(new int[] { 1, 1 });  
    79. table.setWidthPercentage(100F);// 占据百分百宽度  
    80. table.setTotalWidth(pageSize.getRight() - pageSize.getLeft() - 100);  
    81.   
    82. PdfPCell cell1 = new PdfPCell(new Phrase(text, fontDetail));  
    83. PdfPCell cell2 = new PdfPCell(Image.getInstance(total));  
    84.   
    85. cell1.setHorizontalAlignment(Element.ALIGN_RIGHT);  
    86. cell1.setBorder(Rectangle.NO_BORDER);  
    87. cell2.setHorizontalAlignment(Element.ALIGN_LEFT);  
    88. cell2.setBorder(Rectangle.NO_BORDER);  
    89.   
    90. table.addCell(cell1);  
    91. table.addCell(cell2);  
    92. table.writeSelectedRows(0, -1, document.left(), document.bottom(), writer.getDirectContent());  
    93. catch (DocumentException de) {  
    94. throw new ExceptionConverter(de);  
    95. }  
    96.   
    97. }  
    98.   
    99. public void onCloseDocument(PdfWriter writer, Document document) {  
    100.   
    101. try {  
    102. if (bf == null) {  
    103. bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);  
    104. }  
    105. if (fontDetail == null) {  
    106. fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体  
    107. }  
    108. catch (DocumentException e) {  
    109. e.printStackTrace();  
    110. catch (IOException e) {  
    111. e.printStackTrace();  
    112. }  
    113.   
    114. ColumnText.showTextAligned(total, Element.ALIGN_LEFT, new Phrase(String.format("%d页", writer.getPageNumber() - 1), fontDetail), 2, 2, 0);  
    115. }  
    116. }</span>  

    这种只能自己去计算Y轴坐标,很容易不在一行。所以不如我的第一种方便。具体就看你使用了。

  • 相关阅读:
    google搜索引擎使用方法
    通过Ajax和SpringBoot交互的示例
    利用html sessionStorge 来保存局部页面在刷新后回显,保留
    JS页面刷新保持数据不丢失
    Firefox浏览器中,input输入框输入的内容在刷新网页后为何还在?
    关于form/input 的autocomplete="off"属性
    Java对日期Date类进行加减运算,年份加减,月份加减
    select标签设置只读的方法(下拉框不可选但可传值)
    用Thymeleaf在前台下拉列表取值
    jsp页面动态展示list-使用<select>和<c:forEach>标签
  • 原文地址:https://www.cnblogs.com/telwanggs/p/4921189.html
Copyright © 2011-2022 走看看