java使用freemarker完美导出word文档(带图)

本文介绍了如何使用Java的Freemarker模板引擎来生成包含图片的Word(docx)文档。通过将Word文件转换为XML,用Freemarker进行内容渲染,然后将图片转换为base64格式插入。特别强调了docx格式的本质是ZIP压缩包,并提供了文件结构和关键步骤,包括对`[Content_Types].xml`的修改以及在`word`文件夹内的操作。文章还提及了SpringBoot中集成Freemarker的相关配置和Java工具类的使用。

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

poi
java2word
freemarker
最后选用freemarker,为什么呢?业务需要。
生成doc格式,比较简单,这里就不列举了,网上有大量的例子
生成思路大概就是保存一个doc文件,改后缀位xml,占位符去渲染。其中图片转换成base64格式。
这里主要讲docx格式。测试环境office 2013 2016

特殊符号需要转义,否则报错

参考文档 https://my.oschina.net/u/3737136/blog/2958421

docx格式本质上是个zip压缩包。

  1. 新建docx文件,插入自己需要的格式,如图
    在这里插入图片描述
  2. 修改后缀为zip
    [Content_Types].xml
    如果需要插图,需要修改此文件,这里以jpg图片为例,
    插入图片word转为jpeg,建议图片修改jpg为jepg
    如果插入其他格式在此文件夹添加对应的说明
    在这里插入图片描述
    在这里插入图片描述
    3.打开word文件夹,主要改动也是在这里
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    注意: <pic:cNvPr id=“1” name=“图片 1”/> 中的id最好使用数字,前面使用的字符串出现打开文件弹错误的情况
    =====================================================================
    干货来了

目录结构
在这里插入图片描述

springboot maven引入freemarker

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

freemarker相关配置
application.yml
这里就不啰嗦了

spring:
  freemarker:
    charset: UTF-8
    suffix: .html
    template-loader-path: /templates
    content-type: text/html; charset=utf-8

java 工具类

import java.io.*;
import java.util.Date;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import freemarker.core.ParseException;
import freemarker.template.Configuration;
import freemarker.template.MalformedTemplateNameException;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateNotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * @Description: word工具类
 * @Auther: simp
 * @Date: 2020/11/27 11:18
 * @Version: 1.0
 */
@Slf4j
@Component
public class WordUtils {
   

    private static final String path = "/project/upload/doc/";

    public static Configuration getConfiguration() {
   
        Configuration config = new Configuration(Configuration.VERSION_2_3_28);
        config.setDefaultEncoding("utf-8");
        config.setClassForTemplateLoading(WordUtils.class, "/templates");
        config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
        return config;
    }
    /**
     * FreeMarker生成Word
     * @param dataMap 数据
     * @param templateName 目标名
     */
    public static ByteArrayInputStream createXml(JSONObject dataMap, String templateName) {
   
        Template template = null;
        ByteArrayInputStream in = null;
        if(templateName.endsWith(".html")) {
   
            templateName = templateName.substring(0, templateName.indexOf(".html"));
        }
        try {
   
            template = getConfiguration().getTemplate(templateName + ".html");
        } catch (TemplateNotFoundException e) {
   
            e.printStackTrace();
        } catch (MalformedTemplateNameException e) {
   
            e.printStackTrace();
        } catch (ParseException e) {
   
            e.printStackTrace();
        } catch (IOException e) {
   
            e.printStackTrace();
        }
        StringWriter out = new StringWriter();
        try {
   
            template.process(dataMap, out);
            in = new ByteArrayInputStream(out.toString().getBytes("utf-8"));//这里一定要设置utf-8编码 否则导出的word中中文会是乱码
        } catch (TemplateException e) {
   
            e.printStackTrace();
        } catch (IOException e) {
   
            e.printStackTrace();
        }
        try {
   
            out.close();
        } catch (IOException e) {
   
            e.printStackTrace();
        }
        return in;
    }

    public static String exportWord(String report) {
   
        JSONObject jsonObject = JSONObject.parseObject(report);
        Date date = new Date(Long.parseLong(jsonObject.getString("time")));
        String docName = new StringBuffer()
                .append(DateUtil.format(date, "yyyyMMddHHmmss"))
                .append("_")
                .append(jsonObject.getString("taskName"))
                .append(".docx").toString();
        String saveFilePath = path + docName;
        String time = DateUtil.format(date, "yyyy/MM/dd HH:mm:ss");
        jsonObject.put("time", time);
        JSONArray stepInfos = jsonObject.getJSONArray("stepInfos");
        JSONArray images = new JSONArray();
        int count = 10;
        for (Object item : stepInfos) {
   
            JSONObject step = (JSONObject) item;
            if (step.containsKey("images")) {
   
                JSONArray list = step.getJSONArray("images");
                for (Object it : list) {
   
                    JSONObject image = (JSONObject) it;
                    if (image.containsKey("path")) {
   
                        image.put("id", count);
                        image.put("embed", "rId" + count);
                        image.put("name", "图片 " + count);
                        String path = image.getString("path");
                        String ext = path.substring(path.lastIndexOf("."));
                        ext = ".jpg".equals(ext) ? ".jpeg" : ext;
                        JSONObject imageJson = new JSONObject();
                        imageJson.put("embed", image.getString("embed"));
                        imageJson.put("id", image.getString("id"));
                        imageJson.put("ext", ext);
                        imageJson.put("name", "image" + count + ext);
                        try {
   
                            FileInputStream fileIn = new FileInputStream(image.getString("path"));
                            imageJson.put("code", fileIn);
                        } catch (Exception e) {
   

                        }
                        images.add(imageJson);
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

残缘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值