一、前言
在Java項(xiàng)目開發(fā)過程中經(jīng)常會遇到導(dǎo)出Word文檔的業(yè)務(wù)場景。XWPFDocument是apache基金會提供的用戶導(dǎo)出Word文檔的工具類。
二、基本的概念
- XWPFDocument:代表一個(gè)docx文檔
- XWPFParagraph:代表文檔、表格、標(biāo)題等各種的段落,由多個(gè)XWPFRun組成
- XWPFRun:代表具有同樣風(fēng)格的一段文本
- XWPFTable:代表一個(gè)表格
- XWPFTableRow:代表表格的一行
- XWPFTableCell:代表表格的一個(gè)單元格
- XWPFChar:表示.docx文件中的圖表
- XWPFHyperlink:表示超鏈接
- XWPFPicture:代表圖片
- XWPFComment :代表批注
- XWPFFooter:代表頁腳
- XWPFHeader:代表頁眉
- XWPFStyles:樣式(設(shè)置多級標(biāo)題的時(shí)候用)
三、Maven依賴(JAR)
<!-- poi pdf文件/xml文件 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.10-FINAL</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
四、Word模板
1.正文段落
一個(gè)文檔包含多個(gè)段落,一個(gè)段落包含多個(gè)Runs,一個(gè)Runs包含多個(gè)Run,Run是文檔的最小單元
獲取所有段落:List paragraphs = word.getParagraphs();
獲取一個(gè)段落中的所有Runs:List xwpfRuns = xwpfParagraph.getRuns();
獲取一個(gè)Runs中的一個(gè)Run:XWPFRun run = xwpfRuns.get(index);
XWPFRun–代表具有相同屬性的一段文本
2.正文表格
一個(gè)文檔包含多個(gè)表格,一個(gè)表格包含多行,一行包含多列(格),每一格的內(nèi)容相當(dāng)于一個(gè)完整的文檔
獲取所有表格:List xwpfTables = doc.getTables();
獲取一個(gè)表格的行數(shù):int rcount = xwpfTable.getNumberOfRows();
獲取一個(gè)表格的第幾行:XWPFTableRow row = table.getRow(i);
獲取一個(gè)表格中的所有行:List xwpfTableRows = xwpfTable.getRows();
獲取一行中的所有列:List xwpfTableCells = xwpfTableRow.getTableCells();
獲取一格里的內(nèi)容:List paragraphs = xwpfTableCell.getParagraphs();
之后和正文段落一樣
注:
- 表格的一格相當(dāng)于一個(gè)完整的docx文檔,只是沒有頁眉和頁腳。里面可以有表格,使用xwpfTableCell.getTables()獲取,and so on
- 在poi文檔中段落和表格是完全分開的,如果在兩個(gè)段落中有一個(gè)表格,在poi中是沒辦法確定表格在段落中間的。(當(dāng)然除非你本來知道了,這句是廢話)。只有文檔的格式固定,才能正確的得到文檔的結(jié)構(gòu)
3.頁眉
一個(gè)文檔可以有多個(gè)頁眉,頁眉里面可以包含段落和表格
獲取文檔的頁眉:List headerList = doc.getHeaderList();
獲取頁眉里的所有段落:List paras = header.getParagraphs();
獲取頁眉里的所有表格:List tables = header.getTables();
4.頁腳
頁腳和頁眉基本類似,可以獲取表示頁數(shù)的角標(biāo)
五、XWPFDocument的使用
5.4導(dǎo)出Word文檔
1.word模板
在resources目錄下準(zhǔn)備好word模板:xiaoshen.docx
2.PdfTest測試類
package com.shenxm.file.pdf.test;
import com.shenxm.file.pdf.service.impl.SystemFileBizImpl;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
/**
* @Author: shenxm
* @Description: pdf測試
* @Version 1.0
*/
public class PdfTest {
@Test
public void test1(){
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String format = simpleDateFormat.format(date);
HashMap<String, Object> boMap = new HashMap<>();
boMap.put("address","北京");
boMap.put("name","法克\n蒙克麗麗\n娜娜");
boMap.put("datetime","\n"+format);
boMap.put("opinion","\n小沈\n"+format+"\n審批通過");
boMap.put("book","春的林野");
String docxTemplate = "xiaoshen.docx";//docx模板
String pdfFileName = "xiaoshen.pdf";//輸出的pdf
SystemFileBizImpl systemFileBiz = new SystemFileBizImpl();
systemFileBiz.exportPdf(boMap,docxTemplate,pdfFileName);
}
}
3.ISystemFileService接口
package com.shenxm.file.pdf.service;
import com.shenxm.file.pdf.entity.DownloadFileBo;
import java.util.Map;
public interface ISystemFileService {
DownloadFileBo exportPdf(Map<String,Object> map,String template,String fileName);
}
4.SystemFileServiceImpl實(shí)現(xiàn)類
package com.shenxm.file.pdf.service.impl;
import com.shenxm.file.pdf.entity.DownloadFileBo;
import com.shenxm.file.pdf.service.ISystemFileService;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @Author: shenxm
* @Description: 文件處理 Service
* @Version 1.0
*/
@Service
public class SystemFileServiceImpl implements ISystemFilService {
@Override
public DownloadFileBo exportPdf(Map<String, Object> map, String docxTemplateName, String pdfFileName) {
//校驗(yàn)參數(shù)
Assert.notEmpty(map, "數(shù)據(jù)源不可為空!");
Assert.notNull(docxTemplateName,"docxTemplateName不能為空");
Assert.notNull(pdfFileName,"pdfFileName不能為空");
String pdfExportPath = "G:" + File.separator + "test1" + File.separator;
//1.生成pdf文件對象
File pdfFile = this.createFile(pdfExportPath, pdfFileName);
String docxExportPath = "G:" + File.separator + "test1" + File.separator;//生成的word的路徑
String docxExportName ="xiaoshen1.docx";
//使用當(dāng)前線程的類加載器讀取文件
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(docxTemplateName);
if (in == null) {
System.out.println("讀取文件失?。?);
} else {
try {
//讀取模板文檔
XWPFDocument document = new XWPFDocument(in);
//替換段落中的${}
this.replaceTextInParagragh(document, map);
//替換表格中的${}
this.replaceTextInTables(document, map);
//TODO 替換其他的
//將Docx文檔寫入文件
File exportWord = new File(docxExportPath + docxExportName);
FileOutputStream fileOutputStream = new FileOutputStream(exportWord);
//輸出文件
document.write(fileOutputStream);
fileOutputStream.flush();
//TODO word轉(zhuǎn)為pdf
//關(guān)閉流
fileOutputStream.close();
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/** 替換表格中的占位符 */
private void replaceTextInTables(XWPFDocument document, Map<String, Object> dataMap) {
//獲取所有的表格
List<XWPFTable> tables = document.getTables();
//循環(huán)
for (XWPFTable table : tables) {
//獲取每個(gè)表格的總行數(shù)
int rcount = table.getNumberOfRows();
for (int i = 0; i < rcount; i++) {
//獲取表格的第i行
XWPFTableRow row = table.getRow(i);
//獲取一行的所有單元格
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
//一個(gè)cell相當(dāng)于一個(gè)document
//獲取單元格內(nèi)的文本
String cellTextString = cell.getText();
//替換文本:${} -> value
cellTextString = this.replaceText(cellTextString, dataMap);
//移除表格中的段落
while (cell.getParagraphs().size() > 0) {
cell.removeParagraph(0);
}
//處理換行,并設(shè)置單元格內(nèi)容
this.setWrap(cellTextString,cell);
}
}
}
}
/** 替換段落中的占位符 */
private void replaceTextInParagragh(XWPFDocument document, Map<String, Object> dataMap) {
//獲取整個(gè)Word所有段落:包含頁眉或頁腳文本的段落
List<XWPFParagraph> paragraphs = document.getParagraphs();
//循環(huán)
for (XWPFParagraph paragragh : paragraphs) {
//獲取一段的所有本文
List<XWPFRun> runs = paragragh.getRuns();
//獲取段落內(nèi)容:paragragh.getText();
//循環(huán)
for (int i = 0; i < runs.size(); i++) {
//XWPFRun--代表具有相同屬性的一段文本
XWPFRun xwpfRun = runs.get(i);
//獲取文本中的內(nèi)容
String paraString = xwpfRun.getText(xwpfRun.getTextPosition());
if (paraString != null) {
//替換文字
paraString = this.replaceText(paraString, dataMap);
//設(shè)置替換后的段落
xwpfRun.setText(paraString, 0);
}
}
}
}
/** 替換文字 */
private String replaceText(String text, Map<String, Object> dataMap) {
String paraString = text;
//遍歷map,將段落里面的${}替換成map里的value
Iterator<Map.Entry<String, Object>> iterator = dataMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> entry = iterator.next();
String key = entry.getKey();
String value = entry.getValue().toString();
//組裝map里的key為${key}
StringBuffer sb = new StringBuffer();
String placeHolder = sb.append("${").append(key).append("}").toString();
//替換:將"${as}dasdas" --> value+dasdas
paraString = paraString.replace(placeHolder, value);
}
return paraString;
}
/** 單元格內(nèi)設(shè)置換行 */
private void setWrap(String cellTextString,XWPFTableCell cell){
if (cellTextString != null &&cellTextString.trim().contains("\n")){
//創(chuàng)建文本
XWPFRun run = cell.addParagraph().createRun();
String[] split = cellTextString.split("\n");
run.setText(split[0],0);
for (int i = 1; i < split.length; i++) {
//添加換行符
run.addBreak();
//設(shè)置單元格內(nèi)容
run.setText(split[i]);
}
}else {
//設(shè)置單元格內(nèi)容
cell.setText(cellTextString);
}
}
/** 根據(jù)路徑和文件名 創(chuàng)建文件對象*/
private File createFile(String filePath,String fileName){
//pdf目錄對象
File file = new File(filePath);
if (!file.exists() || !file.isDirectory()) {
file.mkdirs();
}
//pdf文件對象
StringBuffer filePathBuffer = new StringBuffer();
filePathBuffer.append(filePath).append(fileName);
return new File(filePathBuffer.toString());
}
}
5.結(jié)果
六、遇到問題
5.1輸出為word的時(shí)候換行符無效
java換行符"\n"在word文檔中不生效,使用"\r",“\r\n”,“(char)11”,“^p”,“br”,“<w:br>”,"w:p"等均無法實(shí)現(xiàn)單元格內(nèi)換行的功能。文章來源:http://www.zghlxwxcb.cn/news/detail-800220.html
實(shí)現(xiàn)單元格內(nèi)自動(dòng)換行:文章來源地址http://www.zghlxwxcb.cn/news/detail-800220.html
到了這里,關(guān)于Java文件:XWPFDocument導(dǎo)出Word文檔的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!