1、模板方式导出
1.1、引入 maven 依赖
<dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.12.2</version>
</dependency>
1.2、导出文档代码
public static void main(String[] args) {Map<String, Object> dataMap = new HashMap<>(16);dataMap.put("title", "标题内容");String pic1 = "C:\\Users\\HARRIS\\Desktop\\打工人.jpg";dataMap.put("pic1", pic1);dataMap.put("productCategory", Texts.of("超链接").link("http://www.baidu.com.cn").create());dataMap.put("attachRealName", Texts.of("锚点文本").anchor("custNo").create());List<Student> students = new ArrayList<>(10);students.add(new Student("张三", 18, 23.5, "111"));students.add(new Student("李四", 18, 23.5, "111"));students.add(new Student("王五", 24, 23.5, "111"));students.add(new Student("马六", 24, 23.5, "111"));List<String[]> dataList = new ArrayList<>();for (Student item : students) {dataList.add(new String[]{item.getName(), String.valueOf(item.getAge()), String.valueOf(item.getScore()),item.getPrice()});}// 创建一个列表来存储行数据RowRenderData commonTitle = Rows.of("姓名", "年龄","分数", "price").textColor("FFFFFF").bgColor("4472C4").center().create();List<RowRenderData> rows = new ArrayList<>();// 添加表头rows.add(commonTitle);// 遍历数据集合,创建 RowRenderData 对象并添加到列表中for (String[] data : dataList) {RowRenderData row = Rows.of(data).textFontFamily("仿宋_GB2312").textFontSize(9).horizontalCenter().center().create();rows.add(row);}TableRenderData table = Tables.create(rows.toArray(new RowRenderData[0]));RowRenderData totalRow = Rows.of("合计", "", "", "80%").horizontalCenter().center().create();table.addRow(totalRow);MergeCellRule.MergeCellRuleBuilder builder = MergeCellRule.builder();int[] indexArr = new int[]{1};for (int i : indexArr) {for (int j = 0; j < dataList.size() / 2; j++) {// 纵向合并单元格builder.map(MergeCellRule.Grid.of(j * 2 + 1, i), MergeCellRule.Grid.of(j * 2 + 2, i));}}// 横向合并单元格 MergeCellRule.Grid.of(x轴下标,y轴下标)builder.map(MergeCellRule.Grid.of(table.getRows().size() - 1, 0), MergeCellRule.Grid.of(table.getRows().size() - 1, 2));MergeCellRule rule = builder.build();table.setMergeRule(rule);dataMap.put("table1", table);try {//模板路径String filePath = "C:\\Users\\HARRIS\\Desktop\\testTemplate.docx";String url = "C:\\Users\\HARRIS\\Desktop\\out.docx";if (!new File(url).getParentFile().exists()) {boolean mkdir = new File(url).getParentFile().mkdirs();if (mkdir) {System.out.printf("创建%s目录%n", new File(url).getParentFile());}}//解析模板XWPFTemplate template = XWPFTemplate.compile(filePath);//渲染数据template.render(dataMap);//以文件形式输出template.writeAndClose(Files.newOutputStream(Paths.get(url)));} catch (Exception e) {throw new RuntimeException(e);}}
1.3 导出模板
1.4 导出结果
参考文档:
poi-tl 文档
poi-tl gitcode
2.1 poi 代码导出
2.1、maven 依赖
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.3</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version>
</dependency>
2.2、Java 生成 word 文档代码
try {// 创建一个文档XWPFDocument document = new XWPFDocument();// 标题XWPFParagraph title = document.createParagraph();title.setAlignment(ParagraphAlignment.CENTER);title.setStyle("Heading1");XWPFRun titleRun = title.createRun();titleRun.setFontFamily("方正小标宋简体");titleRun.setBold(true);titleRun.setFontSize(24);titleRun.setText("标题");titleRun.setColor("FF0000");// 二级标题XWPFParagraph subtitle = document.createParagraph();subtitle.setAlignment(ParagraphAlignment.CENTER);XWPFRun subtitleRun = subtitle.createRun();titleRun.setFontFamily("黑体");subtitleRun.setText("2025年");subtitleRun.setFontSize(16);// 单位XWPFParagraph institution = document.createParagraph();String institutionDate = LocalDateTime.now().getYear() + "年" + LocalDateTime.now().getMonthValue() + "月" + LocalDateTime.now().getDayOfMonth() + "日";String institutionText = "{institutionDate}XXXXXXX";institutionText = institutionText.replace("{institutionDate}", institutionDate);// 设置段落边框(仅底部边框)institution.setAlignment(ParagraphAlignment.CENTER);XWPFRun institutionRun = institution.createRun();institutionRun.setFontFamily("黑体");institutionRun.setFontSize(14);institutionRun.setText(institutionText);institution.setBorderBottom(Borders.SINGLE); // 单线样式// 关键代码:通过OpenXML设置边框CTPPr ppr = institution.getCTP().isSetPPr() ? institution.getCTP().getPPr() : institution.getCTP().addNewPPr();CTBorder border = ppr.isSetPBdr() ?ppr.getPBdr().getBottom() :ppr.addNewPBdr().addNewBottom();border.setVal(STBorder.SINGLE);border.setColor("FF0000");border.setSz(BigInteger.valueOf(24)); // 1.5磅粗institution.setSpacingAfter(50); // 增加段后间距// 内容generateContent(document, ParagraphAlignment.LEFT, false,"content",TEXT_COLOR, 16, "仿宋_GB2312", true, false);// 创建页脚策略XWPFFooter footer = document.createFooter(HeaderFooterType.FIRST);//在首页页脚中添加内容addFooterContent(footer, "footer", "000000");addFooterContent(footer, "footer");// 设置文档属性CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();CTDocGrid grid = sectPr.addNewDocGrid();grid.setType(STDocGrid.LINES);// 设置首页不同sectPr.addNewTitlePg();// 第一段generateContent(document, ParagraphAlignment.LEFT, true,"title", TEXT_COLOR, 16, "黑体", false, false);String stationMetadataQualityContent = "XXXXX";generateContent(document, ParagraphAlignment.LEFT, false, stationMetadataQualityContent,TEXT_COLOR, 16, "仿宋_GB2312", true, false);// 第二段generateContent(document, ParagraphAlignment.LEFT, true,"title", TEXT_COLOR, 16, "黑体", false, false);generateContent(document, ParagraphAlignment.LEFT, false,"XXXXXX",TEXT_COLOR, 16, "仿宋_GB2312", true, false);// 图片 1XWPFParagraph p = document.createParagraph();p.setAlignment(ParagraphAlignment.CENTER);XWPFRun run = p.createRun();// 3. 添加图片try (FileInputStream is = new FileInputStream("../data/pic/1111.jpg")) {int pictureType = Document.PICTURE_TYPE_JPEG; // 图片类型int width = Units.toEMU(400); // 宽度(200像素)int height = Units.toEMU(260); // 高度(150像素)run.addPicture(is, pictureType, "1111.jpg", width, height);} catch (InvalidFormatException e) {throw new RuntimeException(e);}// 图底部描述generateContent(document, ParagraphAlignment.CENTER, false,"图1 ", TEXT_COLOR, 16, "仿宋_GB2312", false, false);generateContent(document, ParagraphAlignment.LEFT, true,"title", TEXT_COLOR, 16, "仿宋_GB2312", false, false);generateContent(document, ParagraphAlignment.LEFT, false,"content",TEXT_COLOR, 16, "仿宋_GB2312", true, false);// 表一generateContent(document, ParagraphAlignment.CENTER, false,"表1", TEXT_COLOR, 16, "仿宋_GB2312", false, false);XWPFTable table = document.createTable();table.setWidth("100%");XWPFTableRow tableHeader = table.getRow(0);tableHeader.getCell(0).setText("序号");tableHeader.addNewTableCell().setText("XXX");tableHeader.addNewTableCell().setText("XX");tableHeader.addNewTableCell().setText("X");tableHeader.addNewTableCell().setText("XXXXXX");setTableHeaderColor(table.getRow(0), "4f81bd");addTableRow(table, "1", "XXXX", "XXXX", "XXX", "47");addTableRow(table, "2", "XXXX", "XXXXX", "XXXX", "-");setAllCellsCenterAlignment(table);// Write the document to a fileFile file = new File("../data/test/test.docx");if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}FileOutputStream out = new FileOutputStream(file);document.write(out);out.close();document.close();System.out.println("DOCX file created successfully!");} catch (IOException e) {e.printStackTrace();
}
/*** 按指定列的值合并单元格** @param table 表格对象* @param columnIndex 合并列*/private static void mergeCellsByFieldName(XWPFTable table, int columnIndex) {List<XWPFTableRow> rows = table.getRows();Map<String, MergeRange> mergeRanges = new HashMap<>();// 第一行是表头,不处理for (int rowIndex = 1; rowIndex < rows.size(); rowIndex++) {XWPFTableCell cell = rows.get(rowIndex).getCell(columnIndex);String cellValue = cell.getText();if (mergeRanges.containsKey(cellValue)) {// 继续当前合并范围MergeRange mergeRange = mergeRanges.get(cellValue);mergeRange.setEndRow(rowIndex);} else {// 开始新的合并范围mergeRanges.put(cellValue, new MergeRange(rowIndex, rowIndex));}}// 应用合并for (MergeRange range : mergeRanges.values()) {if (range.getStartRow() != range.getEndRow()) {mergeCellsVertically(table, columnIndex, range.getStartRow(), range.getEndRow());}}}// 纵向合并单元格private static void mergeCellsVertically(XWPFTable table, int col, int startRow, int endRow) {for (int rowIndex = startRow; rowIndex <= endRow; rowIndex++) {XWPFTableCell cell = table.getRow(rowIndex).getCell(col);if (rowIndex == startRow) {cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);} else {cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);}}}// 横向合并单元格private static void mergeCellsHorizontally(XWPFTable table, int row, int startCol, int endCol) {for (int colIndex = startCol; colIndex <= endCol; colIndex++) {XWPFTableCell cell = table.getRow(row).getCell(colIndex);if (colIndex == startCol) {cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);} else {cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);}}}// 设置表头样式(背景色+加粗)private static void setTableHeaderColor(XWPFTableRow headerRow, String color) {List<XWPFTableCell> tableCells = headerRow.getTableCells();for (XWPFTableCell tableCell : tableCells) {// 设置背景色setCellBackgroundColor(tableCell, color);}}// 设置单元格背景色private static void setCellBackgroundColor(XWPFTableCell cell, String rgbColor) {CTTc ctTc = cell.getCTTc();CTTcPr tcPr = ctTc.isSetTcPr() ? ctTc.getTcPr() : ctTc.addNewTcPr();// 创建填充色CTShd shd = tcPr.isSetShd() ? tcPr.getShd() : tcPr.addNewShd();shd.setFill(rgbColor); // 设置十六进制颜色值shd.setVal(STShd.CLEAR); // 必须设置为CLEAR才能显示填充色}/*** 生成段落** @param document 文档* @param paragraphAlignment 文档位置* @param contentBold 文档内容是否加粗* @param contentText 文档内容* @param contentColor 文档内容颜色* @param contentTextSize 文档内容字体大小* @param contentTextFontFamily 文档内容字体*/private static XWPFParagraph generateContent(XWPFDocument document, ParagraphAlignment paragraphAlignment, boolean contentBold,String contentText, String contentColor, Integer contentTextSize,String contentTextFontFamily, Boolean addTab, Boolean addBreak) {XWPFParagraph content = document.createParagraph();content.setAlignment(paragraphAlignment);XWPFRun contentRun = content.createRun();contentRun.setBold(contentBold);if (addTab) {contentRun.addTab();}contentRun.setColor(contentColor);contentRun.setFontSize(contentTextSize);contentRun.setFontFamily(contentTextFontFamily);contentRun.setText(contentText);if (addBreak) {contentRun.addBreak();}return content;}/*** 添加 footer 内容** @param footer* @param text* @param color*/private static void addFooterContent(XWPFFooter footer, String text, String color) {XWPFParagraph paragraph = footer.createParagraph();paragraph.setSpacingAfterLines(10);// 创建页脚段落paragraph.setAlignment(ParagraphAlignment.LEFT);// 创建页脚内容XWPFRun run = paragraph.createRun();run.setText(text);run.setColor(color);run.setFontSize(8);// 添加页脚横线(可选)addFooterLine(paragraph, 6 ,4);}/*** 添加 footer 线** @param paragraph* @param size* @param space*/private static void addFooterLine(XWPFParagraph paragraph, Integer size, Integer space) {// 通过OpenXML设置上边框作为页脚横线CTPPr ppr = paragraph.getCTP().isSetPPr() ?paragraph.getCTP().getPPr() :paragraph.getCTP().addNewPPr();CTBorder border = ppr.isSetPBdr() ?ppr.getPBdr().getTop() :ppr.addNewPBdr().addNewTop();border.setVal(STBorder.SINGLE);border.setColor("000000"); // 黑色横线border.setSz(BigInteger.valueOf(size)); // 0.75磅粗border.setSpace(BigInteger.valueOf(space)); // 与文本间距}/*** 表格单行数据填充** @param table* @param cells*/private static void addTableRow(XWPFTable table, String... cells) {XWPFTableRow row = table.createRow();for (int i = 0; i < cells.length; i++) {if (row.getCell(i) == null) {row.createCell();}row.getCell(i).setText(cells[i]);}}/*** 表格内容居中** @param table*/private static void setAllCellsCenterAlignment(XWPFTable table) {for (XWPFTableRow row : table.getRows()) {for (XWPFTableCell cell : row.getTableCells()) {// 垂直居中cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);// 水平居中for (XWPFParagraph paragraph : cell.getParagraphs()) {paragraph.setAlignment(ParagraphAlignment.CENTER);// 可选:设置段落中的文本格式for (XWPFRun run : paragraph.getRuns()) {run.setFontSize(12);}}}}}