itextpdf, freemarker and flying-saucer-pdf implement PDF export function

Directory

Directory

1. Import maven

2. Code structure? Edit

3. Plain text generation method

JavaToPdfHtml

template.html

The simhei.ttf font file is downloaded from Baidu

4. Based on the freemarker template engine

JavaToPdfHtmlFreeMarker

templateF.html

5. Based on the advanced features of CSS

JavaToPdfHtmlFreeMarkerCss

templateFCss.html

Font files and picture files to download from Baidu calibri.ttf, simsun.ttc, logo.png

Controller test


  1. import maven

  2. <!-- itextpdf, export pdf core frame package -->
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itextpdf</artifactId>
        <version>5.5.11</version>
    </dependency>
    <!-- itextpdf toolkit, used to parse html to generate pdf -->
    <dependency>
        <groupId>com.itextpdf.tool</groupId>
        <artifactId>xmlworker</artifactId>
        <version>5.5.11</version>
    </dependency>
    <!-- flying saucer, supports parsing of advanced features of CSS -->
    <dependency>
        <groupId>org.xhtmlrenderer</groupId>
        <artifactId>flying-saucer-pdf</artifactId>
        <version>9.1.6</version>
    </dependency>
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.23</version>
    </dependency>
  3. Code Structure

  4. Plain text generation method

    1. JavaToPdfHtml

      import com.itextpdf.text.Document;
      import com.itextpdf.text.DocumentException;
      import com.itextpdf.text.pdf.PdfWriter;
      import com.itextpdf.tool.xml.XMLWorkerFontProvider;
      import com.itextpdf.tool.xml.XMLWorkerHelper;
      import org.springframework.core.io.ClassPathResource;
      
      import java.io.*;
      import java.nio.charset.Charset;
      
      public class JavaToPdfHtml {
      
      private static final String DEST = "D:/pdf/template.pdf";//output address
      private static ClassPathResource FONT = new ClassPathResource("templates/simhei.ttf");
      private static ClassPathResource HTML = new ClassPathResource("templates/template.html");
      
      
      public static void main(String[] args) throws IOException, DocumentException {
      
      // step 1
      Document document = new Document();
      // step 2
      PdfWriter writer = PdfWriter. getInstance(document, new FileOutputStream(DEST));
      // step 3
      document. open();
      // step 4
      XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
      fontImp.register(FONT.getURL().getPath());
      XMLWorkerHelper.getInstance().parseXHtml(writer, document,
      new FileInputStream(HTML. getURL(). getPath()), null, Charset. forName("UTF-8"), fontImp);
      // step 5
      document. close();
      }
      
      }
    2. template.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8" />
      <title>Title</title>
      <style>
      body {
      font-family: SimHei;
      }
      
      .red {
      color: red;
      }
      </style>
      </head>
      <body>
      
      <div class="red">hello world!</div>
      <div class="red">Hi Zook</div>
      </body>
      </html>
    3. simhei.ttf font file to download from Baidu

  5. Basically added freemarker template engine

    1. JavaToPdfHtmlFreeMarker

      import com.itextpdf.text.Document;
      import com.itextpdf.text.DocumentException;
      import com.itextpdf.text.pdf.PdfWriter;
      import com.itextpdf.tool.xml.XMLWorkerFontProvider;
      import com.itextpdf.tool.xml.XMLWorkerHelper;
      
      import freemarker.template.Configuration;
      import freemarker.template.Template;
      import org.springframework.core.io.ClassPathResource;
      
      import javax.servlet.http.HttpServletResponse;
      import java.io.ByteArrayInputStream;
      import java.io.File;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.io.StringWriter;
      import java.io.Writer;
      import java.nio.charset.Charset;
      import java.util.HashMap;
      import java.util.Map;
      
      public class JavaToPdfHtmlFreeMarker {
      
      // Output the address of the PDF file when testing locally
      private static final String DEST = "D:/pdf/templateF.pdf";
      // The directory under the resource where the template file is located
      private static final ClassPathResource FTL = new ClassPathResource("templates/");
      // font file
      private static final ClassPathResource FONT = new ClassPathResource("templates/simhei.ttf");
      // template file
      private static final String HTML = "templateF.html";
      private static Configuration freemarkerCfg = null;
      
      static {
      freemarkerCfg = new Configuration(Configuration. DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
      //freemarker template directory
      try {
      //freemarkerCfg.
      freemarkerCfg.setDirectoryForTemplateLoading(new File(FTL.getURI().getPath()));
      } catch (Exception e) {
      e.printStackTrace();
      }
      }
      
      /**
      * Local Main method test export PDF to local folder
      * @param content
      * @param dest
      * @throws IOException
      * @throws DocumentException
      */
      public static void createPdf(String content, String dest) throws IOException, DocumentException {
      // step 1
      Document document = new Document();
      // step 2
      PdfWriter writer = PdfWriter. getInstance(document, new FileOutputStream(dest));
      // step 3
      document. open();
      // step 4
      XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
      fontImp.register(FONT.getURL().getPath());
      XMLWorkerHelper.getInstance().parseXHtml(writer, document,
      new ByteArrayInputStream(content. getBytes()), null, Charset. forName("UTF-8"), fontImp);
      // step 5
      document. close();
      
      }
      
      /**
      * The web page calls the interface to download PDF
      * @param content
      * @param response
      * @throws IOException
      * @throws DocumentException
      */
      public static void createPdf2(String content, HttpServletResponse response) throws IOException, DocumentException {
      
      response.setContentType("application/pdf");
      // step 1
      Document document = new Document();
      // step 2
      PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
      // step 3
      document. open();
      // step 4
      XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
      fontImp.register(FONT.getURL().getPath());
      XMLWorkerHelper.getInstance().parseXHtml(writer, document,
      new ByteArrayInputStream(content. getBytes()), null, Charset. forName("UTF-8"), fontImp);
      // step 5
      document. close();
      
      }
      
      /**
      * freemarker rendering html
      */
      public static String freeMarkerRender(Map data, String htmlTmp) {
      Writer out = new StringWriter();
      try {
      // Get the template and set the encoding method
      Template template = freemarkerCfg. getTemplate(htmlTmp);
      template.setEncoding("UTF-8");
      // merge data model and template
      template.process(data, out); //Write the merged data and template into the stream, the character stream used here
      out. flush();
      return out.toString();
      } catch (Exception e) {
      e.printStackTrace();
      } finally {
      try {
      out. close();
      } catch (IOException ex) {
      ex. printStackTrace();
      }
      }
      return null;
      }
      
      /**
      * Local testing
      * @param args
      * @throws IOException
      * @throws DocumentException
      */
      public static void main(String[] args) throws IOException, DocumentException {
      Map data = new HashMap();
      data.put("name", "Luffy. Zuke");
      String content = JavaToPdfHtmlFreeMarker. freeMarkerRender(data, HTML);
      JavaToPdfHtmlFreeMarker.createPdf(content, DEST);
      }
      }
    2. templateF.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8" />
      <title>Title</title>
      <style>
      body {
      font-family: SimHei;
      }
      
      .red {
      color: red;
      }
      </style>
      </head>
      <body>
      
      <div class="red">hello world!</div>
      <div class="red">Hi, ${name}</div>
      </body>
      </html>
  6. Based on adding CSS advanced features

    1. JavaToPdfHtmlFreeMarkerCss

      import java.io.File;
      import java.io.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.io.StringWriter;
      import java.io.Writer;
      import java.util.HashMap;
      import java.util.Map;
      
      import org.apache.commons.codec.binary.Base64;
      import org.springframework.core.io.ClassPathResource;
      import org.xhtmlrenderer.pdf.ITextFontResolver;
      import org.xhtmlrenderer.pdf.ITextRenderer;
      
      import com.itextpdf.text.DocumentException;
      import com.itextpdf.text.pdf.BaseFont;
      
      import freemarker.template.Configuration;
      import freemarker.template.Template;
      
      import javax.servlet.http.HttpServletResponse;
      
      public class JavaToPdfHtmlFreeMarkerCss {
      // local test PDF export address
      private static final String DEST = "D:/pdf/templateFCss.pdf";
      // directory where templates are located
      private static final ClassPathResource FTL = new ClassPathResource("templates/");
      // template file
      private static final String HTML = "templateFCss.html";
      // font file
      private static final ClassPathResource FONT = new ClassPathResource("templates/simhei.ttf");
      private static final ClassPathResource FONT_C = new ClassPathResource("templates/calibri.ttf");
      private static final ClassPathResource FONT_S = new ClassPathResource("templates/simsun.ttc");
      // image file
      private static final ClassPathResource LOGO_PATH = new ClassPathResource("templates/logo.png");
      private static Configuration freemarkerCfg = null;
      
      static {
      freemarkerCfg = new Configuration(Configuration. DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
      //freemarker template directory
      try {
      freemarkerCfg.setDirectoryForTemplateLoading(new File(FTL.getURI().getPath()));
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      
      /**
      * Local testing
      * @param args
      * @throws IOException
      * @throws DocumentException
      * @throws com.lowagie.text.DocumentException
      */
      public static void main(String[] args) throws IOException, DocumentException, com.lowagie.text.DocumentException {
      Map data = new HashMap();
      data.put("name", "Lu Qi.D. Ai Nilu ?jie");
      File file = new File(LOGO_PATH. getURL(). getPath());
      data.put("fileType", "image/jpeg");
      data.put("file64Str", fileToBase64Str(file));
      String content = freeMarkerRender(data, HTML);
      System.out.println(content);
      createPdf2(content, DEST);
      
      }
      /**
      * freemarker rendering html
      */
      public static String freeMarkerRender(Map data, String htmlTmp) {
      Writer out = new StringWriter();
      try {
      // Get the template and set the encoding method
      Template template = freemarkerCfg. getTemplate(htmlTmp);
      template.setEncoding("UTF-8");
      // merge data model and template
      template.process(data, out); //Write the merged data and template into the stream, the character stream used here
      out. flush();
      return out.toString();
      } catch (Exception e) {
      e.printStackTrace();
      } finally {
      try {
      out. close();
      } catch (IOException ex) {
      ex. printStackTrace();
      }
      }
      return null;
      }
      
      /**
      * for local testing
      * @param content
      * @param dest
      * @throws IOException
      * @throws DocumentException
      * @throws com.lowagie.text.DocumentException
      */
      public static void createPdf2(String content, String dest) throws IOException, DocumentException, com.lowagie.text.DocumentException {
      ITextRenderer render = new ITextRenderer();
      
      //Set the font
      ITextFontResolver fontResolver = render. getFontResolver();
      fontResolver.addFont(FONT_S.getURL().getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
      fontResolver.addFont(FONT.getURL().getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
      fontResolver.addFont(FONT_C.getURL().getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
      // parse html to generate pdf
      render.setDocumentFromString(content);
      render. layout();
      render.createPDF(new FileOutputStream(dest));
      render. finishPDF();
      }
      
      /**
      * Interface call, web page download
      * @param content
      * @param response
      * @throws IOException
      * @throws DocumentException
      * @throws com.lowagie.text.DocumentException
      */
      public static void createPdf(String content, HttpServletResponse response) throws IOException, DocumentException, com.lowagie.text.DocumentException {
      ITextRenderer render = new ITextRenderer();
      //Set the font
      ITextFontResolver fontResolver = render. getFontResolver();
      fontResolver.addFont(FONT_S.getURL().getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
      fontResolver.addFont(FONT.getURL().getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
      fontResolver.addFont(FONT_C.getURL().getPath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
      // parse html to generate pdf
      render.setDocumentFromString(content);
      render. layout();
      render.createPDF(response.getOutputStream());
      render. finishPDF();
      }
      
      /**
      * File to 64bit Str
      *
      * @param file
      * @return
      */
      public static String fileToBase64Str(File file) {
      byte[] data = null;
      InputStream inputStream = null;
      if (file != null) {
      try {
      inputStream = new FileInputStream(file);
      data = new byte[inputStream. available()];
      inputStream. read(data);
      } catch (Exception e) {
      e.printStackTrace();
      } finally {
      try {
      inputStream. close();
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      return Base64. encodeBase64String(data);
      }
      return null;
      }
      
      /**
      * Common interface for PDF export
      *
      * @param data
      * @param templateName
      * @param response
      */
      public static void exportPdf(Map data, String templateName, String pdfName, HttpServletResponse response) throws UnsupportedEncodingException {
      String content = freeMarkerRender(data, templateName);
      response.setContentType("application/pdf");
      // File name settings support Chinese
      response.setHeader("Content-Disposition", "attachment; filename=" URLEncoder.encode(pdfName, "UTF-8") ".pdf");
      try {
      createPdf(content, response);
      } catch (IOException e) {
      throw new RuntimeException(e);
      } catch (DocumentException e) {
      throw new RuntimeException(e);
      } catch (com. lowagie. text. DocumentException e) {
      throw new RuntimeException(e);
      }
      }
      }
    2. templateFCss.html

      <!DOCTYPE html>
      <html lang="en">
      <head>
      <meta charset="UTF-8"/>
      <title>Title</title>
      <style>
      body {
      font-family: SimHei;
      }
      .color{
      color: green;
      }
      .pos{
      position:absolute;
      left:200px;
      top:5px;
      width: 200px;
      font-size: 10px;
      }
      @media print {
      div. header-right {
      display: block;
      position: running(header-right);
      }
      
      img{page-break-inside: avoid;}
      table{page-break-inside: avoid;}
      }
      @page {
      size: 8.5in 11in;
      
      @top-right {
      content: element(header-right)
      };
      
      /*@bottom-center {
                      content : "Page " counter(page) " of " counter(pages);
                  }; */
      @bottom-center {
      content: element(footer)
      }
      }
      
      #footer {
      position: running(footer);
      }
      
      #pages:before {
      content: counter(page);
      }
      
      #pages:after {
      content: counter(pages);
      }
      
      </style>
      </head>
      <body>
      
      <div id="footer">
      <div style="text-align: center; width: 100%;font-size: 15px;">Page <span id="pages"> of </span></div>
      </div>
      <div class="page">
      <div class="color">Hi, ${name}222</div>
      <img src="data:${fileType};base64,${file64Str}" width="600px" />
      <table border="1">
      <tr>
      <th>Month</th>
      <th>Savings</th>
      </tr>
      <tr>
      <td>January</td>
      <td>$100</td>
      </tr>
      <tr>
      <td>January</td>
      <td>$100</td>
      </tr>
      <tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr><tr>
      <td>January</td>
      <td>$100</td>
      </tr>
      </table>
      </div>
      
      
      </body>
      </html>
    3. Font files and picture files are downloaded by Baidu calibri.ttf, simsun.ttc, logo.png

  7. Controller Test

    @Controller
    @RequestMapping("/pdf")
    public class PdfController {
    
    private static final ClassPathResource LOGO_PATH = new ClassPathResource("templates/logo.png");
    private static final String templateName = "templateFCss.html";
    
    @GetMapping("/sample")
    public void sample(HttpServletResponse response) {
    try {
    Map data = new HashMap<>();
    data.put("name", "Lu Qi.D. Ai Nilu ?jie");
    File file = new File(LOGO_PATH. getURL(). getPath());
    data.put("fileType", "image/jpeg");
    data.put("file64Str", JavaToPdfHtmlFreeMarkerCss.fileToBase64Str(file));
    JavaToPdfHtmlFreeMarkerCss.exportPdf(data, templateName, "My PDF", response);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    Grammar to be noticed in freemarker:

    <style>
            .success {
                color: #1ab394;
                font-weight: bold;
            }
    
            .warning {
                color: #f8ac59;
                font-weight: bold;
            }
    
            .failure {
                color: #ed5565;
                font-weight: bold;
            }
    </style>
    
    
    // Syntax in freemarker:
    
    1. Judge the TRUE and FALSE of the Java Boolean variable testResult:
    <td style="width: 15%;" class="${testResult?string('success', 'failure')}">
        ${testResult?string('success', 'failure')}
    </td>
    
    2. Determine whether the Java collection faultList variable is empty, traverse if not empty, and display no record if it is empty:
    <#if faultList & amp; & amp;(faultList? size > 0)>
        <!-- traverse each fault record in faultList -->
        <#list faultList as fault>
            <tr>
                <td>${fault.id}</td>
                <td>${fault.alarmContent}</td>
                <td>${fault. startTime}</td>
                <td>${fault.endTime}</td>
                <td>${fault.duration}</td>
                <td>${fault. reason}</td>
            </tr>
        </#list>
        <#else>
            <tr>
                <td colspan="6" style="text-align: center;">No record</td>
            </tr>
    </#if>
    
    3. Use of IF/ELSE statement:
    <td style="width: 15%;"
        class="<#if (testResult=0)>failure
               <#elseif (testResult=1)>success
               <#elseif (testResult=2)>warning
               </#if>">
        <#if (testResult=0)> failed
        <#elseif (testResult=1)>Success
        <#elseif (testResult=2)>Dry running
        </#if>
    </td>