跳至主要內容

数据源

xsx大约 9 分钟fop模块数据源

说明

数据源可分为手动模式(模板引擎)与自动模式(对象模式)

手动模式(模板引擎)需自行编写模板, 自动模式(对象模式)无需编写模板

手动模式(模板引擎)

说明

需自行编写模板,控制更灵活

freemarker 数据源

提示

默认数据源,想了解更多语法规则可参考freemarker中文教程open in new window

// 定义fop配置文件路径
String configPath = "E:\\pdf\\template\\fop.xconf";
// 定义xsl-fo模板路径
String templatePath = "E:\\pdf\\template\\freemarker";
// 定义pdf输出路径
String outputPath = "E:\\pdf\\test\\fo\\Freemarker.pdf";
// 设置模板路径
TemplateHandler.DataSource.Freemarker.setTemplatePath(templatePath);
// 定义数据map
Map<String, Object> data = new HashMap<>();
// 定义数据list
List<String> list = new ArrayList<>(2);
list.add("hello");
list.add("world");
// 设置值
data.put("list", list);
data.put("str", "hello world");
// 转换pdf
TemplateHandler.Template.build().setConfigPath(configPath).setDataSource(
        TemplateHandler.DataSource.Freemarker.build().setTemplateName("template.fo").setTemplateData(data)
).transform(outputPath);
使用配置
<?xml version="1.0"?>
<!-- fop版本 -->
<fop version="1.0">

    <!-- 当前路径(项目所在路径) -->
    <base>.</base>

    <!-- 默认源图像 dpi(每英寸点数像素) -->
    <source-resolution>72</source-resolution>
    <!-- 默认目标图像 dpi(每英寸点数像素),默认: 72dpi -->
    <target-resolution>72</target-resolution>

    <!-- 默认页面宽度与高度(A4) -->
    <default-page-settings width="21cm" height="29.7cm"/>

    <!-- 渲染器 -->
    <renderers>
        <!-- pdf 渲染器 -->
        <renderer mime="application/pdf">
            <!-- 过滤器 -->
            <filterList>
                <!-- 默认使用 flate 依赖压缩 -->
                <value>flate</value>
            </filterList>
            <!-- 字体 -->
            <fonts>
                <!-- 自动扫描系统全部字体 -->
                <auto-detect/>
            </fonts>
        </renderer>
    </renderers>
</fop>
使用模板
<?xml version="1.0" encoding="utf-8"?>
<!--根标签-->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
         xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
         xmlns:xe="http://www.x-easypdf.cn/ns"
         xmlns:svg="http://www.w3.org/2000/svg">
    <!--页面模板-->
    <fo:layout-master-set>
        <!--单页面模板-->
        <fo:simple-page-master master-name="A4">
            <!--页面区域主体-->
            <fo:region-body/>
        </fo:simple-page-master>
    </fo:layout-master-set>
    <!--页面序列-->
    <fo:page-sequence master-reference="A4">
        <!--页面流-->
        <fo:flow flow-name="xsl-region-body">
        <#list list as data>
            <fo:block>${data}</fo:block>
        </#list>
        <#if str??>
        <fo:block>${str}</fo:block>
        <#else>
        <fo:block>为空</fo:block>
        </#if>
        </fo:flow>
    </fo:page-sequence>
</fo:root>

thymeleaf 数据源

提示

可选数据源,想了解更多语法规则可参考thymeleaf官方教程open in new window

// 定义fop配置文件路径
String configPath = "E:\\pdf\\template\\fop.xconf";
// 定义xsl-fo模板路径
String templatePath = "E:\\pdf\\template\\thymeleaf\\template.fo";
// 定义pdf输出路径
String outputPath = "E:\\pdf\\test\\fo\\Thymeleaf.pdf";
// 定义数据map
Map<String, Object> data = new HashMap<>();
// 设置值
data.put("data", "hello world");
// 转换pdf
TemplateHandler.Template.build().setConfigPath(configPath).setDataSource(
        TemplateHandler.DataSource.Thymeleaf.build().setTemplatePath(templatePath).setTemplateData(data)
).transform(outputPath);
使用配置
<?xml version="1.0"?>
<!-- fop版本 -->
<fop version="1.0">

    <!-- 当前路径(项目所在路径) -->
    <base>.</base>

    <!-- 默认源图像 dpi(每英寸点数像素) -->
    <source-resolution>72</source-resolution>
    <!-- 默认目标图像 dpi(每英寸点数像素),默认: 72dpi -->
    <target-resolution>72</target-resolution>

    <!-- 默认页面宽度与高度(A4) -->
    <default-page-settings width="21cm" height="29.7cm"/>

    <!-- 渲染器 -->
    <renderers>
        <!-- pdf 渲染器 -->
        <renderer mime="application/pdf">
            <!-- 过滤器 -->
            <filterList>
                <!-- 默认使用 flate 依赖压缩 -->
                <value>flate</value>
            </filterList>
            <!-- 字体 -->
            <fonts>
                <!-- 自动扫描系统全部字体 -->
                <auto-detect/>
            </fonts>
        </renderer>
    </renderers>
</fop>
使用模板
<?xml version="1.0" encoding="utf-8"?>
<!--根标签-->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
         xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
         xmlns:xe="http://www.x-easypdf.cn/ns"
         xmlns:svg="http://www.w3.org/2000/svg">
    <!--页面模板-->
    <fo:layout-master-set>
        <!--单页面模板-->
        <fo:simple-page-master master-name="A4">
            <!--页面区域主体-->
            <fo:region-body/>
        </fo:simple-page-master>
    </fo:layout-master-set>
    <!--页面序列-->
    <fo:page-sequence master-reference="A4">
        <!--页面流-->
        <fo:flow flow-name="xsl-region-body">
            <!--块-->
            <fo:block text-align="center" th:text="${data}"/>
        </fo:flow>
    </fo:page-sequence>
</fo:root>

jte 数据源

提示

可选数据源,想了解更多语法规则可参考jte官方教程open in new window

// 定义fop配置文件路径
String configPath = "/wiki/xsx/core/pdf/template/fop.xconf";
// 定义xsl-fo模板路径
String templatePath = "wiki/xsx/core/pdf/template/jte/template.jte";
// 定义pdf输出路径
String outputPath = "E:\\pdf\\test\\fo\\Jte.pdf";
// 定义数据map
Map<String, Object> data = new HashMap<>();
List<String> list = new ArrayList<>(2);
list.add("hello");
list.add("world");
// 设置值
data.put("list", list);
data.put("str", "hello world");
TemplateHandler.Template.build().setConfigPath(configPath).setDataSource(
    TemplateHandler.DataSource.Jte.build().setTemplatePath(templatePath).setTemplateData(data)
).transform(outputPath);
使用配置
<?xml version="1.0"?>
<!-- fop版本 -->
<fop version="1.0">

    <!-- 当前路径(项目所在路径) -->
    <base>.</base>

    <!-- 默认源图像 dpi(每英寸点数像素) -->
    <source-resolution>72</source-resolution>
    <!-- 默认目标图像 dpi(每英寸点数像素),默认: 72dpi -->
    <target-resolution>72</target-resolution>

    <!-- 默认页面宽度与高度(A4) -->
    <default-page-settings width="21cm" height="29.7cm"/>

    <!-- 渲染器 -->
    <renderers>
        <!-- pdf 渲染器 -->
        <renderer mime="application/pdf">
            <!-- 过滤器 -->
            <filterList>
                <!-- 默认使用 flate 依赖压缩 -->
                <value>flate</value>
            </filterList>
            <!-- 字体 -->
            <fonts>
                <!-- 自动扫描系统全部字体 -->
                <auto-detect/>
            </fonts>
        </renderer>
    </renderers>
</fop>
使用模板
<%--不能留空行--%>
@import java.util.List
@param List<String> list
@param String str
<?xml version="1.0" encoding="utf-8"?>
<!--根标签-->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
         xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
         xmlns:xe="http://www.x-easypdf.cn/ns"
         xmlns:svg="http://www.w3.org/2000/svg">
    <!--页面模板-->
    <fo:layout-master-set>
        <!--单页面模板-->
        <fo:simple-page-master master-name="A4">
            <!--页面区域主体-->
            <fo:region-body/>
        </fo:simple-page-master>
    </fo:layout-master-set>
    <!--页面序列-->
    <fo:page-sequence master-reference="A4">
        <!--页面流-->
        <fo:flow flow-name="xsl-region-body">
            @for(String data : list)
            <fo:block>${data}</fo:block>
            @endfor
            @if(str!=null)
            <fo:block>${str}</fo:block>
            @else
            <fo:block>为空</fo:block>
            @endif
        </fo:flow>
    </fo:page-sequence>
</fo:root>

xml(xslt)数据源

提示

可选数据源,想了解更多语法规则可参考菜鸟教程open in new window

// 定义fop配置文件路径
String configPath = "E:\\pdf\\template\\fop.xconf";
// 定义xsl-fo模板路径
String templatePath = "E:\\pdf\\template\\xml\\template.fo";
// 定义xml数据路径
String xmlPath = "E:\\pdf\\template\\xml\\data.xml";
// 定义pdf输出路径
String outputPath = "E:\\pdf\\test\\fo\\xml.pdf";
// 转换pdf
TemplateHandler.Template.build().setConfigPath(configPath).setDataSource(
	TemplateHandler.DataSource.XML.build().setTemplatePath(templatePath).setXmlPath(xmlPath)
).transform(outputPath);
使用配置
<?xml version="1.0"?>
<!-- fop版本 -->
<fop version="1.0">

    <!-- 当前路径(项目所在路径) -->
    <base>.</base>

    <!-- 默认源图像 dpi(每英寸点数像素) -->
    <source-resolution>72</source-resolution>
    <!-- 默认目标图像 dpi(每英寸点数像素),默认: 72dpi -->
    <target-resolution>72</target-resolution>

    <!-- 默认页面宽度与高度(A4) -->
    <default-page-settings width="21cm" height="29.7cm"/>

    <!-- 渲染器 -->
    <renderers>
        <!-- pdf 渲染器 -->
        <renderer mime="application/pdf">
            <!-- 过滤器 -->
            <filterList>
                <!-- 默认使用 flate 依赖压缩 -->
                <value>flate</value>
            </filterList>
            <!-- 字体 -->
            <fonts>
                <!-- 自动扫描系统全部字体 -->
                <auto-detect/>
            </fonts>
        </renderer>
    </renderers>
</fop>
使用模板
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
                xmlns:xe="http://www.x-easypdf.cn/ns"
                xmlns:svg="http://www.w3.org/2000/svg">
    <!--模板-->
    <xsl:template match="root">
        <!--根标签-->
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <!--页面模板-->
            <fo:layout-master-set>
                <!--单页面模板-->
                <fo:simple-page-master master-name="A4">
                    <!--页面区域主体-->
                    <fo:region-body/>
                </fo:simple-page-master>
            </fo:layout-master-set>
            <!--页面序列-->
            <fo:page-sequence master-reference="A4">
                <!--页面流-->
                <fo:flow flow-name="xsl-region-body">
                    <!--块-->
                    <fo:block text-align="center">
                        <!--文本内容-->
                        <xsl:apply-templates select="data"/>
                    </fo:block>
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
</xsl:stylesheet>
使用数据
<?xml version="1.0" encoding="utf-8"?>
<root>
    <data>hello world</data>
</root>

自动模式(对象模式)

说明

无需自行编写模板,以对象构建的方式生成 pdf 文档

document 数据源

// 定义pdf输出路径
String outputPath = "E:\\pdf\\test\\fo\\document.pdf";
// 转换pdf
TemplateHandler.Document.build().addPage(
    TemplateHandler.Page.build().addBodyComponent(
        TemplateHandler.Text.build().setText("hello world")
    )
).transform(outputPath);
使用配置(默认配置)
<?xml version="1.0"?>
<!-- fop版本 -->
<fop version="1.0">

    <!-- 当前路径(项目所在路径) -->
    <base>.</base>

    <!-- 默认源图像 dpi(每英寸点数像素) -->
    <source-resolution>72</source-resolution>
    <!-- 默认目标图像 dpi(每英寸点数像素),默认: 72dpi -->
    <target-resolution>72</target-resolution>

    <!-- 默认页面宽度与高度(A4) -->
    <default-page-settings width="21cm" height="29.7cm"/>

    <!-- 渲染器 -->
    <renderers>
        <!-- pdf 渲染器 -->
        <renderer mime="application/pdf">
            <!-- 过滤器 -->
            <filterList>
                <!-- 默认使用 flate 依赖压缩 -->
                <value>flate</value>
            </filterList>
            <!-- 字体 -->
            <fonts>
                <!-- 自动扫描系统全部字体 -->
                <auto-detect/>
            </fonts>
        </renderer>
    </renderers>
</fop>
使用模板(默认模板)
<?xml version="1.0" encoding="utf-8"?>
<!--根标签-->
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
         xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
         xmlns:xe="http://www.x-easypdf.cn/ns"
         xmlns:svg="http://www.w3.org/2000/svg">
    <!--页面模板-->
    <fo:layout-master-set></fo:layout-master-set>
</fo:root>

提示

该配置可在 java 代码中进行替换

自定义数据源

说明

如果内置数据源不能满足需求,可自定义数据源

方式一:实现接口

public class MyDataSource implements TemplateDataSource {

    /**
     * 获取数据源读取器
     *
     * @return 返回数据源读取器
     */
    @Override
    public Reader getSourceReader() {
        // TODO 实现模板读取器
        return null;
    }

    /**
     * 转换
     *
     * @param fopFactory   fop工厂
     * @param foAgent      fo代理
     * @param outputStream 输出流
     */
    @Override
    public void transform(FopFactory fopFactory, FOUserAgent foAgent, OutputStream outputStream) {
        // TODO 实现转换逻辑
    }
}
实现参考
public class TemplateDataSourceImpl implements TemplateDataSource {

    /**
     * 模板路径
     */
    protected String templatePath;
    /**
     * 模板数据
     */
    protected Map<String, Object> templateData;

    /**
     * 获取数据源读取器
     *
     * @return 返回数据源读取器
     */
    @SneakyThrows
    @Override
    public Reader getSourceReader() {
        return new InputStreamReader(this.loadTemplate(), StandardCharsets.UTF_8);
    }

    /**
     * 转换
     *
     * @param fopFactory   fop工厂
     * @param foAgent      fo代理
     * @param outputStream 输出流
     */
    @SneakyThrows
    @Override
    public void transform(FopFactory fopFactory, FOUserAgent foAgent, OutputStream outputStream) {
        this.saxTransform(fopFactory, foAgent, outputStream);
    }

    /**
     * 加载模板
     *
     * @return 返回模板输入流
     */
    @SneakyThrows
    private InputStream loadTemplate() {
        try {
            // 从资源路径加载模板
            InputStream inputStream = this.getClass().getResourceAsStream(this.templatePath);
            // 如果不为空,则返回,否则从绝对路径加载模板
            return inputStream != null ? inputStream : Files.newInputStream(Paths.get(this.templatePath));
        } catch (Exception e) {
            // 提示错误信息
            throw new IllegalArgumentException("the template can not be loaded,the path['" + this.templatePath + "'] is error");
        }
    }
}

方式二:继承抽象类

public class MyDataSource extends TemplateAbstractDataSource {

    /**
     * 处理模板
     *
     * @return 返回模板输入流
     */
    @Override
    protected InputStream processTemplate() {
        // TODO 实现模板输入流
        return null;
    }
}
实现参考(freemarker)
public class FreemarkerDataSource extends AbstractDataSource {

    /**
     * 模板配置
     */
    private static final Configuration CONFIGURATION = initConfiguration();

    /**
     * 设置模板名称
     *
     * @param templateName 模板名称
     * @return 返回freemarker数据源
     */
    public FreemarkerDataSource setTemplateName(String templateName) {
        this.templatePath = templateName;
        TemplateLoader templateLoader = CONFIGURATION.getTemplateLoader();
        if (templateLoader instanceof DefaultURLTemplateLoader) {
            ((DefaultURLTemplateLoader) templateLoader).setTemplateName(templateName);
        }
        return this;
    }

    /**
     * 设置模板数据
     *
     * @param templateData 模板数据
     * @return 返回freemarker数据源
     */
    public FreemarkerDataSource setTemplateData(Map<String, Object> templateData) {
        this.templateData = templateData;
        return this;
    }

    /**
     * 处理模板
     *
     * @return 返回模板输入流
     */
    @SneakyThrows
    protected InputStream processTemplate() {
        try (
                // 创建输出流
                ByteArrayOutputStream output = new ByteArrayOutputStream();
                // 创建写入器
                Writer writer = new BufferedWriter(new OutputStreamWriter(output))
        ) {
            // 处理模板
            FreemarkerDataSource.CONFIGURATION.getTemplate(this.templatePath).process(this.templateData, writer);
            // 返回输入流
            return new BufferedInputStream(new ByteArrayInputStream(output.toByteArray()));
        }
    }

    /**
     * 初始化配置
     *
     * @return 返回配置
     */
    @SneakyThrows
    private static Configuration initConfiguration() {
        // 创建配置
        Configuration config = new Configuration(Configuration.VERSION_2_3_31);
        // 设置默认编码
        config.setDefaultEncoding(StandardCharsets.UTF_8.name());
        // 设置模板异常处理器
        config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        // 设置模板异常日志
        config.setLogTemplateExceptions(false);
        // 设置未检查异常
        config.setWrapUncheckedExceptions(true);
        // 设置空循环变量回退
        config.setFallbackOnNullLoopVariable(false);
        // 获取模板路径
        String templatePath = System.getProperty(Constants.FREEMARKER_TEMPLATE_PATH_KEY);
        // 如果非资源路径,则为文件目录
        if (Thread.currentThread().getContextClassLoader().getResource(templatePath) == null) {
            try {
                // 设置文件目录解析器
                config.setDirectoryForTemplateLoading(Paths.get(templatePath).toFile());
            } catch (Exception e) {
                // 设置远程资源解析器
                config.setTemplateLoader(new DefaultURLTemplateLoader(templatePath));
            }
        } else {
            // 设置资源解析器
            config.setTemplateLoader(new ClassTemplateLoader(FreemarkerDataSource.class, File.separator + templatePath));
        }
        // 返回配置
        return config;
    }
}

使用方式

说明

自定义数据源与内置数据源使用方式相同,传入模板对象即可

// 定义fop配置文件路径
String configPath = "E:\\pdf\\template\\fop.xconf";
// 定义pdf输出路径
String outputPath = "E:\\pdf\\test\\fo\\my.pdf";
// 转换pdf
TemplateHandler.Template.build().setConfigPath(configPath).setDataSource(
    // 传入自定义数据源
    new MyDataSource()
).transform(outputPath);