使用poi-tl填充word模板,并转化为pdf输出(兼容word输出)

文章讲述了在后端开发中如何使用XWPFTemplate处理Word文档,包括添加数据、生成二维码以及使用Aspose和thumbnailator库进行Word到PDF的转换,同时展示了依赖管理和文件流操作的相关代码片段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

模板

文字填充

{{text}}

图片填充

{{@image}}

后端

依赖

<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.12.0</version>
</dependency>

Word版本

Word版本填充代码

		// 培训详情
       


        HashMap<String, Object> textMap = new HashMap<>();
        textMap.put("projectNo", projectInitiation.getProjectNo());
        textMap.put("projectName", projectInitiation.getProjectName());
        textMap.put("organization1", organization.getName());
        textMap.put("email", Objects.isNull(user.getEmail()) ? "" : user.getEmail());
        textMap.put("headPhone", Objects.isNull(deviceManage.getHeadPhone()) ? "" : deviceManage.getHeadPhone());
        // 查看培训人员(扫码查看)
        QrConfig config = new QrConfig(300, 300);
        // 设置边距,既二维码和背景之间的边距
        config.setMargin(3);
        HashMap<String, String> qrMap = new HashMap<>();
        qrMap.put("type", RandomUtil.randomString(5));
        qrMap.put("data", AESUtils.encodeBase64(String.valueOf(visitationTask.getId())));
        String qr = QrCodeUtil.generateAsBase64(JsonUtils.objectToJsonString(qrMap), config, ImgUtil.IMAGE_TYPE_JPG);
        textMap.put("detailPages", Pictures.ofBase64(qr, PictureType.JPEG).size(100, 100).create());

        // 选中
        textMap.put("redio", "\u2611");

        textMap.put("customerSignature", Objects.isNull(cultivateDetail.getCustomerSignature()) ? "" : Pictures.ofUrl(cultivateDetail.getCustomerSignature(), PictureType.JPEG).size(100, 50).create());
        textMap.put("engineerSignature", Objects.isNull(cultivateDetail.getEngineerSignature()) ? "" : Pictures.ofUrl(cultivateDetail.getEngineerSignature(), PictureType.JPEG).size(100, 50).create());


        // 获取文件流
        try {
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("template/培训服务报告.docx");
            XWPFTemplate template = XWPFTemplate.compile(inputStream).render(textMap);

            Map<String, Object> map = new HashMap<>();
            ByteArrayOutputStream fos = new ByteArrayOutputStream();
            template.write(fos);
            byte[] bytes = fos.toByteArray();
            byte[] convertToPdf = Doc2PdfUtil.doc2Pdf(bytes);
            String bytesRes = StringUtils.bytesToHexString2(convertToPdf);
            map.put("bytes", bytesRes);
            map.put("title", System.currentTimeMillis() + "培训服务报告.docx");
            fos.close();
            template.close();


            return Response.successJson(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

pdf版本

依赖

		<!--aspose 破解 word转pdf-->
        <dependency>
            <groupId>com.aspose</groupId>
            <artifactId>aspose-words</artifactId>
            <version>16.8.0-jdk16</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/aspose-words-16.8.0-jdk16.jar</systemPath>
        </dependency>

license放到resources下面 license.xml

<License>
    <Data>
        <Products>
            <Product>Aspose.Total for Java</Product>
            <Product>Aspose.Words for Java</Product>
        </Products>
        <EditionType>Enterprise</EditionType>
        <SubscriptionExpiry>20991231</SubscriptionExpiry>
        <LicenseExpiry>20991231</LicenseExpiry>
        <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
    </Data>
    <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>
</License>

word转pdf工具类

package com.gangwantech.web.utils;

import com.aspose.words.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;

public class Doc2PdfUtil {

    /**
     * 加载授权配置文件
     *
     * @return
     */
    private static boolean getLicense() {
        boolean result = false;
        try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("license.xml")) {
            // License的包路径必须为com.aspose.words.License
            License license = new License();
            license.setLicense(in);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * doc转pdf
     *
     * @return
     */
    public static byte[] doc2Pdf(byte[] bytes) {
        System.out.println("pdf转换中...");
        long old = System.currentTimeMillis();

        try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
            // 验证
            if (!getLicense()) {
                throw new RuntimeException("文件转换失败!");
            }
            // 加载字体
            //FontSettings settings = FontSettings.getDefaultInstance();
            //String[] fontFamilyNames = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
            //settings.setFontsFolders(fontFamilyNames, true);
            //LoadOptions loadOptions = new LoadOptions();
            //loadOptions.setFontSettings(settings);

             加载字体
            //FontSettings settings = FontSettings.getDefaultInstance();
            //settings.setFontsFolder("C:\\Windows\\Fonts", true);
            //LoadOptions loadOptions = new LoadOptions();
            //loadOptions.setFontSettings(settings);

            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
            //Document document = new Document(inputStream, loadOptions);
            Document document = new Document(inputStream);

            document.save(fos, SaveFormat.PDF);
            byte[] buffer = fos.toByteArray();
            long now = System.currentTimeMillis();
            System.out.println("pdf转换成功,共耗时:" + ((now - old) / 1000.0) + "秒");
            return buffer;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件转换失败!");
        }
    }
}

pdf版本填充代码,并生成pdf下载

		// 培训详情
        CultivateDetail cultivateDetail = cultivateDetailService.selectOne(new QueryWrapper<CultivateDetail>()
                .eq("work_id", visitationTask.getWorkOrderId())
        );
        
        HashMap<String, Object> textMap = new HashMap<>();
        textMap.put("projectNo", projectInitiation.getProjectNo());
        textMap.put("projectName", projectInitiation.getProjectName());
        // 查看培训人员(扫码查看)
        QrConfig config = new QrConfig(300, 300);
        // 设置边距,既二维码和背景之间的边距
        config.setMargin(3);
        HashMap<String, String> qrMap = new HashMap<>();
        qrMap.put("type", RandomUtil.randomString(5) + "train");
        qrMap.put("data", AESUtils.encodeBase64(String.valueOf(visitationTask.getId())));
        String qr = QrCodeUtil.generateAsBase64(JsonUtils.objectToJsonString(qrMap), config, ImgUtil.IMAGE_TYPE_JPG);
        textMap.put("detailPages", Pictures.ofBase64(qr, PictureType.JPEG).size(100, 100).create());

        // 选中
        textMap.put("redio", "\u2611");

        textMap.put("customerSignature", Objects.isNull(cultivateDetail.getCustomerSignature()) ? "" : Pictures.ofUrl(cultivateDetail.getCustomerSignature(), PictureType.JPEG).size(100, 50).create());
        textMap.put("engineerSignature", Objects.isNull(cultivateDetail.getEngineerSignature()) ? "" : Pictures.ofUrl(cultivateDetail.getEngineerSignature(), PictureType.JPEG).size(100, 50).create());


        // 获取文件流
        try {
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("template/培训服务报告.docx");
            XWPFTemplate template = XWPFTemplate.compile(inputStream).render(textMap);

            Map<String, Object> map = new HashMap<>();
            ByteArrayOutputStream fos = new ByteArrayOutputStream();
            template.write(fos);
            byte[] bytes = fos.toByteArray();
            byte[] convertToPdf = Doc2PdfUtil.doc2Pdf(bytes);
            String bytesRes = StringUtils.bytesToHexString2(convertToPdf);
            map.put("bytes", bytesRes);
            map.put("title", System.currentTimeMillis() + "培训服务报告.docx");
            fos.close();
            template.close();


            return Response.successJson(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

前端下载方法

word下载

		if (res.data.code === 0) {
          const data = res.data.data
          const bytes = hexStr2Byte(data.bytes)
          const blob = new Blob([bytes], {
            type: `application/vnd.openxmlformats-officedocument.wordprocessingml.document`
          })
          const objectUrl = URL.createObjectURL(blob)
          const link = document.createElement('a')
          link.href = objectUrl
          link.setAttribute('download', data.title)
          document.body.appendChild(link)
          link.click()
        } else {
          this.$message.error(res.data.msg)
        }

pdf下载

		  const data = res.data.data
          const bytes = hexStr2Byte(data.bytes)
          const blob = new Blob([bytes], {
            type: `application/pdf`
          })
          const objectUrl = URL.createObjectURL(blob)
          const link = document.createElement('a')
          link.href = objectUrl
          link.setAttribute('download', `${data.title}.pdf`)
          document.body.appendChild(link)
          link.click()
        } else {
          this.$message.error(res.data.msg)
        }

图片旋转

依赖

<!-- 图片旋转 -->
        <dependency>
            <groupId>net.coobird</groupId>
            <artifactId>thumbnailator</artifactId>
            <version>0.4.20</version>
        </dependency>

工具类

package com.gangwantech.web.utils;

import com.aspose.words.*;
import net.coobird.thumbnailator.Thumbnails;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * @Author: LiHuaZhi
 * @Date: 2021/7/13 14:21
 * @Description:
 **/
public class Doc2PdfUtil {

    /**
     * 加载授权配置文件
     *
     * @return
     */
    private static boolean getLicense() {
        boolean result = false;
        try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("license.xml")) {
            // License的包路径必须为com.aspose.words.License
            License license = new License();
            license.setLicense(in);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * doc转pdf
     *
     * @return
     */
    public static byte[] doc2Pdf(byte[] bytes) {
        System.out.println("pdf转换中...");
        long old = System.currentTimeMillis();

        try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
            // 验证
            if (!getLicense()) {
                throw new RuntimeException("文件转换失败!");
            }
            // 加载字体
            //FontSettings settings = FontSettings.getDefaultInstance();
            //String[] fontFamilyNames = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
            //settings.setFontsFolders(fontFamilyNames, true);
            //LoadOptions loadOptions = new LoadOptions();
            //loadOptions.setFontSettings(settings);

             加载字体
            //FontSettings settings = FontSettings.getDefaultInstance();
            //settings.setFontsFolder("C:\\Windows\\Fonts", true);
            //LoadOptions loadOptions = new LoadOptions();
            //loadOptions.setFontSettings(settings);

            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
            //Document document = new Document(inputStream, loadOptions);
            Document document = new Document(inputStream);

            document.save(fos, SaveFormat.PDF);
            byte[] buffer = fos.toByteArray();
            long now = System.currentTimeMillis();
            System.out.println("pdf转换成功,共耗时:" + ((now - old) / 1000.0) + "秒");
            return buffer;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件转换失败!");
        }
    }


    public static BufferedImage rotateUsingThumbnailator(BufferedImage source, double angle) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        // 直接使用Thumbnailator进行旋转操作,并写入到ByteArrayOutputStream
        Thumbnails.of(source)
                .scale(1.0)
                .rotate(angle)
                .outputFormat("PNG") // 根据需要可更改输出格式
                .toOutputStream(baos);

        // 由于ByteArrayOutputStream是内存流,不需要关闭

        // 使用ByteArrayInputStream读取处理后的字节数组并转换为BufferedImage
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());

        try {
            return ImageIO.read(bais);
        } finally {
            bais.close(); // 关闭ByteArrayInputStream
        }
    }
}

public static byte[] rotateUsingThumbnailatorPng(String urlAddress, double angle) throws IOException {
        URL url = new URL(urlAddress);
        BufferedImage originalImage = ImageIO.read(url);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        // 直接使用Thumbnailator进行旋转操作,并写入到ByteArrayOutputStream
        Thumbnails.of(originalImage)
                .scale(1.0)
                .rotate(angle)
                .outputFormat("PNG") // 根据需要可更改输出格式
                .toOutputStream(baos);

        // 由于ByteArrayOutputStream是内存流,不需要关闭

        // 使用ByteArrayInputStream读取处理后的字节数组并转换为BufferedImage
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());

        try {
            BufferedImage read = ImageIO.read(bais);
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            ImageIO.write(read, "PNG", os); // 注意这里是写为PNG格式,根据实际情况可以调整为JPEG等其他格式
            byte[] imageBytes = os.toByteArray();
            return imageBytes;
        } finally {
            bais.close(); // 关闭ByteArrayInputStream
        }
    }

旋转图片,然后填充的代码

if (StringUtils.isNotBlank(cultivateDetail.getEngineerSignature())) {
	byte[] bytes = Doc2PdfUtil.rotateUsingThumbnailatorPng(cultivateDetail.getEngineerSignature(), -90.0);
	textMap.put("engineerSignature", Pictures.ofBytes(bytes, PictureType.PNG).size(100, 70).create());
}
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值