如何使用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.引用

相关推荐
最初的↘那颗心44 分钟前
Java 泛型类型擦除
java·flink
uhakadotcom1 小时前
使用postgresql时有哪些简单有用的最佳实践
后端·面试·github
IT毕设实战小研1 小时前
基于Spring Boot校园二手交易平台系统设计与实现 二手交易系统 交易平台小程序
java·数据库·vue.js·spring boot·后端·小程序·课程设计
bobz9651 小时前
QT 字体
后端
泉城老铁1 小时前
Spring Boot 中根据 Word 模板导出包含表格、图表等复杂格式的文档
java·后端
用户4099322502121 小时前
如何在FastAPI中玩转APScheduler,实现动态定时任务的魔法?
后端·github·trae
极客BIM工作室1 小时前
谈谈《More Effective C++》的条款30:代理类
java·开发语言·c++
孤狼程序员1 小时前
【Spring Cloud 微服务】1.Hystrix断路器
java·spring boot·spring·微服务
风象南1 小时前
开发者必备工具:用 SpringBoot 构建轻量级日志查看器,省时又省力
后端
RainbowSea2 小时前
伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 04
java·spring boot·后端