Apache FOP convert Java objects to pdf files

Recently, because the project needs to print the object to a PDF in a specific mode, after the suggestion of the boss, I chose to use FOP, which is more flexible and less dependent on code than iText.

The following is a brief description of how to use and demo.

1. Requirement description

    According to an existing pdf template, fill in the value into the pdf and export. Among them, the value is obtained from a List<Map<String, Object>> in Java, each Map is displayed in a pdf page, and the entire List is generated as a pdf file.   

2. Demand analysis

    1) Generate a pdf template

    2) Fill each Map into the pdf in a loop, so that each Map occupies a separate page

3. Technical detection

    1) Enter the fop official website https://xmlgraphics.apache.org/fop/ The quickest way to learn is to download the Examples provided by the official website to run locally, so that you can have a more intuitive feeling and help you get key points quickly.

    2) fop is a pdf file based on xsl (making pdf template). You can insert pictures, convert xml, Java objects, SVG, etc. to pdf files.

    3) Since xsl determines the style, you only need to provide the value to be displayed in the Java code to decouple the style from the code. As long as the value is determined, no matter how the subsequent pdf style changes, the Java code does not need to be moved, which is convenient for maintenance. And because the style is determined by xsl, FOP is very customizable and recommended.

4.

    After analyzing the practice, it is found that when fop converts Java objects to pdf, it first converts the objects to xml format, so the completion of this requirement is mainly concentrated in the following two points:

    1) xsl learning----The examples code provided by the official website has a relatively simple fop.xml file, which can be used as an entry. For more knowledge points, you need to learn fo:xsl and xsl grammar, please refer to http://www.w3school.com.cn/xslfo/index.asp, http://www.w3school.com.cn/xsl/xsl_languages. asp; After the template is made, you can refer to https://xmlgraphics.apache.org/fop/quickstartguide.html and use the command line fop -xml XXX.xml -xsl XXX.xsl -pdf xxx.pdf to test whether the template is The target template does not require the participation of Java code at this time, which saves time and effort:)

    2) Java object to xml (using XStream)

          needs to be converted to List<Map<String, Object>> object, which will be referenced in the fop template file The key in the map, but simply using XStream cannot meet the requirements (only the values ​​of key and value are printed at the same time, and the xml tag is the detailed type of key/value), you need to use the Converter class provided by XStream (from XStream's The MapConvertor class is taken out of the jar package and modified locally), and a brief conversion is performed, so that the generated xml tag is the key of the Map, and the value is the value of the Map.

The key code is as follows:

public boolean canConvert(Class type)
	  {
	    if (this.type != null) {
	      return type.equals(this.type);
	    }
	    return (type.equals(HashMap.class)) ||
	      (type.equals(Hashtable.class)) ||
	      (type.getName().equals("java.util.LinkedHashMap")) ||
	      (type.getName().equals("java.util.concurrent.ConcurrentHashMap")) ||
	      (type.getName().equals("sun.font.AttributeMap") ||
	      (type.equals(HashedMap.class)) );
	  }
	  
	  public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context)
	  {
	    Map map = (Map)source;
	    for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();)
	    {
	      Map.Entry entry = (Map.Entry)iterator.next();
	      ExtendedHierarchicalStreamWriterHelper.startNode(writer, entry.getKey().toString(), entry.getClass());
	      
	      writeItem(entry.getValue(), context, writer);
	      
	      writer.endNode();
	    }
	  }


    3) Key points
    3.1) Template---each Map becomes a page, here use xsl:for-each
<fo:page-sequence master-reference="A4-portrait">
  <fo:flow flow-name="xsl -region-body">
   <fo:block>
     <xsl:for-each select="List/map">
       ...
        <!-----Add if judgment, so that the last page does not generate a blank page-- >
        <xsl:if test="last()>position()">
         <fo:block break-before="page"/>
        </xsl:if>
     </xsl:for-each>
   </fo:block>
</fo:flow>
</fo:page-sequence>

   3.2) Template --- Since a table with indefinite rows needs to be generated (the table header is certain, but the number of table rows depends on the specific data), use
    <fo:table-body >   
       <xsl: apply-templates select="XXX"/>
        ...
    </fo:table-body>
    <xsl:template match="XXX">
    ...
    </xsl:template>
    Note: "XXX" here refers to the xpath in xml (if you are unfamiliar, you need to learn it), according to this path, you can find the only one label, so that the value in the label can be retrieved
   

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326115836&siteId=291194637