1. 生成 WORD

1.1 maven 依赖

<!-- Word 模板引擎 -->
<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.10.5</version>
</dependency>
​
<!-- Aspose Word文档控件 -->
<dependency>
    <groupId>com.luhuiguo</groupId>
    <artifactId>aspose-words</artifactId>
    <version>23.1</version>
</dependency>

1.2 Word 工具类

import com.aspose.words.*;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.util.PoitlIOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
​
/**
 * Word工具类
 *
 * @author mobingc
 * @date 2024-04-18
 */
@SuppressWarnings("unused")
public class WordUtils {
​
    private static final Logger log = LoggerFactory.getLogger(WordUtils.class);
​
    /**
     * 生成 Word 输入流
     *
     * @param templateClassPath Word 模板文件路径
     * @param model             需要填充的数据映射模型
     * @return Excel 输入流
     */
    public static InputStream generate2Input(String templateClassPath, Object model) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = WordUtils.generate(templateClassPath, model);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }
​
    /**
     * 生成 Word 输入流
     *
     * @param templateInput Word 模板输入流
     * @param model         需要填充的数据映射模型
     * @return Excel 输入流
     */
    public static InputStream generate2Input(InputStream templateInput, Object model) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = WordUtils.generate(templateInput, model);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }
​
    /**
     * 生成 Word 输入流
     *
     * @param templateClassPath Word 模板文件路径
     * @param config            配置
     * @param model             需要填充的数据映射模型
     * @return Excel 输入流
     */
    public static InputStream generate2Input(String templateClassPath, Configure config, Object model) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = WordUtils.generate(templateClassPath, config, model);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }
​
    /**
     * 生成 Word 输入流
     *
     * @param templateInput Word 模板输入流
     * @param config        配置
     * @param model         需要填充的数据映射模型
     * @return Excel 输入流
     */
    public static InputStream generate2Input(InputStream templateInput, Configure config, Object model) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = WordUtils.generate(templateInput, config, model);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }
​
    /**
     * 生成 Word 字节输出流
     *
     * @param templateClassPath Word 模板文件路径
     * @param model             需要填充的数据映射模型
     * @return Word 字节输出流
     */
    public static ByteArrayOutputStream generate(String templateClassPath, Object model) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        WordUtils.generate(templateClassPath, byteArrayOutputStream, null, model);
        return byteArrayOutputStream;
    }
​
    /**
     * 生成 Word 字节输出流
     *
     * @param templateInput Word 模板输入流
     * @param model         需要填充的数据映射模型
     * @return Word 字节输出流
     */
    public static ByteArrayOutputStream generate(InputStream templateInput, Object model) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        WordUtils.generate(templateInput, byteArrayOutputStream, null, model);
        return byteArrayOutputStream;
    }
​
    /**
     * 生成 Word 字节输出流
     *
     * @param templateClassPath Word 模板文件路径
     * @param config            配置
     * @param model             需要填充的数据映射模型
     * @return Word 字节输出流
     */
    public static ByteArrayOutputStream generate(String templateClassPath, Configure config, Object model) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        WordUtils.generate(templateClassPath, byteArrayOutputStream, config, model);
        return byteArrayOutputStream;
    }
​
    /**
     * 生成 Word 字节输出流
     *
     * @param templateInput Word 模板输入流
     * @param model         需要填充的数据映射模型
     * @return Word 字节输出流
     */
    public static ByteArrayOutputStream generate(InputStream templateInput, Configure config, Object model) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        WordUtils.generate(templateInput, byteArrayOutputStream, config, model);
        return byteArrayOutputStream;
    }
​
    /**
     * 生成 Word
     *
     * @param templateClassPath Word 模板文件路径
     * @param output            Word 输出流
     * @param model             需要填充的数据映射模型
     */
    public static void generate(String templateClassPath, OutputStream output, Object model) throws IOException {
        WordUtils.generate(templateClassPath, output, null, model);
    }
​
    /**
     * 生成 Word
     *
     * @param templateInput Word 模板输入流
     * @param output        Word 输出流
     * @param model         需要填充的数据映射模型
     */
    public static void generate(InputStream templateInput, OutputStream output, Object model) throws IOException {
        WordUtils.generate(templateInput, output, null, model);
    }
​
    /**
     * 生成 Word
     *
     * @param templateClassPath Word 模板文件路径
     * @param output            Word 输出流
     * @param config            配置
     * @param model             需要填充的数据映射模型
     */
    public static void generate(String templateClassPath, OutputStream output, Configure config, Object model) throws IOException {
        InputStream templateInputStream = WordUtils.class.getClassLoader().getResourceAsStream(templateClassPath);
        WordUtils.generate(templateInputStream, output, config, model);
        PoitlIOUtils.closeQuietly(templateInputStream);
    }
​
    /**
     * 生成 Word
     *
     * @param templateInput Word 模板输入流
     * @param output        Word 输出流
     * @param config        配置
     * @param model         需要填充的数据映射模型
     */
    public static void generate(InputStream templateInput, OutputStream output, Configure config, Object model) throws IOException {
        try (XWPFTemplate template = (config == null) ? XWPFTemplate.compile(templateInput) : XWPFTemplate.compile(templateInput, config)) {
            template.render(model).writeAndClose(output);
        }
    }
​
    /**
     * 合并 word
     *
     * @param inputStreamList word 文件输入流集合
     * @param outputStream    输出的 word 文件数据流
     */
    public static void appendMerge(List<InputStream> inputStreamList, OutputStream outputStream) throws Exception {
        log.info("合并 word 文件...");
        long startTime = System.currentTimeMillis();
        Document document = new Document();
        DocumentBuilder documentBuilder = new DocumentBuilder(document);
        for (int i = 0; i < inputStreamList.size(); i++) {
            Document sourceDocument = new Document(inputStreamList.get(i));
            documentBuilder.moveToDocumentEnd();
            documentBuilder.insertDocument(sourceDocument, ImportFormatMode.KEEP_SOURCE_FORMATTING);
            log.info("合并 word 文件:{}/{}", i + 1, inputStreamList.size());
        }
        log.info("合并 word 完成,耗时:{}ms", System.currentTimeMillis() - startTime);
        document.save(outputStream, SaveFormat.DOCX);
    }
​
    /**
     * word 转换为 pdf
     *
     * @param wordInput word 文件输入流
     * @param pdfOutput pdf 文件输出流
     */
    public static void wordToPDF(InputStream wordInput, OutputStream pdfOutput) throws Exception {
        log.info("开始转换 word 文件为 pdf 文件...");
        long startTime = System.currentTimeMillis();
        Document wordDoc = new Document(wordInput);
        PdfSaveOptions pso = new PdfSaveOptions();
        wordDoc.save(pdfOutput, pso);
        log.info("转换完成,耗时:{}ms", System.currentTimeMillis() - startTime);
    }
​
    /**
     * 模板 word 转换为 pdf
     *
     * @param templateClassPath 模板文件 classpath
     * @param pdfOutput         输出的 pdf 数据流
     * @param config            配置
     * @param model             需要替换的数据映射模型
     */
    public static void templateWordToPDF(String templateClassPath, OutputStream pdfOutput, Configure config, Object model) throws Exception {
        InputStream inputStream = WordUtils.generate2Input(templateClassPath, config, model);
        WordUtils.wordToPDF(inputStream, pdfOutput);
        PoitlIOUtils.closeQuietly(inputStream);
    }
​
    /**
     * 获取列表配置
     *
     * @return 列表配置
     */
    public static Configure getConfigureByList(Object model) throws Exception {
        ConfigureBuilder configureBuilder = Configure.builder();
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        if (model instanceof Map) {
            Map<?, ?> modelMap = (Map<?, ?>) model;
            if (!modelMap.isEmpty()) {
                for (Map.Entry<?, ?> entry : modelMap.entrySet()) {
                    Object value = entry.getValue();
                    if (!(value instanceof Collection)) {
                        continue;
                    }
                    Collection<?> collection = (Collection<?>) value;
                    if (!collection.isEmpty() && isBaseTypeCollection(collection)) {
                        continue;
                    }
                    configureBuilder.bind(entry.getKey().toString(), policy);
                }
            }
        } else {
            Class<?> clazz = model.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                Class<?> type = field.getType();
                if (Collection.class.isAssignableFrom(type)) {
                    Method method = clazz.getMethod("get" + StringUtils.capitalize(field.getName()));
                    Collection<?> collection = (Collection<?>) method.invoke(model);
                    if (collection != null && !collection.isEmpty() && isBaseTypeCollection(collection)) {
                        continue;
                    }
                    configureBuilder.bind(field.getName(), policy);
                }
            }
        }
        return configureBuilder.build();
    }
​
    /**
     * 判断集合类型是否为基础类型
     *
     * @param collection 集合
     */
    private static boolean isBaseTypeCollection(Collection<?> collection) {
        Object item = collection.iterator().next();
        Class<?> itemClass = item.getClass();
        String itemTypeName = itemClass.getTypeName();
        return itemTypeName.startsWith("java.lang.");
    }
​
}

1.3 基本用法

1.3.1 配置模板
  • 标签,以{{开头,以}}结尾

    日期:{{date}}
  • 列表,在列表表头加上列表数据标签,次行以[开头,以]结尾表示属性

    {{users}}姓名

    性别

    年龄

    [name]

    [sex]

    [age]

  • 更多:https://deepoove.com/poi-tl/

1.3.2 生成文件
public static void main(String[] args) throws Exception {
​
    // 创建文件获取文件输出流
    String rootDir = System.getProperty("user.dir");
    File file = new File(rootDir + "/output/test.docx");
    if (file.createNewFile()) {
        System.out.println("创建文件成功");
    }
    OutputStream outputStream = new FileOutputStream(file);
​
    // 构造数据
    Map<String, Object> data = new HashMap<>();
    data.put("date", "2024-07-29");
    Map<String, Object> user = new HashMap<>();
    user.put("name", "张三");
    user.put("sex", "男");
    user.put("age", 20);
    data.put("users", Collections.singletonList(user));
​
    // 获取列表配置(若数据中不包含列表可省略)
    Configure config = WordUtils.getConfigureByList(data);
​
    // 模板路径(resource目录下)
    String templateClassPath = "template/测试.docx";
    // 生成 word
    WordUtils.generate(templateClassPath, outputStream, config, data);
    
    // 多个 Word 合并
    //List<InputStream> list = new ArrayList<>();
    //WordUtils.appendMerge(list, outputStream);
}

2. 生成 PDF

  • 通过生成 Word 的方法生成 Word

  • 将 Word 转化为 pdf

public static void main(String[] args) throws Exception {
​
    // 创建文件获取文件输出流
    String rootDir = System.getProperty("user.dir");
    File file = new File(rootDir + "/output/test.pdf");
    if (file.createNewFile()) {
        System.out.println("创建文件成功");
    }
    OutputStream outputStream = new FileOutputStream(file);
​
    // 构造数据
    Map<String, Object> data = new HashMap<>();
    data.put("date", "2024-07-29");
    Map<String, Object> user = new HashMap<>();
    user.put("name", "张三");
    user.put("sex", "男");
    user.put("age", 20);
    data.put("users", Collections.singletonList(user));
​
    // 获取列表配置(若数据中不包含列表可省略)
    Configure config = WordUtils.getConfigureByList(data);
​
    // 生成 word 并转化为 pdf
    InputStream inputStream = WordUtils.generate2Input("template/测试.docx", config, data);
    WordUtils.wordToPDF(inputStream, outputStream);
}

3. 生成 EXCEL

3.1 maven 依赖

<!-- EasyExcel 工具 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.3</version>
</dependency>
​
<!-- Aspose Excel表格控件 -->
<dependency>
    <groupId>com.luhuiguo</groupId>
    <artifactId>aspose-cells</artifactId>
    <version>23.1</version>
</dependency>

3.2 Excel 工具类

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.aspose.cells.*;
import com.deepoove.poi.util.PoitlIOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
​
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
​
/**
 * Excel 工具类
 *
 * @author mobingc
 * @date 2024-04-18
 */
@SuppressWarnings("unused")
public class ExcelUtils {
​
    private static final Logger log = LoggerFactory.getLogger(ExcelUtils.class);
​
    /**
     * 生成 Excel 输入流
     *
     * @param templateClassPath Excel 模板文件路径
     * @param data              Excel 模板填充数据
     * @return Excel 输入流
     */
    public static InputStream generate2Input(String templateClassPath, Map<String, Object> data) {
        ByteArrayOutputStream byteArrayOutputStream = ExcelUtils.generate(templateClassPath, data);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }
​
    /**
     * 生成 Excel 输入流
     *
     * @param templateInput Excel 模板输入流
     * @param data          Excel 模板填充数据
     * @return Excel 输入流
     */
    public static InputStream generate2Input(InputStream templateInput, Map<String, Object> data) {
        ByteArrayOutputStream byteArrayOutputStream = ExcelUtils.generate(templateInput, data);
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }
​
    /**
     * 生成 Excel 字节输出流
     *
     * @param templateClassPath Excel 模板文件路径
     * @param data              Excel 模板填充数据
     * @return Excel 字节输出流
     */
    public static ByteArrayOutputStream generate(String templateClassPath, Map<String, Object> data) {
        InputStream templateInputStream = ExcelUtils.class.getClassLoader().getResourceAsStream(templateClassPath);
        ByteArrayOutputStream byteArrayOutputStream = generate(templateInputStream, data);
        PoitlIOUtils.closeQuietly(templateInputStream);
        return byteArrayOutputStream;
    }
​
    /**
     * 生成 Excel 字节输出流
     *
     * @param templateInput Excel 模板输入流
     * @param data          Excel 模板填充数据
     * @return Excel 字节输出流
     */
    public static ByteArrayOutputStream generate(InputStream templateInput, Map<String, Object> data) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ExcelUtils.generate(templateInput, byteArrayOutputStream, data);
        return byteArrayOutputStream;
    }
​
    /**
     * 生成 Excel
     *
     * @param templateClassPath Excel 模板文件路径
     * @param output            Excel 输出流
     * @param data              Excel 模板填充数据
     */
    public static void generate(String templateClassPath, OutputStream output, Map<String, Object> data) {
        InputStream templateInputStream = ExcelUtils.class.getClassLoader().getResourceAsStream(templateClassPath);
        ExcelUtils.generate(templateInputStream, output, data);
        PoitlIOUtils.closeQuietly(templateInputStream);
    }
​
    /**
     * 生成 Excel
     *
     * @param templateInput Excel 模板输入流
     * @param output        Excel 输出流
     * @param data          Excel 模板填充数据
     */
    public static void generate(InputStream templateInput, OutputStream output, Map<String, Object> data) {
        try (ExcelWriter excelWriter = EasyExcel
                .write(output)
                .withTemplate(templateInput)
                .build()) {
            log.info("生成 excel 文件...");
            long startTime = System.currentTimeMillis();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            Map<String, Object> baseData = new HashMap<>();
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if (value instanceof List) {
                    excelWriter.fill(new FillWrapper(key, (List<?>) value), writeSheet);
                    continue;
                }
                baseData.put(key, value);
            }
            excelWriter.fill(baseData, writeSheet);
            excelWriter.finish();
            log.info("生成 excel 完成,耗时:{}ms", System.currentTimeMillis() - startTime);
        }
    }
​
    /**
     * 合并 Excel
     *
     * @param inputList Excel 输入流列表
     * @param output    Excel 输出流
     */
    public static void merge(List<InputStream> inputList, OutputStream output) throws Exception {
        log.info("合并 excel 文件...");
        long startTime = System.currentTimeMillis();
        WriteSheet writeSheet = EasyExcel.writerSheet().build();
        Workbook workbook = new Workbook(inputList.get(0));
        Worksheet workSheet = workbook.getWorksheets().get(0);
        Cells workSheetCells = workSheet.getCells();
        int totalRowCount = workSheetCells.getMaxDisplayRange().getRowCount();
        for (int i = 1; i < inputList.size(); ++i) {
            Workbook tmpWorkbook = new Workbook(inputList.get(i));
            Worksheet tmpSheet = tmpWorkbook.getWorksheets().get(0);
            Range sourceRange = tmpSheet.getCells().getMaxDisplayRange();
            int sourceFirstRow = sourceRange.getFirstRow() + totalRowCount;
            int sourceFirstColumn = sourceRange.getFirstColumn();
            int sourceTotalRows = sourceRange.getRowCount();
            int sourceTotalColumns = sourceRange.getColumnCount();
            Range destRange = workSheetCells.createRange(sourceFirstRow, sourceFirstColumn, sourceTotalRows, sourceTotalColumns);
            destRange.copy(sourceRange);
            totalRowCount += sourceRange.getRowCount();
            log.info("合并 excel 文件:{}/{}", i + 1, inputList.size());
        }
        log.info("合并 excel 完成,耗时:{}ms", System.currentTimeMillis() - startTime);
        workbook.save(output, new XlsSaveOptions(SaveFormat.XLSX));
    }
​
}

3.3 基本用法

3.3.1 配置模板
3.3.2 生成文件
public static void main(String[] args) throws Exception {
​
    // 创建文件获取文件输出流
    String rootDir = System.getProperty("user.dir");
    File file = new File(rootDir + "/output/test.xlsx");
    if (file.createNewFile()) {
        System.out.println("创建文件成功");
    }
    OutputStream outputStream = new FileOutputStream(file);
​
    // 构造数据
    Map<String, Object> data = new HashMap<>();
    data.put("date", "2024-07-29");
    Map<String, Object> user = new HashMap<>();
    user.put("name", "张三");
    user.put("sex", "男");
    user.put("age", 20);
    data.put("users", Collections.singletonList(user));
​
    // 模板路径(resource目录下)
    String templateClassPath = "template/测试.xlsx";
    // 生成 excel
    ExcelUtils.generate(templateClassPath, outputStream, data);
    
    // 多个 Excel 合并
    //List<InputStream> list = new ArrayList<>();
    //ExcelUtils.merge(list, outputStream);
}