一、需求
根据数据库生成文档,文档包含大量表格,表格数量不确定,每个表格行数也不确定。
二、实现方案
引入依赖
xml
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.4</version>
</dependency>
代码实现
-
静态常量
javapublic static final int FONT_SIZE = 9; public static final TitleStyle[] titleStyles = { new TitleStyle("一级标题", 44, true), new TitleStyle("二级标题", 36, true), new TitleStyle("三级标题", 32, true), new TitleStyle("四级标题", 30, false)}; public record TitleStyle(String name, int fontSize, boolean bold) { }
-
创建文档
java/** * A3 Portrait 16840 23814 720 * A3 Landscape 23814 16940 720 * A4 Portrait 11907 16840 720 * A4 Landscape 16840 11907 720 */ public void createDocument(int width, int height, int top, int right, int bottom, int left) { XWPFDocument document = new XWPFDocument(); CTSectPr sectPr = document.getDocument().getBody().addNewSectPr(); CTPageSz pageSz = sectPr.addNewPgSz(); pageSz.setW(BigInteger.valueOf(width)); pageSz.setH(BigInteger.valueOf(height)); pageSz.setOrient(width > height ? STPageOrientation.LANDSCAPE : STPageOrientation.PORTRAIT); CTPageMar pageMar = sectPr.addNewPgMar(); pageMar.setTop(BigInteger.valueOf(top)); pageMar.setRight(BigInteger.valueOf(right)); pageMar.setBottom(BigInteger.valueOf(bottom)); pageMar.setLeft(BigInteger.valueOf(left)); for (int i = 0; i < titleStyles.length; i++) { addCustomHeadingStyle(document, titleStyles[i], i + 1); } } private static void addCustomHeadingStyle(XWPFDocument document, TitleStyle titleStyle, int headingLevel) { CTStyle ctStyle = CTStyle.Factory.newInstance(); ctStyle.setStyleId(titleStyle.name()); CTString styleName = CTString.Factory.newInstance(); styleName.setVal(titleStyle.name()); ctStyle.setName(styleName); CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance(); indentNumber.setVal(BigInteger.valueOf(headingLevel)); // lower number > style is more prominent in the formats bar ctStyle.setUiPriority(indentNumber); CTOnOff onOffNull = CTOnOff.Factory.newInstance(); ctStyle.setUnhideWhenUsed(onOffNull); // style shows up in the formats bar ctStyle.setQFormat(onOffNull); // style defines a heading of the given level CTPPr ppr = CTPPr.Factory.newInstance(); ppr.setOutlineLvl(indentNumber); ctStyle.setPPr(ppr); CTRPr rpr = CTRPr.Factory.newInstance(); // font size CTHpsMeasure ctHpsMeasure = CTHpsMeasure.Factory.newInstance(); ctHpsMeasure.setVal(BigInteger.valueOf(titleStyle.fontSize())); rpr.setSz(ctHpsMeasure); rpr.setSzCs(ctHpsMeasure); // fond bold if (titleStyle.bold()) { CTOnOff b = rpr.addNewB(); b.setVal(STOnOff.TRUE); } ctStyle.setRPr(rpr); XWPFStyle style = new XWPFStyle(ctStyle); style.setType(STStyleType.PARAGRAPH); XWPFStyles styles = document.createStyles(); styles.addStyle(style); }
-
创建标题
javapublic void createTitle(int level, int id, String title) { XWPFParagraph paragraph = document.createParagraph(); paragraph.setStyle(titleStyles[level - 1].name()); XWPFRun run = paragraph.createRun(); run.setText(title); CTBookmark bookmark = paragraph.getCTP().addNewBookmarkStart(); bookmark.setName("bm_" + id); bookmark.setId(BigInteger.valueOf(id)); paragraph.getCTP().addNewBookmarkEnd().setId(BigInteger.valueOf(id)); }
-
创建表格
javapublic XWPFTable createTable(int width, TableTitle... titles) { XWPFTable table = document.createTable(1, titles.length); CTTblPr TblPr = table.getCTTbl().addNewTblPr(); TblPr.addNewTblLayout().setType(STTblLayoutType.FIXED); // 布局固定,不随内容改变宽度 CTTblWidth tblW = TblPr.isSetTblW() ? TblPr.getTblW() : TblPr.addNewTblW(); tblW.setType(STTblWidth.DXA); tblW.setW(BigInteger.valueOf(width)); // 表格边颜色 CTTblBorders borders = TblPr.addNewTblBorders(); tableBorderStyle(borders.addNewInsideH()); tableBorderStyle(borders.addNewInsideV()); tableBorderStyle(borders.addNewLeft()); tableBorderStyle(borders.addNewRight()); tableBorderStyle(borders.addNewTop()); tableBorderStyle(borders.addNewBottom()); XWPFTableRow row = table.getRow(0); for (int i = 0; i < titles.length; i++) { TableTitle title = titles[i]; XWPFTableCell cell = row.getCell(i); cell.setColor("3a60a0"); if (title.width() > 0) { CTTcPr ctTcPr = cell.getCTTc().addNewTcPr(); CTTblWidth tblWidth = ctTcPr.isSetTcW() ? ctTcPr.getTcW() : ctTcPr.addNewTcW(); tblWidth.setW(BigInteger.valueOf(title.width())); tblWidth.setType(STTblWidth.DXA); } XWPFParagraph paragraphArray = cell.getParagraphArray(0); XWPFRun run = paragraphArray.createRun(); run.setText(title.name()); run.setBold(true); run.setColor("f5f5f5a"); run.setFontSize(FONT_SIZE); paragraphArray.setAlignment(ParagraphAlignment.CENTER); // 水平居中 } return table; } public record TableTitle(String name, int width) { }
-
创建空行
javapublic void createBlankLine() { document.createParagraph(); }
-
创建表格行
javaXWPFTableRow row = table.createRow();
-
获取单元格
javaXWPFTableCell cell = row.getCell(0);
-
创建超链接
javapublic static void createHyperlinkRunToAnchor(XWPFParagraph paragraph, String text, int id) { paragraph.setVerticalAlignment(TextAlignment.CENTER); CTHyperlink ctHyperlink = paragraph.getCTP().addNewHyperlink(); ctHyperlink.setAnchor("bm_" + id); ctHyperlink.addNewR(); XWPFHyperlinkRun hyperlinkRun = new XWPFHyperlinkRun(ctHyperlink, ctHyperlink.getRArray(0), paragraph); hyperlinkRun.setText(text); hyperlinkRun.setColor("0000FF"); hyperlinkRun.setUnderline(UnderlinePatterns.SINGLE); hyperlinkRun.setFontSize(FONT_SIZE); } public static void createHyperlinkRunToFile(XWPFParagraph paragraph, String text, String fileName, Integer id) { paragraph.setVerticalAlignment(TextAlignment.CENTER); String uri = fileName; if (id != null) { uri += "#bm_" + id; } String rId = paragraph.getDocument().getPackagePart() .addExternalRelationship(uri, XWPFRelation.HYPERLINK.getRelation()).getId(); CTHyperlink ctHyperlink = paragraph.getCTP().addNewHyperlink(); ctHyperlink.setId(rId); ctHyperlink.addNewR(); XWPFHyperlinkRun hyperlinkRun = new XWPFHyperlinkRun(ctHyperlink, ctHyperlink.getRArray(0), paragraph); hyperlinkRun.setText(text); hyperlinkRun.setColor("0000FF"); hyperlinkRun.setUnderline(UnderlinePatterns.SINGLE); hyperlinkRun.setFontSize(FONT_SIZE); }