使用FreeMarker,导出Word或者Excel

需求:给定Word模板,完成数据的单个导出 或者批量导出,不需要携带图片。

Word模板

Word模板如下 我们把需要填充内容的地方打上标记,并添加分页符,保证之后在填充的时候每一页只有一条记录,如下图所示。

Freemarker需要使用xml文件,我们将Word另存为xml文件,如下图所示。

另存后的xml内容是压缩过的,我们可以通过在线XML格式化。另存之后记得检查一下${xxx},有时候Word看着是正常的,但是转为xml格式之后,${xxx}有可能就分家了。

然后我们需要对xml文件进行处理,用来接收数据列表。

  1. 定位到<w:body>标签,输入<#list elems as elem>,其中elems为集合,elem为集合中的一个对象
  1. 定位到<w:sectPr>,差不多就是分页符结束的地方,我们添加上闭合标签</#list>

使用FreeMarker填充模板

引入Maven坐标

.xml 复制代码
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

实体类:最好不要用内部类,因为FreeMarker会访问实体类的get方法,如果访问不到会报错的。

java 复制代码
import lombok.Data;

@Data
public class TestInfo {
    private String name;
    private String sex;
    private String idCard;
    private String year;
    private String month;
    private String day;
    private String title;
    private String checkName;
}

填充模板并生成文件

java 复制代码
public class Test01 {
    public static void main(String[] args) {
        List<TestInfo> testData = new ArrayList<>();
        // 第一组测试数据
        TestInfo info1 = new TestInfo();
        info1.setName("张三");
        info1.setSex("男");
        info1.setIdCard("110101199003071234");
        info1.setYear("1990");
        info1.setMonth("03");
        info1.setDay("07");
        info1.setTitle("软件工程师");
        info1.setCheckName("李四");
        testData.add(info1);
        downloadFile(testData);
    }

    public static void downloadFile(List<TestInfo> detail) {
        Map<String, Object> data = new HashMap<>();
        data.put("elems", detail);
        // 预加载模板文件
        File xmlFile = new File("D:\test01.xml");
        InputStream templateStream = null;
        try {
            templateStream = new FileInputStream(xmlFile);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        try {
            Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
            cfg.setDirectoryForTemplateLoading(xmlFile.getParentFile());
            cfg.setDefaultEncoding("UTF-8");
            Template template = cfg.getTemplate(xmlFile.getName());
            // 4. 加载模板并生成文件
            File outputFile = new File("D:\testfile" + System.currentTimeMillis() + ".docx");
            try (Writer out = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(outputFile.toPath()), StandardCharsets.UTF_8))) {
                template.process(data, out);
            }
        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭 InputStream
            try {
                templateStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

导出效果:

填充模板并写入响应体返回给前端

可以参考这个,先创建一个填充好的临时文件,返回给前端后,将临时文件删除。

java 复制代码
// 创建临时文件
File tempFile = null;
try {
    tempFile = File.createTempFile(fileName, ".xml");
    Files.copy(templateStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
    throw new RuntimeException(e);
}
try {
    Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
    cfg.setDirectoryForTemplateLoading(tempFile.getParentFile());
    cfg.setDefaultEncoding("UTF-8");

    // 3. 设置响应头信息
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    response.setHeader("Content-Disposition", "attachment;");
    response.setCharacterEncoding("UTF-8");
    // 4. 加载模板并生成文件
    Template template = cfg.getTemplate(tempFile.getName());
    Writer out = response.getWriter();
    template.process(data, out);
} catch (IOException | TemplateException e) {
    throw new RuntimeException(e);
} finally {
    // 关闭 InputStream
    try {
        templateStream.close();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    tempFile.delete();
}

写在最后:导出Excel的方法,和这个差不多,有空可以试一试

相关推荐
天若有情67317 分钟前
Spring Boot 前后端联调3大经典案例:从入门到实战(通俗易懂版)
spring boot·后端·状态模式
BD_Marathon20 分钟前
SpringBoot——配置文件格式
java·spring boot·后端
幽络源小助理26 分钟前
SpringBoot+小程序高校素拓分管理系统源码 – 幽络源免费分享
spring boot·后端·小程序
程序员爱钓鱼27 分钟前
Node.js 编程实战:测试与调试 —— 日志与监控方案
前端·后端·node.js
雄大31 分钟前
使用 QWebChannel 实现 JS 与 C++ 双向通信(超详细 + 踩坑总结 + Demo)
后端
计算机学姐33 分钟前
基于SpringBoot的汉服租赁系统【颜色尺码套装+个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·mysql·信息可视化·推荐算法
回家路上绕了弯33 分钟前
定期归档历史数据实战指南:从方案设计到落地优化
分布式·后端
+VX:Fegn089533 分钟前
计算机毕业设计|基于springboot + vue建筑材料管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
掘金者阿豪34 分钟前
Redis `WRONGTYPE` 错误的原因及解决方法
后端
天天摸鱼的java工程师38 分钟前
线程池深度解析:核心参数 + 拒绝策略 + 动态调整实战
java·后端