java aspose word 模板根据数据导出pdf

支持以功能:

1、字符串占位符替换。

2、占位符循环替换。

3、图片替换。

4、基础图标,折现、饼图、柱状图。

本案例运行环境:

1、aspose word21.1版本。

2、jdk 18。

话不多说直接上代码。

复制代码
<!-- 图表相关 -->
        <dependency>
            <groupId>jfree</groupId>
            <artifactId>jfreechart</artifactId>
            <version>1.0.13</version>
        </dependency>
        <!-- 文档处理 -->
        <dependency>
            <groupId>com.aspose</groupId>
            <artifactId>aspose-words</artifactId>
            <version>21.1</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/aspose-words-21.1.jar</systemPath>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>

maven依赖

复制代码
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;

import java.awt.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;

/**
 *@author pengbenlei
 *@date 2024/12/12 11:37
 *@desc
 */
public class ChartUtil {
    private static final Color[] BAR_COLORS = new Color[]{
            new Color(79, 129, 189),
            new Color(192, 80, 77),
            new Color(155, 187, 89),
    };

    private static final Color[] LINE_COLORS = new Color[]{
            new Color(237, 123, 46),
            new Color(90, 154, 213),
            new Color(164, 164, 164),
    };

    private static final Color[] PIE_COLORS = new Color[]{
            new Color(75, 172, 198),
            new Color(128, 100, 162),
            new Color(155, 187, 89),
            new Color(192, 80, 77),
            new Color(79, 129, 189),
            new Color(44, 77, 117),
            new Color(247, 150, 70),
            new Color(165, 165, 165),
    };


    private static StandardChartTheme initChartTheme() {
        StandardChartTheme currentTheme = new StandardChartTheme("JFree");
        // 横轴纵轴标题文字大小
        currentTheme.setLargeFont(new java.awt.Font("宋体", java.awt.Font.BOLD, 15));
        // 横轴纵轴数值文字大小
        currentTheme.setRegularFont(new java.awt.Font("宋体", java.awt.Font.PLAIN, 13));
        currentTheme.setExtraLargeFont(new java.awt.Font("宋体", java.awt.Font.BOLD, 20));
        // 背景颜色
        currentTheme.setPlotBackgroundPaint(new Color(255, 255, 204, 0));
        // 边框线条
        currentTheme.setPlotOutlinePaint(new Color(0, 0, 0, 0));
        // 网格线条
        currentTheme.setRangeGridlinePaint(new Color(78, 74, 74));
        return currentTheme;
    }

    /**
     * 线图
     *
     * @param title 标题
     * @param categoryAxisLabel 分类标签
     * @param valueAxisLabel 数值标签
     * @param dataset 数据集
     * @return org.jfree.chart.JFreeChart
     * @author Hou_fx
     * @date 2021.8.4 10:39
     */
    public static JFreeChart lineChart(String title, String categoryAxisLabel, String valueAxisLabel, DefaultCategoryDataset dataset) {
        ChartFactory.setChartTheme(initChartTheme());

        JFreeChart chart = ChartFactory.createLineChart(
                title,
                categoryAxisLabel,
                valueAxisLabel,
                dataset,
                PlotOrientation.VERTICAL,
                true,
                true,
                false
        );

        CategoryPlot plot = chart.getCategoryPlot();
        LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
        // 折现点显示数值
        renderer.setBaseItemLabelsVisible(true);
        renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
        // 更改线条颜色
        for (int i = 0; i < dataset.getRowKeys().size(); i++) {
            renderer.setSeriesPaint(i, LINE_COLORS[i]);
        }
        return chart;
    }

    /**
     * 柱状图
     *
     * @param title
     * @param categoryAxisLabel
     * @param valueAxisLabel
     * @param dataset           数据集
     * @return org.jfree.chart.JFreeChart
     * @author Hou_fx
     * @date 2021.8.4 14:03
     */
    public static JFreeChart barChart(String title, String categoryAxisLabel, String valueAxisLabel, DefaultCategoryDataset dataset) {
        ChartFactory.setChartTheme(initChartTheme());

        JFreeChart chart = ChartFactory.createBarChart(
                title,
                categoryAxisLabel,
                valueAxisLabel,
                dataset,
                PlotOrientation.VERTICAL,
                true,
                true,
                false
        );

        CategoryPlot plot = chart.getCategoryPlot();
        BarRenderer renderer = (BarRenderer) plot.getRenderer();
        // 纯色显示
        renderer.setBarPainter(new StandardBarPainter());
        // 柱子上显示小数字
        renderer.setBaseItemLabelsVisible(true);
        renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
        // 设置柱子间隔
        renderer.setItemMargin(0.0);
        // 设置柱子颜色
        for (int i = 0; i < dataset.getRowKeys().size(); i++) {
            renderer.setSeriesPaint(i, BAR_COLORS[i]);
        }
        return chart;
    }

    /**
     * 饼图
     *
     * @param title
     * @param dataset
     * @return org.jfree.chart.JFreeChart
     * @author Hou_fx
     * @date 2021.8.4 14:04
     */
    public static JFreeChart pieChart(String title, DefaultPieDataset dataset) {
        ChartFactory.setChartTheme(initChartTheme());

        JFreeChart chart = ChartFactory.createPieChart(
                title,
                dataset,
                true,
                true,
                false
        );
        PiePlot plot = (PiePlot) chart.getPlot();
        // 设置扇区颜色
        for (int i = 0; i < dataset.getKeys().size(); i++) {
            plot.setSectionPaint(dataset.getKey(i), PIE_COLORS[i]);
        }
        // 设置扇区的线条颜色
        plot.setBaseSectionOutlinePaint(new Color(255, 255, 255));
        // 设置扇区的线条大小
        plot.setBaseSectionOutlineStroke(new BasicStroke(3));
        // 设置标签颜色
        plot.setLabelLinkPaint(new Color(255, 255, 255, 0));
        // 设置标签背景色
        plot.setLabelBackgroundPaint(new Color(255, 255, 255, 0));
        // 设置标签线条颜色
        plot.setLabelOutlinePaint(new Color(255, 255, 255, 0));
        // 设置标签阴影颜色
        plot.setLabelShadowPaint(new Color(255, 255, 255, 0));
        // 设置饼图阴影颜色
        plot.setShadowPaint(new Color(255, 255, 255, 0));
        // 添加标签数字百分比显示
        plot.setLabelGenerator(new StandardPieSectionLabelGenerator(("{0}{2}"), NumberFormat.getNumberInstance(), new DecimalFormat("0.00%")));
        return chart;
    }
}

图表相关工具类

复制代码
import com.aspose.words.*;
import org.jfree.chart.ChartUtilities;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 *@author pengbenlei
 *@date 2024/12/12 15:07
 *@desc
 */
public class AsposeUtils {


    /**
     * 根据word模板生成pdf
     * @param template 模板路径
     * @param outPath  输出目录
     * @param dataJson  业务数据json字符串
     * @param sourceName 业务数据源名称
     * @param wordImages  图片集合
     * @throws Exception 异常信息
     */
    public static void getPdfByWordTemplate(String template, String outPath, String dataJson, String sourceName, List<WordImg> wordImages) throws Exception {
        // 验证
        Assert.isTrue(StringUtils.hasLength(template), "模板文件路径不能为空!");
        Assert.isTrue(StringUtils.hasLength(sourceName), "模板数据源名称!");
        Assert.isTrue(StringUtils.hasLength(outPath), "pdf输出路径不能为空!");
        // 将输入流转为doc
        Document doc = new Document(template);
        // doc构建
        DocumentBuilder builder = new DocumentBuilder(doc);
        // 填充数据
        JsonDataLoadOptions opt = new JsonDataLoadOptions();
        final ReportingEngine engine = new ReportingEngine();
        JsonDataSource jsonDataSource = new JsonDataSource(new ByteArrayInputStream(dataJson.getBytes()), opt);
        engine.buildReport(doc, jsonDataSource, sourceName);
        // 填充图片
        for (WordImg wordImage : wordImages) {
            if (!StringUtils.hasLength(wordImage.getBookmark())) {
                continue;
            }
            // 定位书签位置
            builder.moveToBookmark(wordImage.getBookmark());
            if (wordImage.getType() == 1 || wordImage.getType() == 3) {
                // 本地图片和网络url图片
                builder.insertImage(wordImage.getPath());
            } else if (wordImage.getType() == 2) {
                // 字节码图片
                builder.insertImage(wordImage.getImageBytes());
            }
        }
        // 转pdf
        doc.save(outPath, SaveFormat.PDF);
    }

    public static void main(String[] args) throws Exception {
        final String filePath = "C:\\Users\\Administrator\\Desktop\\上传整理\\新建文件夹\\temp.docx";
        final String outPath = "C:\\Users\\Administrator\\Desktop\\上传整理\\新建文件夹\\output.pdf";
        String jsonStr = "{\n" +
                "    \"age\": 20,\n" +
                "    \"birth\": \"1555-01-55\",\n" +
                "    \"checkNumber\": \"12349864\",\n" +
                "    \"idCard\": \"56456461645\",\n" +
                "    \"items\": [\n" +
                "        {\n" +
                "            \"checked\": false,\n" +
                "            \"itemName\": \"血常规\"\n" +
                "        },\n" +
                "        {\n" +
                "            \"checked\": false,\n" +
                "            \"itemName\": \"生化检验\"\n" +
                "        },\n" +
                "        {\n" +
                "            \"checked\": true,\n" +
                "            \"itemName\": \"尿常规\"\n" +
                "        }\n" +
                "    ],\n" +
                "    \"name\": \"张三三\",\n" +
                "    \"phone\": \"15445454454\",\n" +
                "    \"sex\": \"男\",\n" +
                "    \"title\": \"成都市温江区金马街道社区卫生服务中心\"\n" +
                "}";
        DefaultCategoryDataset lineDataset = new DefaultCategoryDataset();
        for (int i = 1; i < 10; i++) {
            lineDataset.addValue(i, "张儿", String.valueOf((i * 2)));
        }

        for (int i = 1; i < 5; i++) {
            lineDataset.addValue(i, "李儿", String.valueOf((i * 3)));
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        // 折线图
//        ChartUtilities.writeChartAsJPEG(bos, ChartUtil.lineChart("测试折线图", "A", "B", lineDataset),
//                300, 300);
        // 折线图
//        ChartUtilities.writeChartAsJPEG(bos, ChartUtil.lineChart("测试折线图", "A", "B", lineDataset),
//                (int) signRect.getWidth(), (int) signRect.getHeight());
        // 饼图
        DefaultPieDataset defaultPieDataset = new DefaultPieDataset();
        defaultPieDataset.setValue("Category A", 40); // 类别 A 占 40%
        defaultPieDataset.setValue("Category B", 30); // 类别 B 占 30%
        defaultPieDataset.setValue("Category C", 20); // 类别 C 占 20%
        defaultPieDataset.setValue("Category D", 10); // 类别 D 占 10%
        ChartUtilities.writeChartAsJPEG(bos, ChartUtil.pieChart("测试饼图", defaultPieDataset),
                200, 200);
//        ChartUtilities.writeChartAsJPEG(bos, ChartUtil.barChart("测试柱状图", "A", "B", lineDataset),
//                200, 200);
        byte[] imageBytes = bos.toByteArray();
        List<WordImg> wordImages = new ArrayList<>();
        // 二维码
        WordImg wordImg1 = WordImg.builder()
                .bookmark("qrCode")
                .type(1)
                .path("C:\\Users\\Administrator\\Desktop\\上传整理\\新建文件夹\\0.jpg")
                .build();
        wordImages.add(wordImg1);
        WordImg wordImg2 = WordImg.builder()
                .bookmark("lineImg")
                .type(2)
                .imageBytes(imageBytes)
                .build();
        wordImages.add(wordImg2);
        getPdfByWordTemplate(filePath, outPath, jsonStr, "data", wordImages);
    }
}

文件处理工具类

复制代码
import lombok.Builder;
import lombok.Data;

/**
 *@author pengbenlei
 *@date 2024/12/13 9:37
 *@desc Aspose图片数据
 */
@Data
@Builder
public class WordImg {

    /**
     * 占位书签名
     */
    private String bookmark;

    /**
     * 图片处理类型 1-本地图片 2-imageBytes  3-网络url图片
     */
    private int type;

    /**
     * 图片路径
     */
    private String path;

    /**
     * 图片字节数组
     */
    private byte[] imageBytes;
}

图片

以上就能实现大部分模板替换的业务功能,下面说下模板的设计。

1、一般使用table对word模板布局。

2、占位符和模板语法查阅官方文档,或者看我的截图。

3、图片使用书签占位。

相关推荐
这是个栗子17 分钟前
前端开发中的常用工具函数(八)
开发语言·前端·javascript
凤凰院凶涛QAQ31 分钟前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
研☆香39 分钟前
为什么变量声明在赋值前也能使用?—— 深入理解 JavaScript 变量提升与作用域
开发语言·前端·javascript
右耳朵猫AI1 小时前
PHP周刊2026W28 | 安全更新、Laravel 13.18、Twig 3.28
开发语言·php·laravel
second601 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++
罗政1 小时前
PDF 批量合并工具:本地 AI 自动排序、识别正文日期与合同编号
数据库·pdf·php
郝学胜-神的一滴1 小时前
算法实战:最小k个数——大顶堆的优雅解法
开发语言·数据结构·c++·python·程序人生·算法·排序算法
bksczm1 小时前
linux之线程概念和控制
linux·开发语言·c++
掘金_答案1 小时前
上线那天,一个 ConcurrentHashMap 差点送走我的 AI 客服——3 天排查 JVM 血泪史
java·后端·架构
JackieZhengChina2 小时前
零依赖轻量级JS悬浮提示插件title2tip-js的使用教程
开发语言·javascript·ecmascript