Package cn.guoyukun.pdm2pdf

Source Code of cn.guoyukun.pdm2pdf.PdfGenerator

package cn.guoyukun.pdm2pdf;

import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.guoyukun.pdm2pdf.model.Biz;
import cn.guoyukun.pdm2pdf.model.ColInfo;
import cn.guoyukun.pdm2pdf.model.Domain;
import cn.guoyukun.pdm2pdf.model.TableInfo;
import cn.guoyukun.pdm2pdf.model.TableTree;
import cn.guoyukun.pdm2pdf.pdf.Fonts;
import cn.guoyukun.pdm2pdf.pdf.PdfReportM1HeaderFooter;

import com.itextpdf.text.Anchor;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chapter;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Section;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPHeaderCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.LineSeparator;

public class PdfGenerator {
  private static final String AUTHOR = "中科软科技股份有限公司";
  // 日志对象
  private static final Logger LOG = LoggerFactory
      .getLogger(PdfGenerator.class);
  //Document对象
  private Document document;
  //pdf输出流
  private PdfWriter writer;
  // 章节索引
  private int chapterIndex = 1;
  // 表数据
  private Map<String, TableInfo> tables;
  // 文档标题,封面上的
  private String pdfTitle;
  // 版本
  private String version;
  // 生成日期
  private String generateDate;
  //获得版本号
  public String getVersion() {
    return version;
  }
   
  //设置版本号
  public PdfGenerator setVersion(String version) {
    this.version = version;
    return this;
  }

  //获得pdf文档的标题
  public String getPdfTitle() {
    return pdfTitle;
  }

  //设置文档的标题
  public PdfGenerator setPdfTitle(String pdfTitle) {
    this.pdfTitle = pdfTitle;
    return this;
  }
 
  //获得pdf文档的制作日期
  public String getGenerateDate() {
    return generateDate;
  }

  //设置pdf文档的制作日期
  public PdfGenerator setGenerateDate(String generateDate) {
    this.generateDate = generateDate;
    return this;
  }

  /**
   * 设置页眉页脚
   * @param writer
   * @param left
   * @param right
   * @throws DocumentException
   * @throws IOException
   */
  private void setHeaderFooter(PdfWriter writer, String left, String right)
      throws DocumentException, IOException {
    // 第几页/共几页 模式。
    PdfReportM1HeaderFooter headerFooter = new PdfReportM1HeaderFooter();// 就是上面那个类
    headerFooter.setHeader(left);
    headerFooter.setHeaderRight(right);
    // 跳过封皮
    headerFooter.setPageOffset(-1);
    headerFooter.setPresentFontSize(10);
    writer.setBoxSize("art", PageSize.A4);
    writer.setPageEvent(headerFooter);
  }

  //生成新的pdf文档
  public PdfGenerator newPdf(String pdf)
      throws DocumentException, MalformedURLException, IOException {
    // 横版A4
    document = new Document(PageSize.A4.rotate(), 50, 50, 50, 50);
    //
    writer = PdfWriter.getInstance(document, new FileOutputStream(pdf));
    // //1,设置此PDF文件的权限,只有写上的是答应的。这里只答应打印,读取和保存,不答应修改等。
    // int intPermissions =
    // PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_SCREENREADERS;
    // //2,若要实现其他权限如修改等 则需要写进密码,这里是设置密码加密标准或加密类型。
    // int intEncryptionType = PdfEncryption.AES_128;
    // //3,要是用这个方法需要引进一个jar包(bcprov-jdk15-137.jar)。第一个参数:
    //     打开时需要的密码;第二个参数:实用其他其他权限时使用的密码;第三个参数:可使用的权限;第四个参数:密码类型
    // writer.setEncryption(null, "hello".getBytes(),
    // intPermissions,intEncryptionType);

    writer.setPdfVersion(PdfWriter.VERSION_1_7);
    writer.setFullCompression();
    // 保证图片不会漂移
    writer.setStrictImageSequence(true);
    // TOC
    writer.setViewerPreferences(PdfWriter.PageModeUseOutlines);
    // 页眉页脚
    //通州版
    //setHeaderFooter(writer, AUTHOR,"通州版  "+ version);
    //云南标准版
    setHeaderFooter(writer, AUTHOR, version);
    // TODO: 设置行间距,没试出效果
    writer.setInitialLeading(-100f);

    document.addTitle(this.pdfTitle + " " +this.version);
    document.addAuthor(AUTHOR);
    document.addCreationDate();
    document.addSubject(this.pdfTitle);
    document.addCreator(AUTHOR);
    writer.setTagged();
    return this;
  }

  public PdfGenerator openPdf() {
    document.open();
    return this;
  }

  public PdfGenerator addOutline() {
//    PdfStructureTreeRoot root = writer.getStructureTreeRoot();
//    root.mapRole(new PdfName("chapter"), PdfName.SECT);
//    root.mapRole(new PdfName("title"), PdfName.H);
//    root.mapRole(new PdfName("para"), PdfName.P);
//    PdfStructureElement top = new PdfStructureElement(root, new PdfName(
//        "chapter"));
//    //SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
//    List<PdfStructureElement> elements = new ArrayList<PdfStructureElement>();
//   
//    elements.add(new PdfStructureElement(top, new PdfName("title")));
//   
   
//   
//    parser.parse(new InputSource(new FileInputStream(RESOURCE)),
//        new StructureParser(top, elements));
//    parser.parse(new InputSource(new FileInputStream(RESOURCE)),
//        new ContentParser(document, writer, elements));
//    // PdfOutline root = writer.getRootOutline();
    //
    // PdfOutline link;
    // String title;
    // for(int i=0;i<100;i++){
    // PdfOutline movieBookmark = new PdfOutline(root,
    // new PdfDestination(
    // PdfDestination.FITH, writer.getVerticalPosition(true)),
    // "title-"+i, true);
    // movieBookmark.setStyle(Font.BOLD);
    // }
    // // for (Movie movie : movies) {
    // // title = movie.getMovieTitle();
    // // if ("3-Iron".equals(title))
    // // title = "\ube48\uc9d1";
    // // movieBookmark = new PdfOutline(root,
    // // new PdfDestination(
    // // PdfDestination.FITH, writer.getVerticalPosition(true)),
    // // title, true);
    // // movieBookmark.setStyle(Font.BOLD);
    // // link = new PdfOutline(movieBookmark,
    // // new PdfAction(String.format(RESOURCE, movie.getImdb())),
    // // "link to IMDB");
    // // link.setColor(BaseColor.BLUE);
    // // new PdfOutline(movieBookmark,
    // // PdfAction.javaScript(
    // // String.format(INFO, movie.getYear(), movie.getDuration()),
    // writer),
    // // "instant info");
    // // document.add(new Paragraph(movie.getMovieTitle()));
    // // document.add(PojoToElementFactory.getDirectorList(movie));
    // // document.add(PojoToElementFactory.getCountryList(movie));
    // // }
    return this;
  }

  //关闭资源
  public void closePdf() {
    document.close();
    writer.close();
  }

  /**
   * 封皮
   *
   * @throws DocumentException
   */
  public PdfGenerator addCover() throws DocumentException {

    //封皮上的标题
    Paragraph title = new Paragraph(this.pdfTitle, Fonts.FONT_COVER_TITLE);
    title.setAlignment(Paragraph.ALIGN_CENTER);
    title.setSpacingBefore(100);
    document.add(title);

    //封皮上的版本
    Paragraph pVersion = new Paragraph("版本:" + version, Fonts.FONT_TITILE1);
    pVersion.setAlignment(Paragraph.ALIGN_CENTER);
    pVersion.setSpacingBefore(90f);
    pVersion.setSpacingAfter(10f);
    document.add(pVersion);

    //封皮上的创建日期
    Paragraph pDate = new Paragraph( generateDate, Fonts.FONT_TITILE1);
    pDate.setAlignment(Paragraph.ALIGN_CENTER);
    document.add(pDate);
   
   
    // 封皮上的作者 “中科软科技股份有限公司”
    Anchor anchorTarget = new Anchor(AUTHOR, Fonts.FONT_COVER_SUBTITLE);
    anchorTarget.setName("BackToTop");

    Paragraph paragraph1 = new Paragraph();

    paragraph1.setSpacingBefore(220);

    paragraph1.add(anchorTarget);
    paragraph1.setAlignment(Paragraph.ALIGN_CENTER);

    document.add(paragraph1);

    return this;
  }

  /**
   * 构建一个业务的内容
   *
   * @param cParentChapter
   * @throws DocumentException
   * @throws IOException
   * @throws MalformedURLException
   */
  public void addBiz(Section parentSection, Biz biz)
      throws DocumentException, MalformedURLException, IOException {

    String bizTitle = biz.getName();
    // 业务标题
    Paragraph pBiz = new Paragraph(bizTitle, Fonts.FONT_TITILE2);
    // 业务章节
    Section sBiz = parentSection.addSection(pBiz);
    if (biz.isHasImg()) {
      // 表关系章节
      buildTableRelationship(sBiz, biz);
    }
    // 表清单章节
    buildTableListSection(sBiz, biz);
    // 所有表结构
    buildAllTableDetail(sBiz, biz);
  }

  /**
   * 所有表结构
   *
   * @param parentSection
   * @throws DocumentException
   */
  public void buildAllTableDetail(Section parentSection, Biz biz)
      throws DocumentException {
    String title = biz.getName() + "接口表明细";
    // 明细标题
    Paragraph pTitle = new Paragraph(title, Fonts.FONT_TITILE2);

    // 表明细章节
    Section section = parentSection.addSection(pTitle);
    // 循环生成表树的结构
    List<TableTree> tableTrees = biz.getTableTrees();
    if (tableTrees == null) {
      return;
    }
    for (TableTree tableTree : tableTrees) {
      addTableTree(section, tableTree);
    }
  }

  // 生成一个表树得结构
  public void addTableTree(Section parentSection, TableTree tableTree)
      throws DocumentException {
    String code = tableTree.getCode();
    String title = tables.get(code).getName() ;
    if(!title.endsWith("表")){
      title= title+"表";
    }
    title= title+"("+code+")";
    // 表结构标题
    Paragraph pTitle = new Paragraph(title, Fonts.FONT_TITILE3);
    // 表结构章节
    Section section = parentSection.addSection(pTitle);
    // 生成表结构
    TableInfo tableInfo = tables.get(code);
    addTable(section, tableInfo);
    // 递归子表数
    List<TableTree> subs = tableTree.getSubTables();
    if (subs == null) {
      return;
    }
    for (TableTree sub : subs) {
      addTableTree(section, sub);
    }
  }

  public void addTable(Section section, TableInfo tableInfo)
      throws DocumentException {
    PdfPTable t = new PdfPTable(5);
    // 宽度百分比,相对于父容器
    t.setWidthPercentage(98);
    // 各列宽度百分比
    t.setWidths(new int[] { 30, 20, 12, 8, 30 });
    // 上下间隙
    t.setSpacingBefore(25);
    t.setSpacingAfter(25);
    // 设置标题行有几行,跨页时会再生成标题行
    t.setHeaderRows(1);
    /*
     * 如果出现某些行中的文本非常大, 那么iText将按照“行优先”的方式对表格进行分页处理,
     * 所谓“行优先”是说:当遇到无法在当前页显示完整的一行时, 该行将被放到下一页进行显示,而只有当一整业都无法显示完此行时,
     * iText才会将此行拆开显示在两页中。如果不想使用“行优先”的方式,
     * 而是想采用“页优先”方式(保证填满当前页面的前提下,决定是否需要分拆行)显示, 可使用方法setSplitLate(false)。
     */
    t.setSplitLate(true);
    t.setSplitRows(false);
    // 表头
    t.addCell(buildHeaderCell("数据项"));
    t.addCell(buildHeaderCell("字段名"));
    t.addCell(buildHeaderCell("数据类型"));
    t.addCell(buildHeaderCell("填报要求"));
    t.addCell(buildHeaderCell("描述"));

    addColumns(t, tableInfo.getHeaderColumns());
    addColumns(t, tableInfo.getColumns());
    addColumns(t, tableInfo.getFooterColumns());
    section.add(t);
  }

  private void addCell(PdfPTable t, String text, boolean nullable) {
    if (text == null) {
      t.addCell("");
    } else {
      if(nullable){
        t.addCell(buildCell(text))
      }else{
        t.addCell(buildCell(text, Fonts.FONT_MAIN_TEXT_RED));
      }
     
    }

  }

  public void addColumns(PdfPTable t, Map<String, ColInfo> cols) {
    if (cols != null) {
      for (Entry<String, ColInfo> entry : cols.entrySet()) {
        ColInfo colInfo = entry.getValue();
        if (colInfo == null) {
          LOG.warn("字段【{}】为空!!", entry.getKey());
          continue;
        }
        boolean nullable = colInfo.isNullable();
       
        addCell(t, colInfo.getName(), nullable);
        addCell(t, colInfo.getCode(), nullable);
        addCell(t, colInfo.getType(), nullable);
        addCell(t, nullable ? "可选" : "必填", nullable);
        addCell(t, colInfo.getDesc(), nullable);
      }
    }
  }

  /**
   * 表关系章节
   *
   * @param parentSection
   * @throws MalformedURLException
   * @throws IOException
   * @throws DocumentException
   */
  public void buildTableRelationship(Section parentSection, Biz biz)
      throws MalformedURLException, IOException, DocumentException {
    String title = biz.getName() + "关系图";
    // 表关系图标题
    Paragraph pTableImageTitle = new Paragraph(title, Fonts.FONT_TITILE2);
    // 表关系图章节
    Section sTableImage = parentSection.addSection(pTableImageTitle);

    String img = "/table_rel/" + biz.getCode() + ".png";
    LOG.info("加载关系图[{}]", img);
    // 表关系图
    Image iTableImg = Image.getInstance(
        PdfGenerator.class.getResource(img), true);
    iTableImg.scaleToFit(360f, 480f);
    // iTableImg.setAlignment(Image.MIDDLE);
    iTableImg.setIndentationLeft(20f);
    // iTableImg.setBorder(10);
    // iTableImg.setBorderColor(BaseColor.GREEN);
    // iTableImg.setBorderWidth(4);
    iTableImg.setAlignment(Image.LEFT);
    // iTableImg.enableBorderSide(Rectangle.BOX);
    iTableImg.setSpacingBefore(10f);
    iTableImg.setSpacingAfter(10);

    // iTableImg.setAbsolutePosition(
    // (PageSize.POSTCARD.getWidth()
    // - iTableImg.getScaledWidth()) / 2,
    // (PageSize.POSTCARD.getHeight()
    // -iTableImg.getScaledHeight()) / 2);
    //
    // writer.getDirectContent().addImage(iTableImg);

    sTableImage.add(iTableImg);
    // Chunk c = new Chunk("xxxxx", Fonts.FONT_TITILE1);
    // c.setNewPage();
    // sTableImage.add(c);
    // sTableImage.setComplete(true);
    // Chunk c = new Chunk();
    // LineDrawer ld = new LineDrawer(iTableImg);
    // sTableImage.add(ld);
  }

  /**
   * 表清单章节
   *
   * @param cParentChapter
   * @throws DocumentException
   */
  public void buildTableListSection(Section parentSection, Biz biz)
      throws DocumentException {
    String title = biz.getName() + "表清单";
    // 表清单标题
    Paragraph pTableListTitle = new Paragraph(title, Fonts.FONT_TITILE2);
    pTableListTitle.setExtraParagraphSpace(10);
    // 表清单章节
    Section sTableList = parentSection.addSection(pTableListTitle);

    int count = Helper.calcTableCount(biz.getTableTrees());
    // 表清单说明
    Paragraph someSectionText = new Paragraph(biz.getName() + "业务共包括"
        + count + "张业务信息接口表", Fonts.FONT_MAIN_TEXT);
    someSectionText.setSpacingBefore(10);
    someSectionText.setFirstLineIndent(30);
    sTableList.add(someSectionText);
    // 表清单表格
    PdfPTable tTableList = buildTableList(sTableList, biz);
    sTableList.add(tTableList);

    pTableListTitle.setAlignment(Paragraph.ALIGN_LEFT);
  }

  /**
   * 构建业务域内容
   *
   * @throws MalformedURLException
   * @throws IOException
   * @throws DocumentException
   */
  public void addDomainContent(Domain domain) throws MalformedURLException,
      IOException, DocumentException {
    String domainTitle = domain.getName();
    // 域标题
    Paragraph pDomainTitle = new Paragraph(domainTitle, Fonts.FONT_TITILE1);
    pDomainTitle.setAlignment(Paragraph.ALIGN_CENTER);
    // 章节
    Chapter cDomainChapter = new Chapter(domainTitle, chapterIndex++);
    // 编号深度
    cDomainChapter.setNumberDepth(0);
    // 必须添加一个Section。Chapter不会产生目录!!(会产生目录,只有一章的时候阅读器默认隐藏了而已!)
    // Section section = cDomainChapter.addSection(pDomainTitle);
    // 分割线
    LineSeparator line = new LineSeparator(2f, 100, BaseColor.BLACK,
        Element.ALIGN_CENTER, -5f);
    pDomainTitle.add(line);

    List<Biz> bizs = domain.getBizs();

    // 构建该域下面的业务内容
    if (bizs != null && !bizs.isEmpty()) {
      for (Biz biz : bizs) {
        addBiz(cDomainChapter, biz);
      }
    }

    document.add(cDomainChapter);

  }

  private PdfPCell buildHeaderCell(String text) {
    PdfPHeaderCell h1 = new PdfPHeaderCell();
    Phrase pHeader = new Phrase(text, Fonts.FONT_TITILE3);
    // TODO: 居中,没试出效果
    h1.setHorizontalAlignment(PdfPHeaderCell.ALIGN_CENTER);
    h1.setBackgroundColor(BaseColor.GRAY);
    h1.addElement(pHeader);
    return h1;
  }

  private PdfPCell buildCell(String text) {
    return buildCell(text, Fonts.FONT_MAIN_TEXT);
  }
 
  private PdfPCell buildCell(String text, Font font) {
    PdfPCell cell = new PdfPCell();
    Phrase pText = new Phrase(text, font );
    cell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
    cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
    cell.addElement(pText);
    return cell;
  }

  private void addTableTrees(PdfPTable t, List<TableTree> trees) {
    if (trees == null) {
      return;
    }
    for (TableTree tree : trees) {
      addTableTree(t, tree);
    }
  }

  private void addTableTree(PdfPTable t, TableTree tree) {
    if (tree == null) {
      return;
    }
    String code = tree.getCode();
    LOG.info("添加清单:[{}]", code);
    String rel = tree.getRel();
    TableInfo tableInfo = tables.get(code);
    String name = tableInfo.getName();
    //String desc = tableInfo.getDesc();
    // 表内容
    t.addCell(buildCell(name));
    t.addCell(buildCell(code));
    t.addCell(buildCell(rel));
    //t.addCell(buildCell(desc));
    List<TableTree> subTrees = tree.getSubTables();
    addTableTrees(t, subTrees);

  }

  public PdfPTable buildTableList(Section parentSection, Biz biz)
      throws DocumentException {
    PdfPTable t = new PdfPTable(3);
    t.setHorizontalAlignment(PdfPTable.ALIGN_CENTER);
    // 宽度百分比,相对于父容器
    t.setWidthPercentage(98);
    // 各列宽度百分比
    t.setWidths(new int[] { 45, 35, 20 });
    // 上下间隙
    t.setSpacingBefore(25);
    t.setSpacingAfter(25);
    // 设置标题行有几行,跨页时会再生成标题行
    t.setHeaderRows(1);
    /*
     * 如果出现某些行中的文本非常大, 那么iText将按照“行优先”的方式对表格进行分页处理,
     * 所谓“行优先”是说:当遇到无法在当前页显示完整的一行时, 该行将被放到下一页进行显示,而只有当一整业都无法显示完此行时,
     * iText才会将此行拆开显示在两页中。如果不想使用“行优先”的方式,
     * 而是想采用“页优先”方式(保证填满当前页面的前提下,决定是否需要分拆行)显示, 可使用方法setSplitLate(false)。
     */
    t.setSplitLate(true);
    t.setSplitRows(false);
    // 表头
    t.addCell(buildHeaderCell("表中文名"));
    t.addCell(buildHeaderCell("表英文名"));
    t.addCell(buildHeaderCell("表关系"));
    //t.addCell(buildHeaderCell("表描述"));

    // TODO: 第一行不显示,所以填充一行占位!!
    t.addCell(buildCell(""));
    t.addCell(buildCell(""));
    t.addCell(buildCell(""));
    //t.addCell(buildCell(""));

    List<TableTree> tableTrees = biz.getTableTrees();
    addTableTrees(t, tableTrees);

    return t;
  }

  public Map<String, TableInfo> getTables() {
    return tables;
  }

  public PdfGenerator setTables(Map<String, TableInfo> tables) {
    this.tables = tables;
    return this;
  }

}
TOP

Related Classes of cn.guoyukun.pdm2pdf.PdfGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.