poi-tl二次開發
poi-tl是一款非常好用的word模板生成庫,更新響應快、文檔demo齊全。堪稱word模板界的小軍刀!
寫在前面
如果你對word模板技術有了解、或者有興趣,更甚者工作中接觸過,那么接下來的內容應該會讓你有所收獲。
介紹poi-tl
功能如下:
- 文本 {{var}}
- 表格 {{#var}}
- 圖片 {{@var}}
- 列表 {{*var}}
- 嵌套 {{+var}}
更多文檔參考如下:poi-tl
這里不再更多的贅述poi-tl的功能了,非常優秀的一個word模板庫。
二次開發
如果你還沒使用過poi-tl,那么接下來的內容,你應該不太會感同身受。
poi-tl使用一段時間后會發現仍存在一些問題,比如行列表格需要自己寫代碼指定樣式、圖片需要寫代碼指定高度寬度、列表也寫代碼指定樣式。
為最大化利用word的樣式,減少代碼量,這里在v1.6.0之上進行源碼擴展。
加入模板語法:name|attr:var
。
- name 為功能名稱
- attr 為屬性
- var 為數據變量名稱
fork地址:github
表格
語法:{{table|limit:var}}
- table 說明是表格
- limit 為數據填充的行數,數據不足補空
- var 為填充數據(JSON)的 key,可以是一個對象或者對象數組。
模板:
其中:
- 姓名的前面出現的
{{table|5:[users]}}
,代表了這是一個表格模板(可以出現在表格的任意位置,建議在表頭),users
則說明數據中存在一個 users 的 key 。 - 表格的第二行變量會根據傳遞的值動態替換,{name}、{age} 等模板,則說明 users 這個 key 中的對象或對象數組存在 name、age 這兩個key。
- 由於數據只有2條,限制5條,因此補空行3條
測試代碼:
@Test
public void run() {
Path path = Paths.get("src/test/resources", "table_pattern.docx");
XWPFTemplate template = XWPFTemplate.compile(path.toFile())
// 數據
.render(new HashMap<String, Object>() {{
put("users", Arrays.asList(new User("張三", 1), new User("李四", 2)));
}});
// 輸出
Path outPath = Paths.get("src/test/resources", "table_pattern_out.docx");
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(outPath.toFile()))) {
template.write(os);
} catch (IOException e) {
LOG.error("render tpl error", e);
} finally {
try {
template.close();
} catch (IOException e) {
LOG.error("close template error", e);
}
}
}
可以看到這里的 map 中存在 users 這個 key,且存在 2 條數據。User 這個對象有兩個屬性 name、age ,模板在解析時,會自動取值。
輸出:
總結:表格正常渲染,而且樣式也正常保留,原來的數據也會保留下來,數據不足補空行。
圖片
語法:{{image|height*width:var}}
- image 說明是圖片
- height*width 代表圖片的高度和寬度,單位為厘米
- var 為填充數據的 key,是一個圖片字節通過base64加密的字符串
模板:
測試代碼:
@Test
public void run() throws IOException {
Path logoPath = Paths.get("src/test/resources", "logo.png");
byte[] bytes = Files.readAllBytes(logoPath);
byte[] encode = Base64.getEncoder().encode(bytes);
Path path = Paths.get("src/test/resources", "image_pattern.docx");
XWPFTemplate template = XWPFTemplate.compile(path.toFile())
// 數據
.render(new HashMap<String, Object>() {{
put("logo", new String(encode));
}});
// 輸出
Path outPath = Paths.get("src/test/resources", "image_pattern_out.docx");
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(outPath.toFile()))) {
template.write(os);
} catch (IOException e) {
LOG.error("render tpl error", e);
} finally {
try {
template.close();
} catch (IOException e) {
LOG.error("close template error", e);
}
}
}
輸出:
總結:圖片能正常根據高度寬度渲染出來
列表
語法:list|limit:var
- list 說明是列表
- limit 為數據填充的行數,數據不足補空
- var 為填充數據的 key,值可以是一個字符串或者一個字符串數組。
模板:
測試代碼:
@Test
public void run() {
Path inPath = Paths.get("src/test/resources", "list_pattern.docx");
Path outPath = Paths.get("src/test/resources", "list_pattern_out.docx");
Map<String, Object> model = new HashMap<String, Object>() {{
put("items", Arrays.asList("張三", "李四", "王五"));
}};
try (InputStream is = Files.newInputStream(inPath); OutputStream os = Files.newOutputStream(outPath)) {
Tpl.render(is, model).out(os);
} catch (IOException e) {
LOG.info("render tpl failed", e);
}
}
輸出:
總結:列表也能正常渲染,保證原有的格式。
tips
看示例,你也許會覺得很奇怪,為什么語法明明寫的var
,但是截圖中有的寫的是[var]
、有的卻寫的var
。
這是因為變量取值采用的 spring expression 語法:如果代碼中是一個對象,就可以直接寫var
,是一個map,就寫[var]
,數組則是var[下標]
。
寫在最后
如果覺得有用,快快使用起來吧!