@
建立一個word檔案,輸入如下圖所示的內容:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.0</version>
</dependency>
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import java.io.IOException;
import java.io.InputStream;
public class CustomXWPFDocument extends XWPFDocument {
public CustomXWPFDocument(InputStream in) throws IOException {
super(in);
}
public CustomXWPFDocument() {
super();
}
public CustomXWPFDocument(OPCPackage pkg) throws IOException {
super(pkg);
}
/**
* @param id
* @param width 寬
* @param height 高
* @param paragraph 段落
*/
public void createPicture(int id, int width, int height,
XWPFParagraph paragraph) {
final int EMU = 9525;
width *= EMU;
height *= EMU;
String blipId = super.getRelationId(super.getAllPictures().get(id));
CTInline inline = paragraph.createRun().getCTR().addNewDrawing()
.addNewInline();
String picXml = ""
+ "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">"
+ " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">"
+ " <pic:nvPicPr>" + " <pic:cNvPr id=\""
+ id
+ "\" name=\"Generated\"/>"
+ " <pic:cNvPicPr/>"
+ " </pic:nvPicPr>"
+ " <pic:blipFill>"
+ " <a:blip r:embed=\""
+ blipId
+ "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>"
+ " <a:stretch>"
+ " <a:fillRect/>"
+ " </a:stretch>"
+ " </pic:blipFill>"
+ " <pic:spPr>"
+ " <a:xfrm>"
+ " <a:off x=\"0\" y=\"0\"/>"
+ " <a:ext cx=\""
+ width
+ "\" cy=\""
+ height
+ "\"/>"
+ " </a:xfrm>"
+ " <a:prstGeom prst=\"rect\">"
+ " <a:avLst/>"
+ " </a:prstGeom>"
+ " </pic:spPr>"
+ " </pic:pic>"
+ " </a:graphicData>" + "</a:graphic>";
inline.addNewGraphic().addNewGraphicData();
XmlToken xmlToken = null;
try {
xmlToken = XmlToken.Factory.parse(picXml);
} catch (XmlException xe) {
xe.printStackTrace();
}
inline.set(xmlToken);
inline.setDistT(0);
inline.setDistB(0);
inline.setDistL(0);
inline.setDistR(0);
CTPositiveSize2D extent = inline.addNewExtent();
extent.setCx(width);
extent.setCy(height);
CTNonVisualDrawingProps docPr = inline.addNewDocPr();
docPr.setId(id);
docPr.setName("圖片名稱");
docPr.setDescr("描述資訊");
}
}
private final String REGEX = "\\$\\{(.+?)\\}";
private CustomXWPFDocument document;
public PoICreateWordFactory(String templatePath) throws IOException {
loadTemplate(templatePath);
}
/**
* 載入模板
*
* @param templatePath 模板路徑
* @return 包含返回true, 不包含返回false
*/
private void loadTemplate(String templatePath) throws IOException {
try (InputStream in = Files.newInputStream(Paths.get(templatePath))) {
//轉成word
this.document = new CustomXWPFDocument(in);
}
}
/**
* 生成word
*
* @param targetFile word生成路徑
* @return 包含返回true, 不包含返回false
*/
public void createWordFile(String targetFile) throws IOException {
try (FileOutputStream out = new FileOutputStream(targetFile)){
document.write(out);
}
}
/**
* 判斷文字中是否包含$
*
* @param text 文字
* @return 包含返回true, 不包含返回false
*/
public boolean checkText(String text) {
boolean check = false;
if (text.indexOf("$") != -1) {
check = true;
}
return check;
}
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 替換段落文字
*
* @param textMap(資料來源)
*/
public void replaceText(Map<String, Object> textMap) {
//獲取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//獲取到段落中的所有文字內容
String text = paragraph.getText();
//判斷此段落中是否有需要進行替換的文字
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替換模板原來位置
Pattern pattern = Pattern.compile(REGEX);
Matcher matcher = pattern.matcher(run.toString());
if (matcher.find()) {
String key = matcher.group(1);
if(textMap.containsKey(key)){
run.setText(String.valueOf(textMap.get(key)), 0);
}
}
}
}
}
}
/**
* 替換圖片
*
* @param imageMap(資料來源)
*/
public void replaceImage(Map<String, byte[]> imageMap) throws org.apache.poi.openxml4j.exceptions.InvalidFormatException {
//段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
Set<Map.Entry<String, byte[]>> imageSets = imageMap.entrySet();
for (XWPFParagraph paragraph : paragraphs) {
//獲取到段落中的所有文字內容
String text = paragraph.getText();
//判斷此段落中是否有需要進行替換的文字
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替換模板原來位置
Pattern pattern = Pattern.compile(REGEX);
String runText = run.toString();
Matcher matcher = pattern.matcher(runText);
if (matcher.find()) {
String key = matcher.group(1);
if(imageMap.containsKey(key)){
//清空原有內容
run.setText("", 0);
//設定圖片
document.addPictureData(imageMap.get(key), XWPFDocument.PICTURE_TYPE_PNG);
//建立一個word圖片,並插入到檔案中-->畫素可改
document.createPicture(document.getAllPictures().size() - 1, 240, 240,paragraph);
break;
}
}
}
}
}
}
/**
* 替換表格內容
*
* @param index(表格索引:第幾個表格)
* @param tableList(資料來源)
* @Return void
* @Exception
*/
public void replaceTable(int index, List<List<String>> tableList) {
XWPFTable table = document.getTables().get(index);
//建立行,根據需要插入的資料新增新行,不處理表頭
for (int i = 1; i <= tableList.size(); i++) {
table.createRow();
}
//遍歷表格插入資料
List<XWPFTableRow> rows = table.getRows();
for (int i = 1; i < tableList.size()+1; i++) {
XWPFTableRow newRow = table.getRow(i);
List<XWPFTableCell> cells = newRow.getTableCells();
List<String> rowData = tableList.get(i - 1);
for (int j = 0; j < rowData.size(); j++) {
XWPFTableCell cell = cells.get(j);
String text = rowData.get(j);
cell.setText(text);
//表格樣式一致-->沒有此段表格會預設左對齊
//有此段會使表格格式一致
CTTc cttc = cell.getCTTc();
CTTcPr ctPr = cttc.addNewTcPr();
ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
}
}
}
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STJc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STVerticalJc;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PoICreateWordFactory {
/**
* 生成ord
*
*/
public void crateWord(Map<String, Object> dataMap, String templatePath, String targetFile) throws IOException, InvalidFormatException {
//載入模板檔案
loadTemplate(templatePath);
//將dataMap拆分成 textMap、imageMap、tableMap TODO 爛尾中
//段落替換變數
Map<String, Object> textMap = new HashMap<>();
//替換模板資料
replaceText(textMap);
//圖片替換變數
Map<String, byte[]> imageMap = new HashMap<>();
replaceImage(imageMap);
//寫入表格
List<List<String>> arrearsList = new ArrayList<>();
replaceTable(0, arrearsList);
//生成新的word
createWordFile(targetFile);
}
private final String REGEX = "\\$\\{(.+?)\\}";
private CustomXWPFDocument document;
public PoICreateWordFactory() {}
public PoICreateWordFactory(String templatePath) throws IOException {
loadTemplate(templatePath);
}
/**
* 載入模板
*
* @param templatePath 模板路徑
* @return 包含返回true, 不包含返回false
*/
public void loadTemplate(String templatePath) throws IOException {
try (InputStream in = Files.newInputStream(Paths.get(templatePath))) {
//轉成word
this.document = new CustomXWPFDocument(in);
}
}
/**
* 生成word
*
* @param targetFile word生成路徑
* @return 包含返回true, 不包含返回false
*/
public void createWordFile(String targetFile) throws IOException {
try (FileOutputStream out = new FileOutputStream(targetFile)){
document.write(out);
}
}
/**
* 判斷文字中是否包含$
*
* @param text 文字
* @return 包含返回true, 不包含返回false
*/
public boolean checkText(String text) {
boolean check = false;
if (text.indexOf("$") != -1) {
check = true;
}
return check;
}
/**
* 替換段落文字
*
* @param textMap(資料來源)
*/
public void replaceText(Map<String, Object> textMap) {
//獲取段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
//獲取到段落中的所有文字內容
String text = paragraph.getText();
//判斷此段落中是否有需要進行替換的文字
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替換模板原來位置
Pattern pattern = Pattern.compile(REGEX);
Matcher matcher = pattern.matcher(run.toString());
if (matcher.find()) {
String key = matcher.group(1);
if(textMap.containsKey(key)){
run.setText(String.valueOf(textMap.get(key)), 0);
}
}
}
}
}
}
/**
* 替換圖片
*
* @param imageMap(資料來源)
*/
public void replaceImage(Map<String, byte[]> imageMap) throws org.apache.poi.openxml4j.exceptions.InvalidFormatException {
//段落集合
List<XWPFParagraph> paragraphs = document.getParagraphs();
Set<Map.Entry<String, byte[]>> imageSets = imageMap.entrySet();
for (XWPFParagraph paragraph : paragraphs) {
//獲取到段落中的所有文字內容
String text = paragraph.getText();
//判斷此段落中是否有需要進行替換的文字
if (checkText(text)) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
//替換模板原來位置
Pattern pattern = Pattern.compile(REGEX);
String runText = run.toString();
Matcher matcher = pattern.matcher(runText);
if (matcher.find()) {
String key = matcher.group(1);
if(imageMap.containsKey(key)){
//清空原有內容
run.setText("", 0);
//設定圖片
document.addPictureData(imageMap.get(key), XWPFDocument.PICTURE_TYPE_PNG);
//建立一個word圖片,並插入到檔案中-->畫素可改
document.createPicture(document.getAllPictures().size() - 1, 240, 240,paragraph);
break;
}
}
}
}
}
}
/**
* 替換表格內容
*
* @param index(表格索引:第幾個表格)
* @param tableList(資料來源)
* @Return void
* @Exception
*/
public void replaceTable(int index, List<List<String>> tableList) {
XWPFTable table = document.getTables().get(index);
//建立行,根據需要插入的資料新增新行,不處理表頭
for (int i = 1; i <= tableList.size(); i++) {
table.createRow();
}
//遍歷表格插入資料
List<XWPFTableRow> rows = table.getRows();
for (int i = 1; i < tableList.size()+1; i++) {
XWPFTableRow newRow = table.getRow(i);
List<XWPFTableCell> cells = newRow.getTableCells();
List<String> rowData = tableList.get(i - 1);
for (int j = 0; j < rowData.size(); j++) {
XWPFTableCell cell = cells.get(j);
String text = rowData.get(j);
cell.setText(text);
//表格樣式一致-->沒有此段表格會預設左對齊
//有此段會使表格格式一致
CTTc cttc = cell.getCTTc();
CTTcPr ctPr = cttc.addNewTcPr();
ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
}
}
}
}
public static void main(String[] args) throws IOException, InvalidFormatException {
String templatePath = "D:\\文章\\word生成\\poi\\qiantiao.docx";
String targetFile = "D:\\test\\qiantiao.docx";
//初始化,並載入模板檔案
PoICreateWordFactory poICreateWordFactory = new PoICreateWordFactory(templatePath);
//段落替換變數
LocalDate currentDate = LocalDate.now();
LocalDate endDate = currentDate.plusYears(1L);
Map<String, Object> textMap = new HashMap<>();
textMap.put("debtor", "陳有楚");
textMap.put("nowYear", String.valueOf(currentDate.getYear()));
textMap.put("nowMonth", String.valueOf(currentDate.getMonthValue()));
textMap.put("nowDay", String.valueOf(currentDate.getDayOfMonth()));
textMap.put("arrears", "一頓老魏、貴州大黃牛、v我50");
textMap.put("endYear", String.valueOf(endDate.getYear()));
textMap.put("endMonth", String.valueOf(endDate.getMonthValue()));
textMap.put("endDay", String.valueOf(endDate.getDayOfMonth()));
textMap.put("creditor", "知北遊");
//替換模板資料
poICreateWordFactory.replaceText(textMap);
//圖片替換變數
FileInputStream imageInput = new FileInputStream("D:\\picture\\其他\\24-05-23-142418.png");
byte[] bytes = new byte[imageInput.available()];
imageInput.read(bytes);
imageInput.close();
Map<String, byte[]> imageMap = new HashMap<>();
imageMap.put("image1", bytes);
poICreateWordFactory.replaceImage(imageMap);
//寫入表格
List<List<String>> arrearsList = new ArrayList<>();
arrearsList.add(Arrays.asList("一頓老魏", "1", "三月內"));
arrearsList.add(Arrays.asList("貴州大黃牛", "1", "一年內"));
arrearsList.add(Arrays.asList("v我50", "1", "一月內"));
//獲取表格位置 0代表第一個表格,寫死第一個,模板裡也只有一個模板
poICreateWordFactory.replaceTable(0, arrearsList);
//生成新的word
poICreateWordFactory.createWordFile(targetFile);
}
其實從測試程式碼裡就可以發現這其實只是一個半成品程式碼,文字替換、圖片替換、表格替換甚至需要分別傳遞不同的資料map。本來是打算合併成一個dataMap,然後根據引數類來區分是文字、圖片、表格的。然後拆分成多個資料map。但是在寫這些程式碼時發現了也是基於poi開發的開源專案poi-tl。功能很全,我想實現的功能他都有,頓時我寫的上面這些程式碼就失去了意義,然後就爛尾了。。。後面有時間介紹一下poi-tl這個開源專案使用方式吧,經過試驗這個確實功能完善,非常推薦。