最近因为项目需要将对象打印特定模式的PDF,经大佬建议,选择了使用FOP,较之iText,灵活性更强,对代码依赖更少。
下面简要说明一下如何使用及demo。
1. 需求描述
根据现有一个pdf模板,将值填入pdf中导出。其中,值从Java一个List<Map<String, Object>>获取,每个Map展示在一页pdf中,整个List生成为一个pdf文件。
2. 需求分析
1)生成pdf模板
2)将每个Map循环填入pdf中,使得每个Map占用单独一页
3. 技术探测
1)进入fop官网 https://xmlgraphics.apache.org/fop/ 学习,最快捷的方法就是将官网提供的Examples下载到本地运行,这样可以有更直观的感受,可以帮助快速get关键点。
2)fop是一个基于xsl(制作pdf模板)来生成pdf文件的。可以插入图片,将xml,Java对象,SVG等转换为pdf格式的文件。
3)由于xsl确定样式,所以Java代码里只需要提供要展示的值即可,将样式与代码解耦。只要值确定,无论后续pdf样式如何更改,Java代码都无需再动,便于维护。而正因为样式由xsl决定,所以FOP的可定制性非常强,推荐使用。
4. 实践
经过分析,发现fop在将Java对象转换为pdf时,先将对象转换为了xml格式,所以本需求的完成主要聚集在以下两点:
1) xsl学习----官网提供的examples代码里有相对简单的fop.xml文件,可以作为入门。更多的知识点需要学习fo:xsl以及xsl语法,可参考 http://www.w3school.com.cn/xslfo/index.asp、http://www.w3school.com.cn/xsl/xsl_languages.asp;模板制作好后,可参考https://xmlgraphics.apache.org/fop/quickstartguide.html下方,使用命令行 fop -xml XXX.xml -xsl XXX.xsl -pdf xxx.pdf 来测试模板是否为目标模板,此时不需要Java代码参与,更省时省力:)
2) Java对象转xml (采用XStream)
由于需要转换的为List<Map<String, Object>>对象,而fop模板文件中会引用map中的key,而简单的使用XStream无法满足需求(只会将key和value的值同时打印出来,而xml标签里是key/value的详细类型),需要使用XStream提供的Convertor类(从XStream的jar包里取出了MapConvertor类到本地修改),进行简要的转换,使得生成的xml标签为Map的key,而值是Map的value。
关键代码下所示:
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)关键点
3.1)模板---每个Map成为一页,这里使用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">
...
<!-----加上if判断,使得最后一页不生成空白页-->
<xsl:if test="last()>position()">
<fo:block break-before="page"/>
</xsl:if>
</xsl:for-each>
</fo:block>
</fo:flow>
</fo:page-sequence>
3.2)模板---由于要生成不定行的表格(表头一定,但表行数视具体数据而定),使用
<fo:table-body>
<xsl:apply-templates select="XXX"/>
...
</fo:table-body>
<xsl:template match="XXX">
...
</xsl:template>
注意:这里的"XXX"指的是xml中的xpath(不熟悉的需要学习一下),根据这个path,才能找到惟一的标签,这样才能取出标签中的值
- 大小: 102.3 KB
分享到:
相关推荐
数字证书:从文件中读取数字证书,生成文件输入流,输入文件为c:/mycert.cer,获取一个处理X.509证书的证书工厂…… Java+ajax写的登录实例 1个目标文件 内容索引:Java源码,初学实例,ajax,登录 一个Java+ajax写...
数字证书:从文件中读取数字证书,生成文件输入流,输入文件为c:/mycert.cer,获取一个处理X.509证书的证书工厂…… Java+ajax写的登录实例 1个目标文件 内容索引:Java源码,初学实例,ajax,登录 一个Java+ajax写...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
样本pdf 示例 XML 到 FO 到 PDF spring-boot 应用程序。 示例 spring-boot 项目使用 xslt 样式将 xml 数据转换为 fo: 然后使用 apache FOP 将其转换为 pdf 文件
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
J2C 将 Java 代码转成 C++ 代码,这是源码级别的转换,输出的 C++ 代码是有效的代码。 OSGi 分布式通讯组件 R-OSGi R-OSGi 是一套适用于任意满足 OSGi 架构的分布式通讯组件。它以 jar 的形式发布,部署容易,使用...
另一种可能性是使用Batik的模块转换成各种格式SVG的通过,如光栅图像(JPEG,PNG或TIFF格式 )或其它矢量格式(EPS或PDF格式 ,后两者由于转码器由Apache FOP提供 )。 Batik工程创建的目的是为开发者提供一系列...
apache fop可以通过runngin进行安装:brew install fop(OSX)apt-get install fop(Ubuntu / debian)或转到以下位置: : Java JDK 改进之处 在客户端使用javascript编写pdf发票: : 或服务器端: : (node.js...