如何使用POI-TL生成有个性的简历?

1.介绍

POI-TL 是一个基于 Apache POI 的 Java 库,专注于在 Microsoft Word 文档(.docx 格式)中进行模板填充和动态内容生成。它的全称是 "POI Template Language",旨在简化文档生成过程,特别是在需要根据动态数据生成复杂文档的场景中。POI-TL 通过提供一种简单而强大的模板引擎,使开发者能够轻松地将数据嵌入到 Word 文档中,从而自动化生成报告、合同、发票等文档。

2.原理

POI-TL 的核心原理是将 Word 文档视为模板,并在其中定义占位符。占位符通常以 {{key}} 的形式出现,代表需要动态替换的内容。开发者通过 Java 代码提供一个数据模型,其中包含占位符对应的实际值。POI-TL 使用这些数据来替换模板中的占位符,从而生成最终的文档。

POI-TL 基于 Apache POI 构建,利用 POI 提供的对 Word 文档的低级别操作能力,实现了对文档的高效处理。它支持复杂的文档结构,包括表格、图片、段落等,使得生成的文档不仅内容准确,还能保持良好的格式和样式。

3.代码工程

目标

利用word模版生成简历

pom.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Java-demo</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>poi-tl</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.deepoove</groupId>
            <artifactId>poi-tl</artifactId>
            <version>1.12.2</version>
        </dependency>
        <!-- Log4j dependencies for logging -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.19.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.19.0</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

模版

在代码仓库的测试包下面

bash 复制代码
src/test/resources/resume.docx

代码

ExperienceData.java

typescript 复制代码
package com.et;

import com.deepoove.poi.data.NumberingRenderData;

public class ExperienceData {
    private String company;
    private String department;
    private String time;
    private String position;
    private NumberingRenderData responsibility;

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public NumberingRenderData getResponsibility() {
        return responsibility;
    }

    public void setResponsibility(NumberingRenderData responsibility) {
        this.responsibility = responsibility;
    }

}

ResumeDataV2.java

kotlin 复制代码
package com.et;

import java.util.List;

import com.deepoove.poi.data.NumberingRenderData;
import com.deepoove.poi.data.PictureRenderData;

public class ResumeDataV2 {

    private PictureRenderData portrait;
    private String name;
    private String job;
    private String sex;
    private String phone;
    private String birthday;
    private String province;
    private String email;
    private String address;
    private String english;
    private String University;
    private String rank;
    private String education;
    private String profession;
    private NumberingRenderData stack;
    private String hobbies;
    private List<ExperienceData> experiences;

    public void setPortrait(PictureRenderData portrait) {
        this.portrait = portrait;
    }

    public PictureRenderData getPortrait() {
        return this.portrait;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public String getJob() {
        return this.job;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getSex() {
        return this.sex;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getPhone() {
        return this.phone;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public String getBirthday() {
        return this.birthday;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getProvince() {
        return this.province;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getEmail() {
        return this.email;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getAddress() {
        return this.address;
    }

    public void setEnglish(String english) {
        this.english = english;
    }

    public String getEnglish() {
        return this.english;
    }

    public void setUniversity(String University) {
        this.University = University;
    }

    public String getUniversity() {
        return this.University;
    }

    public void setRank(String rank) {
        this.rank = rank;
    }

    public String getRank() {
        return this.rank;
    }

    public void setEducation(String education) {
        this.education = education;
    }

    public String getEducation() {
        return this.education;
    }

    public void setProfession(String profession) {
        this.profession = profession;
    }

    public String getProfession() {
        return this.profession;
    }

    public void setStack(NumberingRenderData stack) {
        this.stack = stack;
    }

    public NumberingRenderData getStack() {
        return this.stack;
    }

    public void setHobbies(String hobbies) {
        this.hobbies = hobbies;
    }

    public String getHobbies() {
        return this.hobbies;
    }

    public List<ExperienceData> getExperiences() {
        return experiences;
    }

    public void setExperiences(List<ExperienceData> experiences) {
        this.experiences = experiences;
    }

}

ResumeIterableExample.java

ini 复制代码
package com.et;

import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.data.Numberings;
import com.deepoove.poi.data.Pictures;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.data.style.Style;

@DisplayName("Foreach resume example")
public class ResumeIterableExample {

    ResumeDataV2 datas = new ResumeDataV2();

    @BeforeEach
    public void init() {
        datas.setPortrait(Pictures.ofLocal("src/test/resources/sayi.png").size(100, 100).create());
        datas.setName("卅一");
        datas.setJob("BUG工程师");
        datas.setPhone("18080809090");
        datas.setSex("男");
        datas.setProvince("杭州");
        datas.setBirthday("2000.08.19");
        datas.setEmail("adasai90@gmail.com");
        datas.setAddress("浙江省杭州市西湖区古荡1号");
        datas.setEnglish("CET6 620");
        datas.setUniversity("美国斯坦福大学");
        datas.setProfession("生命工程");
        datas.setEducation("学士");
        datas.setRank("班级排名 1/36");
        datas.setHobbies("音乐、画画、乒乓球、旅游、读书\nhttps://github.com/Sayi");

        // 技术栈部分
        TextRenderData textRenderData = new TextRenderData("SpringBoot、SprigCloud、Mybatis");
        Style style = Style.builder().buildFontSize(10).buildColor("7F7F7F").buildFontFamily("微软雅黑").build();
        textRenderData.setStyle(style);
        datas.setStack(Numberings.of(textRenderData, textRenderData, textRenderData).create());

        /*
         * {{?experiences}} {{company}} {{department}} {{time}} {{position}}
         * {{*responsibility}} {{/experiences}}
         */
        List<ExperienceData> experiences = new ArrayList<ExperienceData>();
        ExperienceData data0 = new ExperienceData();
        data0.setCompany("香港微软");
        data0.setDepartment("Office 事业部");
        data0.setTime("2001.07-2020.06");
        data0.setPosition("BUG工程师");
        textRenderData = new TextRenderData("负责生产BUG,然后修复BUG,同时有效实施招聘行为");
        textRenderData.setStyle(style);
        data0.setResponsibility(Numberings.of(textRenderData, textRenderData).create());
        ExperienceData data1 = new ExperienceData();
        data1.setCompany("自由职业");
        data1.setDepartment("OpenSource 项目组");
        data1.setTime("2015.07-2020.06");
        data1.setPosition("研发工程师");
        textRenderData = new TextRenderData("开源项目的迭代和维护工作");
        textRenderData.setStyle(style);
        TextRenderData textRenderData1 = new TextRenderData("持续集成、Swagger文档等工具调研");
        textRenderData1.setStyle(style);
        data1.setResponsibility(Numberings.of(textRenderData, textRenderData1, textRenderData).create());
        experiences.add(data0);
        experiences.add(data1);
        experiences.add(data0);
        experiences.add(data1);
        datas.setExperiences(experiences);
    }

    @Test
    public void testResumeExample() throws Exception {
        XWPFTemplate template = XWPFTemplate.compile("src/test/resources/resume.docx").render(datas);

        FileOutputStream out = new FileOutputStream("target/out_example_resume_iterable.docx");
        template.write(out);
        out.flush();
        out.close();
        template.close();
    }

}

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

4.测试

运行测试代码,打开生成的文件(target/out_example_resume_iterable.docx)如下图展示

5.引用

相关推荐
疯一样的码农10 分钟前
Maven 如何配置忽略单元测试
java·单元测试·maven
老牛源码12 分钟前
Z2400024基于Java+SSM+mysql+maven开发的社区论坛系统的设计与实现(附源码 配置 文档)
java·mysql·maven·ssm
zhangj112514 分钟前
Java部分新特性
java·开发语言
暮湫20 分钟前
异常处理(6)自定义异常
java
不修×蝙蝠24 分钟前
数据结构--链表实现栈和队列
java·数据结构·链表··队列
小登ai学习25 分钟前
框架学习07 - SpringMVC 其他功能实现
java·学习·spring·mvc
Layue0000043 分钟前
学习HTML第三十三天
java·前端·笔记·学习·html
API快乐传递者44 分钟前
Java爬虫:深入探索1688接口的奥秘
java·开发语言·爬虫
江小北1 小时前
Java基础面试题03:简述什么是迭代器(Iterator)?
java·后端·java ee
morning_judger1 小时前
【设计模式系列】责任链模式(十六)
java·设计模式·责任链模式