概述

Apache POI 简介是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office(Excel、WORD、PowerPoint、Visio等)格式档案读和写的功能。

官网: http://poi.apache.org/index.html

API帮助文档: http://poi.apache.org/apidocs/index.html

Apache POI常用的类

  • HSSF - 提供读写Microsoft Excel XLS格式档案的功能。
  • XSSF - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。
  • HWPF - 提供读写Microsoft Word DOC97格式档案的功能。
  • XWPF- 提供读写Microsoft Word DOC2003格式档案的功能。
  • HSLF - 提供读写Microsoft PowerPoint格式档案的功能。
  • HDGF - 提供读Microsoft Visio格式档案的功能。
  • HPBF - 提供读Microsoft Publisher格式档案的功能。
  • HSMF - 提供读Microsoft Outlook格式档案的功能。

Maven依赖

 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.0.0</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.0.0</version></dependency>

Excel(HSSF/XSSF)

概述

​ HSSF是POI项目对Excel '97(.xls)文件格式的纯Java实现。XSSF是POI项目对Excel 2007 OOXML(.xlsx)文 件格式的纯Java实现。

​ HSSF和XSSF提供了读取电子表格的方法,以创建,修改,读取和写入XLS电子表格。

创建工作薄

Workbook wb = new HSSFWorkbook();
...
try (OutputStream fileOut = new FileOutputStream("workbook.xls")) {wb.write(fileOut);
}
或者
Workbook wb = new XSSFWorkbook();
...
try (OutputStream fileOut = new FileOutputStream("workbook.xlsx")) {wb.write(fileOut);
}

创建工作表

//创建默认名称的Sheet
Sheet sheet = wb.createSheet();
//创建指定名称的Sheet
Sheet my_sheet = wb.createSheet("my_sheet");

创建单元格

 // 创建行Row row = sheet.createRow(0);// 创建单元格Cell cell = row.createCell(0);//设置值cell.setCellValue(1);或者链式编程sheet.createRow(0).createCell(1).setCellValue(88);sheet.createRow(0).createCell(2).setCellValue(true);

创建日期类单元格

CellStyle cellStyle = wb.createCellStyle();
CreationHelper creationHelper = wb.getCreationHelper();
cellStyle.setDataFormat(creationHelper.createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss"));
cell = row.createCell(3);
cell.setCellValue(new Date());
cell.setCellStyle(cellStyle);
//你也能使用日期工具类  java.util.Calendar
cell = row.createCell(4);
cell.setCellValue(Calendar.getInstance());
cell.setCellStyle(cellStyle);

Files vs InputStreams

当打开工作簿(.xls HSSFWorkbook或.xlsx XSSFWorkbook)时,可以从FileInputStream加载工作簿。使用File对象可以减少内存消耗,而InputStream需要更多内存,因为它必须缓冲整个文件。

如果使用WorkbookFactory,则使用其中一个非常容易:

// Use a file
Workbook wb = WorkbookFactory.create(new File("MyExcel.xls"));
// Use an InputStream, needs more memory
Workbook wb = WorkbookFactory.create(new FileInputStream("MyExcel.xlsx"));

展示各种对齐方式

public static void main(String[] args) throws Exception {Workbook wb = new XSSFWorkbook(); //or new HSSFWorkbook();Sheet sheet = wb.createSheet();Row row = sheet.createRow(2);row.setHeightInPoints(30);createCell(wb, row, 0, HorizontalAlignment.CENTER, VerticalAlignment.BOTTOM);createCell(wb, row, 1, HorizontalAlignment.CENTER_SELECTION,                             VerticalAlignment.BOTTOM);createCell(wb, row, 2, HorizontalAlignment.FILL, VerticalAlignment.CENTER);createCell(wb, row, 3, HorizontalAlignment.GENERAL, VerticalAlignment.CENTER);createCell(wb, row, 4, HorizontalAlignment.JUSTIFY, VerticalAlignment.JUSTIFY);createCell(wb, row, 5, HorizontalAlignment.LEFT, VerticalAlignment.TOP);createCell(wb, row, 6, HorizontalAlignment.RIGHT, VerticalAlignment.TOP);// Write the output to a filetry (OutputStream fileOut = new FileOutputStream("writeExcel.xlsx")) {wb.write(fileOut);}wb.close();}private static void createCell(Workbook wb, Row row, int column, HorizontalAlignment     halign, VerticalAlignment valign) {Cell cell = row.createCell(column);cell.setCellValue("Align It");CellStyle cellStyle = wb.createCellStyle();cellStyle.setAlignment(halign);cellStyle.setVerticalAlignment(valign);cell.setCellStyle(cellStyle);}

边界处理

设置边框的样式与颜色

CellStyle style = wb.createCellStyle();
style.setBorderBottom(BorderStyle.THIN);
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setBorderLeft(BorderStyle.THIN);
style.setLeftBorderColor(IndexedColors.GREEN.getIndex());
style.setBorderRight(BorderStyle.THIN);
style.setRightBorderColor(IndexedColors.BLUE.getIndex());
style.setBorderTop(BorderStyle.MEDIUM_DASHED);
style.setTopBorderColor(IndexedColors.BLACK.getIndex());
cell.setCellStyle(style);

获取单元格内容

要获取单元格的内容,您首先需要知道它是哪种单元格.

@Test
public void cellValue() throws IOException {HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream("cellValue.xls"));DataFormatter formatter = new DataFormatter();Sheet sheet1 = wb.getSheetAt(0);for (Row row : sheet1) {for (Cell cell : row) {CellReference cellRef = new CellReference(row.getRowNum(),                               cell.getColumnIndex());System.out.print(cellRef.formatAsString());System.out.print(" - ");//能够获取任何单元格类型的值String text = formatter.formatCellValue(cell);System.out.println(text);//或者// 判断单元格类型switch (cell.getCellType()) {case STRING:System.out.println(cell.getRichStringCellValue().getString());break;case NUMERIC:if (DateUtil.isCellDateFormatted(cell)) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd                                   HH:mm:ss");String value = sdf.format(cell.getDateCellValue());System.out.println(value);} else {System.out.println(cell.getNumericCellValue());}break;case BOOLEAN:System.out.println(cell.getBooleanCellValue());break;case FORMULA:System.out.println(cell.getCellFormula());break;case BLANK:System.out.println("");break;case ERROR:System.out.println("未知错误");default:System.out.println("未知类型");}}}
}

文字提取

对于大多数文本提取要求,标准的ExcelExtractor类应提供您所需要的全部。

 @Testpublic void textExtraction() throws IOException {InputStream inp = new FileInputStream("cellValue.xls");HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(inp));ExcelExtractor extractor = new ExcelExtractor(wb);extractor.setFormulasNotResults(true);extractor.setIncludeSheetNames(false);String text = extractor.getText();System.out.println(text);wb.close();}

填充和颜色

 CellStyle style = wb.createCellStyle();style.setFillBackgroundColor(IndexedColors.AQUA.getIndex());//填充背景颜色style.setFillPattern(FillPatternType.BIG_SPOTS);            //填充模式Cell cell = row.createCell(1);cell.setCellStyle(style);style.setFillForegroundColor(IndexedColors.ORANGE.getIndex());//填充前景色style.setFillPattern(FillPatternType.SOLID_FOREGROUND);       //填充模式

合并单元格

//参数1: first row (0-based) 开始行
//参数2: last row  (0-based) 结束行
//参数3: first column (0-based) 开始列
//参数4: last column  (0-based) 结束列
sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, 2));

字体

 Font font = wb.createFont();font.setFontHeightInPoints((short)24);font.setFontName("Courier New");font.setItalic(true); //斜体font.setStrikeout(true); //删除线font.setBold(true);//加粗CellStyle style = wb.createCellStyle();style.setFont(font);cell.setCellStyle(style);

遇到的问题

使用POI循环写入数据时发现只有最后一列有数据

检查调用createRow() 是否在外层循环调用的,如果是在内层循环调用就会出现这个问题,因为程序会不停的重新创建行,直至最后一个cell中的数据写入,跳至下一行同上,所以会出现只有最后一列数据的情况。

Excel中写入日期变为一堆#######

原因: 单元格的宽度不够

拉开单元格宽度发现正常显示了

Word(HWPF)

​ Apache poi的hwpf模块是专门用来对word doc文件进行读写操作的。在hwpf里面我们使用HWPFDocument来表示一个word doc文档。在HWPFDocument里面有这么几个概念:

Range:它表示一个范围,这个范围可以是整个文档,也可以是里面的某一小节(Section),也可以是某一个段落(Paragraph),还可以是拥有共同属性的一段文本(CharacterRun)。

Section:word文档的一个小节,一个word文档可以由多个小节构成。

Paragraph:word文档的一个段落,一个小节可以由多个段落构成。

CharacterRun:具有相同属性的一段文本,一个段落可以由多个CharacterRun组成。

Table:一个表格。

TableRow:表格对应的行。

TableCell:表格对应的单元格。

​ Section、Paragraph、CharacterRun和Table都继承自Range。

Maven依赖

<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.0.0</version>
</dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId><version>4.0.0</version>
</dependency>

读word doc文件

​ 在日常应用中,我们从word文件里面读取信息的情况非常少见,更多的还是把内容写入到word文件中。使用POI从word doc文件读取数据时主要有两种方式:通过WordExtractor读和通过HWPFDocument读。在WordExtractor内部进行信息读取时还是通过HWPFDocument来获取的。

通过WordExtractor读文件

​ 在使用WordExtractor读文件时我们只能读到文件的文本内容和基于文档的一些属性,至于文档内容的属性等是无法读到的。如果要读到文档内容的属性则需要使用HWPFDocument来读取了。下面是使用WordExtractor读取文件的一个示例:

public class HwpfTest {@Testpublic void testReadByExtractor() throws IOException {InputStream is = new FileInputStream("test.doc");WordExtractor extractor = new WordExtractor(is);//输出word文档所有的文本System.out.println(extractor.getText());System.out.println("=======================");System.out.println(extractor.getTextFromPieces());//输出页眉的内容System.out.println("页眉: " + extractor.getHeaderText());//输出页脚的内容System.out.println("页脚: " + extractor.getFooterText());//输出当前word文档的元数据信息,包括作者、文档的修改时间等。System.out.println(extractor.getMetadataTextExtractor().getText());//获取各个段落的文本String paraTexts[] = extractor.getParagraphText();for (int i = 0; i < paraTexts.length; i++) {System.out.println("Paragraph " + (i + 1) + " : " + paraTexts[i]);}//输出当前word的一些信息printInfo(extractor.getSummaryInformation());//输出当前word的一些信息this.printInfo(extractor.getDocSummaryInformation());this.closeStream(is);}/*** 输出SummaryInfomation** @param info*/private void printInfo(SummaryInformation info) {//作者System.out.println(info.getAuthor());//字符统计System.out.println(info.getCharCount());//页数System.out.println(info.getPageCount());//标题System.out.println(info.getTitle());//主题System.out.println(info.getSubject());}/*** 输出DocumentSummaryInfomation** @param info*/private void printInfo(DocumentSummaryInformation info) {//分类System.out.println(info.getCategory());//公司System.out.println(info.getCompany());}/*** 关闭输入流** @param is*/private void closeStream(InputStream is) {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}
}

通过HWPFDocument读文件

HWPFDocument是当前Word文档的代表,它的功能比WordExtractor要强。通过它我们可以读取文档中的表格、列表等,还可以对文档的内容进行新增、修改和删除操作。只是在进行完这些新增、修改和删除后相关信息是保存在HWPFDocument中的,也就是说我们改变的是HWPFDocument,而不是磁盘上的文件。如果要使这些修改生效的话,我们可以调用HWPFDocument的write方法把修改后的HWPFDocument输出到指定的输出流中。这可以是原文件的输出流,也可以是新文件的输出流(相当于另存为)或其它输出流。

@Test
public void testReadByDoc() throws Exception {InputStream is = new FileInputStream("test.doc");HWPFDocument doc = new HWPFDocument(is);//输出书签信息this.printInfo(doc.getBookmarks());//输出文本System.out.println(doc.getDocumentText());Range range = doc.getRange();//  this.insertInfo(range);this.printInfo(range);//读表格this.readTable(range);//读列表this.readList(range);//删除rangeRange r = new Range(2, 5, doc);r.delete();//在内存中进行删除,如果需要保存到文件中需要再把它写回文件//把当前HWPFDocument写到输出流中doc.write(new FileOutputStream("test.doc"));this.closeStream(is);
}/*** 关闭输入流* @param is*/
private void closeStream(InputStream is) {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}
}/*** 输出书签信息* @param bookmarks*/
private void printInfo(Bookmarks bookmarks) {int count = bookmarks.getBookmarksCount();System.out.println("书签数量:" + count);Bookmark bookmark;for (int i=0; i<count; i++) {bookmark = bookmarks.getBookmark(i);System.out.println("书签" + (i+1) + "的名称是:" + bookmark.getName());System.out.println("开始位置:" + bookmark.getStart());System.out.println("结束位置:" + bookmark.getEnd());}
}/*** 读表格* 每一个回车符代表一个段落,所以对于表格而言,每一个单元格至少包含一个段落,每行结束都是一个段落。* @param range*/
private void readTable(Range range) {System.out.println("=============readTable start================");//遍历range范围内的table。TableIterator tableIter = new TableIterator(range);Table table;TableRow row;TableCell cell;while (tableIter.hasNext()) {table = tableIter.next();int rowNum = table.numRows();for (int j=0; j<rowNum; j++) {row = table.getRow(j);int cellNum = row.numCells();for (int k=0; k<cellNum; k++) {cell = row.getCell(k);//输出单元格的文本System.out.print(cell.text().trim()+"   ");}System.out.println();}}System.out.println("=============readTable end==============");
}/*** 读列表* @param range*/
private void readList(Range range) {System.out.println("=========readList  start==========");int num = range.numParagraphs();Paragraph para;for (int i=0; i<num; i++) {para = range.getParagraph(i);if (para.isInList()) {System.out.println("list: " + para.text());}}System.out.println("=========readList  end==========");
}/*** 输出Range* @param range*/
private void printInfo(Range range) {//获取段落数int paraNum = range.numParagraphs();System.out.println(paraNum);for (int i=0; i<paraNum; i++) {System.out.println("段落" + (i+1) + ":" + range.getParagraph(i).text());if (i == (paraNum-1)) {this.insertInfo(range.getParagraph(i));}}int secNum = range.numSections();System.out.println(secNum);Section section;for (int i=0; i<secNum; i++) {section = range.getSection(i);System.out.println(section.getMarginLeft());System.out.println(section.getMarginRight());System.out.println(section.getMarginTop());System.out.println(section.getMarginBottom());System.out.println(section.getPageHeight());System.out.println(section.text());}
}/*** 插入内容到Range,这里只会写到内存中* @param range*/
private void insertInfo(Range range) {range.insertAfter("Hello");
}

写word doc文件

在实际应用中,我们在生成word文件的时候都是生成某一类文件,该类文件的格式是固定的,只是某些字段不一样罢了。所以在实际应用中,我们大可不必将整个word文件的内容都通过HWPFDocument生成。而是先在磁盘上新建一个word文档,其内容就是我们需要生成的word文件的内容,然后把里面一些属于变量的内容使用类似于“${paramName}”这样的方式代替。这样我们在基于某些信息生成word文件的时候,只需要获取基于该word文件的HWPFDocument,然后调用Range的replaceText()方法把对应的变量替换为对应的值即可,之后再把当前的HWPFDocument写入到新的输出流中。这种方式在实际应用中用的比较多,因为它不但可以减少我们的工作量,还可以让文本的格式更加的清晰。下面我们就来基于这种方式做一个示例。

​ 假设我们现在拥有一些变动的信息,然后需要通过这些信息生成如下格式的word doc文件:model.doc

${title}报告

姓名 年龄 生日
${name} ${age} ${birthday}

替换模版中的变量,生成新的doc文件

@Test
public void testWrite() throws Exception {String templatePath = "model.doc";InputStream is = new FileInputStream(templatePath);HWPFDocument doc = new HWPFDocument(is);Range range = doc.getRange();range.replaceText("${title}", "体检");range.replaceText("${name}", "张三");range.replaceText("${age}", "22");range.replaceText("${birthday}", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));OutputStream os = new FileOutputStream("new.doc");//把doc输出到输出流中doc.write(os);os.close();is.close();
}

Word(XWPF)

API文档:https://poi.apache.org/apidocs/4.0/index.html

XWPFDocument

这是 org.apache.poi.xwpf.usermodel 包下的类。 它用于创建.docx文件格式的MS-Word文档。

类方法:

No. 方法和说明
1 commit()提交并保存文档。
2 createParagraph()在本文档中追加一个新段落。
3 createTable()默认情况下,创建一个包含一行和一列的空表。
4 createTOC()创建Word文档的内容表。
5 getParagraphs()返回包含页眉或页脚文本的段落。
6 getStyle()返回使用的样式对象。

XWPFParagraph

这是 org.apache.poi.xwpf.usermodel 包下的类,用于在Word文档中创建段落。 此实例也用于将所有类型的元素添加到Word文档中。

类方法:

No. 方法和说明
1 createRun()将新运行附加到此段落。
2 getAlignment()返回将应用于本段文本的段落对齐方式。
3 setAlignment(ParagraphAlignment align)指定应适用于本段文本的段落对齐方式。
4 setBorderBottom(Borders border)指定应显示在一组段落下方的边框,这些段落具有相同的一组段落边框设置。
5 setBorderLeft(Borders border)指定应在页面左侧围绕指定段落显示的边框。
6 setBorderRight(Borders border)指定应在页面右侧围绕指定段落显示的边框。
7 setBorderTop(Borders border)指定应显示在具有相同的一组段落边框设置的一组段落上方的边框。

XWPFRun

这是 org.apache.poi.xwpf.usermodel 包下的类,用于向段落中添加文本区域。

类方法:

No. 方法和说明
1 addBreak()指定断点应放置在运行内容的当前位置。
2 addTab()指定制表符应放置在运行内容中的当前位置。
3 setColor(java.lang.String rgbStr)设置文本颜色。
4 setFontSize(int size)指定在显示时应用于此运行内容中所有非复杂脚本字符的字体大小。
5 setText(java.lang.String value)设置此文本运行的文本。
6 setBold(boolean value)指定在文档中显示时,粗体属性是否应用于此运行内容中的所有非复杂脚本字符。

XWPFStyle

这是 org.apache.poi.xwpf.usermodel 包下的类,用于向word文档中的对象元素添加不同的样式。

类方法:

No. 方法和说明
1 getNextStyleID()它用于获取下一个样式的StyleID。
2 getStyleId()它用于获取样式的StyleID。
3 getStyles()它用于获取样式。
4 setStyleId(java.lang.String styleId)它用于设置styleID。

XWPFTable

这是 org.apache.poi.xwpf.usermodel 包下的类,用于将表数据添加到Word文档中。

类方法:

No. 方法和说明
1 addNewCol()为此表中的每一行添加一个新列。
2 addRow(XWPFTableRow row)向表中添加新行
3 addRow(XWPFTableRow row, int pos)向表中指定位置添加新行
4 createRow()创建一个新的XWPFTableRow对象,其具有与那一刻定义的列数一样多的单元格。
5 setWidth(int width)设置列的宽度。

XWPFWordExtractor

这是 org.apache.poi.xwpf.extractor 包下的类。 它是一个基本的解析器类,用于从Word文档中提取简单文本。

类方法:

No. 方法和说明
1 getText()检索文档中的所有文本。

Apache POI Word - 文件

创建空白文档

@Test
public void createDocument() throws IOException {XWPFDocument document= new XWPFDocument();FileOutputStream out = new FileOutputStream(new File("createdocument.docx"));document.write(out);out.close();
}

Apache POI Word - 段落

创建段落

首先创建一个文档,然后我们可以创建一个段落。

XWPFDocument document = new XWPFDocument();
XWPFParagraph paragraph = document.createParagraph();

运行段落

您可以使用运行输入文本或任何对象元素。 使用Paragraph实例,您可以创建运行

XWPFRun run = paragraph.createRun();

写入段落

run.setText("Hello World");

完整代码

@Test
public void createParagraph() throws IOException {XWPFDocument document = new XWPFDocument();FileOutputStream out = new FileOutputStream(new File("createparagraph.docx"));XWPFParagraph paragraph = document.createParagraph();XWPFRun run = paragraph.createRun();run.setText("Hello World");document.write(out);out.close();
}

Apache POI Word - 边框

应用边框

以下代码用于在文档中应用边框:

@Test
public void applyingBorder() throws IOException {XWPFDocument document= new XWPFDocument();FileOutputStream out = new FileOutputStream(new File("applyingborder.docx"));XWPFParagraph paragraph = document.createParagraph();XWPFRun run=paragraph.createRun();run.setText("您将学习如何使用Java编程将边框应用到段落。");paragraph.setBorderBottom(Borders.SINGLE);paragraph.setBorderLeft(Borders.SINGLE);paragraph.setBorderRight(Borders.SINGLE);paragraph.setBorderTop(Borders.SINGLE);document.write(out);out.close();
}

Apache POI Word - 表格

创建表

@Test
public void createTable() throws IOException {XWPFDocument document= new XWPFDocument();FileOutputStream out = new FileOutputStream(new File("create_table.docx"));//create tableXWPFTable table = document.createTable();//create first rowXWPFTableRow tableRowOne = table.getRow(0);tableRowOne.getCell(0).setText("col one, row one");tableRowOne.addNewTableCell().setText("col two, row one");tableRowOne.addNewTableCell().setText("col three, row one");//create second rowXWPFTableRow tableRowTwo = table.createRow();tableRowTwo.getCell(0).setText("col one, row two");tableRowTwo.getCell(1).setText("col two, row two");tableRowTwo.getCell(2).setText("col three, row two");//create third rowXWPFTableRow tableRowThree = table.createRow();tableRowThree.getCell(0).setText("col one, row three");tableRowThree.getCell(1).setText("col two, row three");tableRowThree.getCell(2).setText("col three, row three");document.write(out);out.close();
}

Apache POI Word - 字体样式和对齐方式

通常,字体样式包含:字体大小,类型,粗体,斜体和下划线。 对齐分为左,中,右,对齐。

字体样式

@Test
public void fontStyle() throws IOException {XWPFDocument document= new XWPFDocument();//Write the Document in file systemFileOutputStream out = new FileOutputStream(new File("fontstyle.docx"));//create paragraphXWPFParagraph paragraph = document.createParagraph();//Set Bold an ItalicXWPFRun paragraphOneRunOne = paragraph.createRun();paragraphOneRunOne.setBold(true); //加粗paragraphOneRunOne.setItalic(true);//斜体paragraphOneRunOne.setText("Font Style");paragraphOneRunOne.addBreak();//Set text PositionXWPFRun paragraphOneRunTwo = paragraph.createRun();paragraphOneRunTwo.setUnderline(UnderlinePatterns.SINGLE); //下划线paragraphOneRunTwo.setText("Font Style two");paragraphOneRunTwo.setTextPosition(30);//Set Strike through and Font Size and SubscriptXWPFRun paragraphOneRunThree = paragraph.createRun();paragraphOneRunThree.setStrike(true);paragraphOneRunThree.setFontSize(18);paragraphOneRunThree.setSubscript(VerticalAlign.SUBSCRIPT);paragraphOneRunThree.setText(" Different Font Styles");document.write(out);out.close();
}

对齐方式

以下代码用于设置与段落文本的对齐方式:

@Testpublic void alignParagraph() throws IOException {XWPFDocument document= new XWPFDocument();FileOutputStream out = new FileOutputStream(new File("alignparagraph.docx"));//create paragraphXWPFParagraph paragraph = document.createParagraph();//Set alignment paragraph to RIGHTparagraph.setAlignment(ParagraphAlignment.RIGHT);XWPFRun run=paragraph.createRun();run.setText("At tutorialspoint.com, we strive hard to " +"provide quality tutorials for self-learning " +"purpose in the domains of Academics, Information " +"Technology, Management and Computer Programming " +"Languages.");//Create Another paragraphparagraph=document.createParagraph();//Set alignment paragraph to CENTERparagraph.setAlignment(ParagraphAlignment.CENTER);run=paragraph.createRun();run.setText("The endeavour started by Mohtashim, an AMU " +"alumni, who is the founder and the managing director " +"of Tutorials Point (I) Pvt. Ltd. He came up with the " +"website tutorialspoint.com in year 2006 with the help" +"of handpicked freelancers, with an array of tutorials" +" for computer programming languages. ");document.write(out);out.close();}

操作word模板并生成新的word.docx

要具体操作通过XWPFDocument 可以获得的docx中的各种对象,我们离不开一个对象为XWPFRun对象,API结构org.apache.poi.xwpf.usermodel.XWPFRun。其描述为:XWPFRun object defines a region of text with a common set of properties。通过描述我们不难理解其作用为设置文本对象的各种属性。
通过XWPFDocument 获取对象

//解析docx模板并获取document对象
XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));
//获取整个文本对象
List<XWPFParagraph> allParagraph = document.getParagraphs();
//获取整个表格对象
List<XWPFTable> allTable = document.getTables();
//获取图片对象
XWPFPictureData pic = document.getPictureDataByID("PICId");

首先建一个很简单的word模板model.docx,我们通过操作对象获取word中的文本内容

姓名: ${name}

性别: ${sex}

​ 需要替换的表格

家庭地址 电话 邮箱
${address} ${phone} ${email}

​ 需要插入的表格

电话 QQ 微信 微博
package com.newland.poi.word;import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.xwpf.usermodel.*;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;/*** @author 张宝奎* @date 2021/3/16*/
public class WordTemplateUtil {/*** 根据模板生成新word文档* 判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入** @param inputUrl  模板存放地址* @param outputUrl 新文档存放地址* @param textMap   需要替换的信息集合* @param tableList 需要插入的表格信息集合* @return 成功返回true, 失败返回false*/public static boolean changWord(String inputUrl, String outputUrl, Map<String, String> textMap, List<String[]> tableList) {//模板转换默认成功boolean changeFlag = true;try {//获取docx解析对象XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage(inputUrl));//解析替换文本段落对象WordTemplateUtil.changeText(document, textMap);//解析替换表格对象WordTemplateUtil.changeTable(document, textMap, tableList);//生成新的wordFile file = new File(outputUrl);FileOutputStream stream = new FileOutputStream(file);document.write(stream);stream.close();} catch (IOException e) {e.printStackTrace();changeFlag = false;}return changeFlag;}/*** 替换段落文本** @param document docx解析对象* @param textMap  需要替换的信息集合*/public static void changeText(XWPFDocument document, Map<String, String> 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) {//替换模板原来位置run.setText(changeValue(run.toString(), textMap), 0);}}}}/*** 替换表格对象方法** @param document  docx解析对象* @param textMap   需要替换的信息集合* @param tableList 需要插入的表格信息集合*/public static void changeTable(XWPFDocument document, Map<String, String> textMap,List<String[]> tableList) {//获取表格对象集合List<XWPFTable> tables = document.getTables();for (int i = 0; i < tables.size(); i++) {//只处理行数大于等于2的表格,且不循环表头XWPFTable table = tables.get(i);if (table.getRows().size() > 1) {//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入if (checkText(table.getText())) {List<XWPFTableRow> rows = table.getRows();//遍历表格,并替换模板eachTable(rows, textMap);} else {//                  System.out.println("插入"+table.getText());insertTable(table, tableList);}}}}/*** 遍历表格** @param rows    表格行对象* @param textMap 需要替换的信息集合*/public static void eachTable(List<XWPFTableRow> rows, Map<String, String> textMap) {for (XWPFTableRow row : rows) {List<XWPFTableCell> cells = row.getTableCells();for (XWPFTableCell cell : cells) {//判断单元格是否需要替换if (checkText(cell.getText())) {List<XWPFParagraph> paragraphs = cell.getParagraphs();for (XWPFParagraph paragraph : paragraphs) {List<XWPFRun> runs = paragraph.getRuns();for (XWPFRun run : runs) {run.setText(changeValue(run.toString(), textMap), 0);}}}}}}/*** 为表格插入数据,行数不够添加新行** @param table     需要插入数据的表格* @param tableList 插入数据集合*/public static void insertTable(XWPFTable table, List<String[]> tableList) {//创建行,根据需要插入的数据添加新行,不处理表头for (int i = 1; i < tableList.size(); i++) {XWPFTableRow row = table.createRow();}//遍历表格插入数据List<XWPFTableRow> rows = table.getRows();for (int i = 1; i < rows.size(); i++) {XWPFTableRow newRow = table.getRow(i);List<XWPFTableCell> cells = newRow.getTableCells();for (int j = 0; j < cells.size(); j++) {XWPFTableCell cell = cells.get(j);cell.setText(tableList.get(i - 1)[j]);}}}/*** 判断文本中时候包含$** @param text 文本* @return 包含返回true, 不包含返回false*/public static boolean checkText(String text) {boolean check = false;if (text.indexOf("$") != -1) {check = true;}return check;}/*** 匹配传入信息集合与模板** @param value   模板需要替换的区域* @param textMap 传入信息集合* @return 模板需要替换区域信息集合对应值*/public static String changeValue(String value, Map<String, String> textMap) {Set<Map.Entry<String, String>> textSets = textMap.entrySet();for (Map.Entry<String, String> textSet : textSets) {//匹配模板与替换值 格式${key}String key = "${" + textSet.getKey() + "}";if (value.indexOf(key) != -1) {value = textSet.getValue();}}//模板未匹配到区域替换为空if (checkText(value)) {value = "";}return value;}public static void main(String[] args) {//模板文件地址String inputUrl = "model.docx";//新生产的模板文件String outputUrl = "new.docx";Map<String, String> testMap = new HashMap<String, String>();testMap.put("name", "小明");testMap.put("sex", "男");testMap.put("address", "软件园");testMap.put("phone", "88888888");List<String[]> testList = new ArrayList<String[]>();testList.add(new String[]{"1", "1AA", "1BB", "1CC"});testList.add(new String[]{"2", "2AA", "2BB", "2CC"});testList.add(new String[]{"3", "3AA", "3BB", "3CC"});testList.add(new String[]{"4", "4AA", "4BB", "4CC"});WordTemplateUtil.changWord(inputUrl, outputUrl, testMap, testList);}}

Apache POI学习笔记相关推荐

  1. 09Apache POI学习笔记

    Apache POI学习笔记 文章目录 1 Poi介绍 1.1 poi简介 1.2 依赖包 1.3 POI包结构 1.4 优劣势 2 入门案例 2.1 从Excel文件读取数据 2.1.1 读取步骤 ...

  2. POI学习笔记 自定义颜色

    http://yunzhongxia.iteye.com/blog/561425 http://yunzhongxia.iteye.com/blog/558998 项目中经常要解析和生成Excel文件 ...

  3. EasyExcel和POI学习笔记

    EasyExcel和POI使用详解 一.Poi-Excel 写 1.常规入门 POI是Apache软件基金会的,POI为"Poor Obfuscation Implementation&qu ...

  4. Apache Drill学习笔记一:环境搭建和简单试用

    简介 Apache Drill是一个低延迟的分布式海量数据(涵盖结构化.半结构化以及嵌套数据)交互式查询引擎,使用ANSI SQL兼容语法,支持本地文件.HDFS.HBase.MongoDB等后端存储 ...

  5. Apache Log4j 学习笔记

    Apache Logging Project Homepage: http://logging.apache.org Log4j的类图 Logger - 日志写出器,供程序员输出日志信息 Append ...

  6. Apache服务器学习笔记

    Apache服务器知识 首先我们要知道一共有那几个程序在监听网络端口,即与网络保持活跃连接,打开CMD命令窗口 输入: netstat  –an 指令就能显示出所有与网络保持连接的程序,输入net s ...

  7. 文件用户Apache shiro学习笔记+ spring整合shiro (一)

    改章节朋友在青岛游玩的时候突然想到的...这两天就有想写几篇关于文件用户的博客,所以回家到之后就奋笔疾书的写出来发表了 Apache Shiro官网:http://shiro.apache.org/ ...

  8. Apache Camel学习笔记

    Apache Camel:         概念:是一个基于 规则路由 和 processor处理 的引擎.             官网介绍:Camel允许您创建企业集成模式,以基于Java的域特定 ...

  9. Apache kylin学习笔记

    一.Apache kylin的核心概念 表(Table ):表定义在hive中,是数据立方体(Data cube)的数据源,在build cube 之前,必须同步在 kylin中. 模型(model) ...

最新文章

  1. java出现no XXX in java.library.path的解决办法及eclipse配置
  2. java try-with-resource语句使用
  3. Sublime Text 3 注册激活码
  4. 关于:以前的某个程序安装已在安装计算机上创建挂起的文件操作 解决办法
  5. vc mysql_vc6.0连接mysql数据库
  6. 15. HTML 块 div span
  7. 如何在单元里植入图片html,单元格用HTML显示图片
  8. CG-光栅图形学区域填充算法-学习笔记
  9. java导出excel超出65536条处理
  10. 计算机操作系统第三次作业,操作系统第三次作业参考答案
  11. STM32F103ZET6+ADF4351+HMI串口屏
  12. mil mm 单位换算
  13. TA进阶实例33(Unreal制作魔兽世界透视效果)
  14. [ScyllaHide] 02 InjectorCLI源码分析
  15. 如何做推广?利用今日头条吸引大量精准粉丝
  16. 微信公众号数据2019_2019年2月全国Top100购物中心微信公众号榜单
  17. 【POJ】 1014 Dividing(多重背包,优化)
  18. Canvas实现微信大转盘抽奖代码
  19. TCP协议与HTTP协议的区别
  20. 蔡徐坤打篮球and源码

热门文章

  1. 久其报表大厅_天下苦“数”久矣,大数据分析平台解决物流数据孤岛
  2. 容器入门(1) - 安装和使用Docker Registry
  3. 在Pandas DataFrame中重塑数据
  4. Redis 6.0.0 GA
  5. 使用Visual Studio Code进行由内而外的C#开发
  6. 用于CRUD和更多的模型驱动的RESTful API
  7. python定义一个类怎么弄_Python怎么创建一个类
  8. mysql json 引号 双引号_关于JSON字符串key缺少双引号的解决方法 的讲解
  9. 74ls390设计任意进制计数器_利用数字频率合成技术设计高速任意波形发生器(上)...
  10. mysql 查询判断手机号