栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java根据word模板生成word文件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java根据word模板生成word文件

1.简介

处理word的方式有许多种:

  1. 使用Hutool工具类,但是只能处理简单的word,不能处理表格,动态图片,替换文字等
  2. 使用Apache POI,可以处理复杂的Word文档,但是处理过程复杂,word转xml,xml再转ftl才可进行操作,不适合经常处理word
  3. 其他第三方工具
  4. XDocReport +FreeMarker,该技术组合既简单又高效可实现word模板的编辑,docx和doc均可处理

本文将实现动态文本替换、动态图片替换、动态表格填充。

2.pom引入

     fr.opensagres.xdocreport
     fr.opensagres.xdocreport.core
     2.0.2


     fr.opensagres.xdocreport
     fr.opensagres.xdocreport.document
     2.0.2


      fr.opensagres.xdocreport
      fr.opensagres.xdocreport.template
      2.0.2


     fr.opensagres.xdocreport
     fr.opensagres.xdocreport.document.docx
     2.0.2


      fr.opensagres.xdocreport
      fr.opensagres.xdocreport.template.freemarker
      2.0.2


     org.freemarker
     freemarker
     2.3.23

3.动态文本替换

比如说我们有个邮件word模板,需要动态的在横线处填入相关信息,然后生成完整的word文档。

我们做以下操作:

  1. 将横线位置替换成域
  2. 给每个要替换的位置取个名字
  3. FreeMarker域格式为—— ${……}

代码实现

import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;


public class WordTemplate {

    private static final Logger logger = LoggerFactory.getLogger(WordTemplate.class);

    public static void test() {
        InputStream ins = null;
        OutputStream out = null;
        try {

            //获取Word模板,模板存放路径
            ins = new FileInputStream("C:\Users\she52\Desktop\演示.docx");
            //注册xdocreport实例并加载FreeMarker模板引擎
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins, TemplateEngineKind.Freemarker);
            //创建xdocreport上下文对象,用于存放具体数据
            IContext context = report.createContext();


            //创建要替换的文本变量
            context.put("name", "李梅");
            context.put("sendName", "张三");
            context.put("year", "2022");
            context.put("month", "08");
            context.put("day", "03");


            //输出到本地目录
            String filePath = "C:\Users\she52\Desktop\结果.docx";
            out = new FileOutputStream(new File(filePath));
            report.process(context, out);

        } catch (Exception e) {
            logger.info("生成word发生异常", e);
        } finally {
            try {
                if (ins != null){
                    ins.close();
                }
                if (out != null){
                    out.close();
                }
            } catch (IOException e) {
                logger.info("文件流关闭失败", e);
            }
        }
    }
}

注意,执行代码时要把word模板关掉,否则模板加载不成功,会报错

执行结果:

4.动态表格

如果表格是标准的几行几列的列表,使用以下方法。如果不是标准的,比如说合并单元格,则需要使用上 面文本替换的方法,挨个起名赋值。

我们做以下操作:

  1. 除了标题行,保留一行空白行,删掉其余的空白行(为什么这么做,因为表格填充,本质是列表循环填写,列表大小是不确定的,我们只保留一行,让它自己根据列表大小创建行数)
  2. 起一个列表名,比如上面的示例表是用户信息表,则起名为userInfo
  3. 对用户信息属性挨个起名,姓名name、年龄age、性别sex
  4. 第2和第3步骤,等同于新建一个Java实体类
  5. 添加域,命名规范----- u s e r I n f o . n a m e 、 {userInfo.name}、 userInfo.name、{userInfo.age}、${userInfo.sex},自己总结规律
  6. 修改完后记得保存,然后关闭word

代码实现:

import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;


public class WordTemplate {

    private static final Logger logger = LoggerFactory.getLogger(WordTemplate.class);

    public static void test() {
        InputStream ins = null;
        OutputStream out = null;
        try {

            //获取Word模板,模板存放路径
            ins = new FileInputStream("C:\Users\she52\Desktop\演示.docx");
            //注册xdocreport实例并加载FreeMarker模板引擎
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins, TemplateEngineKind.Freemarker);
            //创建xdocreport上下文对象,用于存放具体数据
            IContext context = report.createContext();

            //创建要替换的文本变量
            List userInfos = new ArrayList<>();
            UserInfo userInfo = new UserInfo();
            userInfo.setName("张三");
            userInfo.setAge("15");
            userInfo.setSex("男");
            userInfos.add(userInfo);
            UserInfo userInfo1 = new UserInfo();
            userInfo1.setName("李四");
            userInfo1.setAge("14");
            userInfo1.setSex("男");
            userInfos.add(userInfo1);
            UserInfo userInfo2 = new UserInfo();
            userInfo2.setName("李梅");
            userInfo2.setAge("16");
            userInfo2.setSex("女");
            userInfos.add(userInfo2);
            
            //此处的userInfo是word中命名的列表名
            context.put("userInfo", userInfos);

            //创建字段元数据
            FieldsMetadata fm = report.createFieldsMetadata();
            //Word模板中的表格数据对应的集合类型
            fm.load("userInfo", UserInfo.class, true);

            //输出到本地目录
            String filePath = "C:\Users\she52\Desktop\结果.docx";
            out = new FileOutputStream(new File(filePath));
            report.process(context, out);

        } catch (Exception e) {
            logger.info("生成word发生异常", e);
        }finally {
            try {
                if (ins != null){
                    ins.close();
                }
                if (out != null){
                    out.close();
                }
            } catch (IOException e) {
                logger.info("文件流关闭失败", e);
            }
        }
    }
}

@Data
public class UserInfo{
    
    private String name;
    
    private String age;
    
    private String sex;
}

执行结果

注意,代码中创建的UserInfo实体类必须是public公共的,否则赋不到值

5.动态图片

比如说word文档中有,勾选框, 同意则打对勾。我们可以将勾选框变成图片,再令准备一张打好对勾的图片,如果勾选则将其替换,否则不替换,就可以完美解决勾选问题。

做以下操作:

  1. 将勾选的圆圈替换成大小相同的图片,可以让UI帮忙整一个
  2. 给图片添加标签并命名,直接写名字就行,不用加${}

代码实现:

import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.images.ByteArrayImageProvider;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;


public class WordTemplate {

    private static final Logger logger = LoggerFactory.getLogger(WordTemplate.class);

    public static void test() {

        InputStream in = null;
        OutputStream out = null;
        FileInputStream fins = null;
        try {
            //获取Word模板,模板存放路径
            in = new FileInputStream("C:\Users\she52\Desktop\演示.docx");
            //注册xdocreport实例并加载FreeMarker模板引擎
            IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in, TemplateEngineKind.Freemarker);
            //创建xdocreport上下文对象,用于存放具体数据
            IContext context = report.createContext();

            //图片元数据
            FieldsMetadata metadata = report.createFieldsMetadata();
            //读取对勾圆形图片
            fins = new FileInputStream(new File("C:Usersshe52DesktophookRound.png"));
            
            metadata.addFieldAsImage("accept");
            //只在同意上打对勾,不同意那个图片则不用管
            context.put("accept", new ByteArrayImageProvider(fins));
            
            report.setFieldsMetadata(metadata);

            //输出到本地目录
            String filePath = "C:\Users\she52\Desktop\结果.docx";
            out = new FileOutputStream(new File(filePath));
            report.process(context, out);

        } catch (Exception e) {
            logger.info("生成word发生异常", e);
        }finally {
            try {
                if (in != null){
                    in.close();
                }
                if(fins != null){
                    fins.close();
                }
                if(out != null){
                    out.close();
                }
            } catch (IOException e) {
                logger.info("文件流关闭失败",e);
            }

        }
    }
}

运行结果:

注意

  1. 读取图片大多人用IImageProvider image = FileImageProvider(new File(……));但是这种方式,文件流不能关闭,所以用ByteArrayImageProvider(new FileInputStream())可及时关闭InputStream流。

  2. 如果word有多个地方需要不同的动态图片,可以挨个对图片添加书签并命名,然后重复以下代码

fins = new FileInputStream(new File("C:Usersshe52Desktopimage1.png"));
metadata.addFieldAsImage("image1");
context.put("image1", new ByteArrayImageProvider(fins));
6.总结

如果Word模板文件复杂,则融合上面三种方法,即可满足绝大部分需求,如果满足不了,百度吧__

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1036918.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号