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);
// 图片 1
XWPFParagraph 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 file
File 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);
}
}
}
}
}