package org.example.databaseword.util;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.*;
import com.itextpdf.layout.properties.TabAlignment;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.example.databaseword.entity.Catalogue;
import org.example.databaseword.mapper.TableMapper;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.*;
import java.util.List;
@Slf4j
@Component
public class TableUtil
{
@Resource
TableMapper tableMapper;
// 配置常量
private static final float[] TABLE_COLUMN_WIDTHS = {1, 2, 1, 1, 1, 2};
private static final String[] TABLE_HEADERS = {"字段名", "类型", "长度", "NULL", "默认值", "注释"};
public void toPdf(List<Map<String, Object>> tables, String fileName, String title)
{
validateParameters(tables, fileName, title);
try (PdfWriter writer = new PdfWriter(fileName);
PdfDocument pdf = new PdfDocument(writer);
Document document = new Document(pdf))
{
// 初始化字体
PdfFont contentFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
// 添加封面页
addCoverPage(document, title, contentFont);
//预生成目录数据
List<Catalogue> tocEntries = preGenerateTocEntries(tables);
//在封面后插入目录
insertTableOfContents(document, tocEntries);
// 生成表结构内容
generateTableContentWithToc(document, tables, contentFont);
log.info("PDF生成成功: {}", fileName);
} catch (IOException e) {
log.error("PDF生成失败", e);
throw new RuntimeException("PDF生成失败: " + e.getMessage(), e);
}
}
// 预生成目录条目
private List<Catalogue> preGenerateTocEntries(List<Map<String, Object>> tables) {
List<Catalogue> entries = new ArrayList<>();
int currentPage = 3; // 封面(1) + 目录(2) = 内容从第3页开始
for (Map<String, Object> tableMap : tables) {
String tableName = getStringValue(tableMap, "TABLE_NAME");
String tableComment = getStringValue(tableMap, "TABLE_COMMENT");
entries.add(new Catalogue(tableName + (tableComment.isEmpty() ? "" : " (" + tableComment + ")"),
currentPage
));
}
return entries;
}
//在封面后添加目录
private void insertTableOfContents(Document document, List<Catalogue> tocEntries) throws IOException {
PdfFont CatalogueTitleFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
// 添加目录标题
Paragraph tocTitle = new Paragraph("目录")
.setFont(CatalogueTitleFont)
.setFontSize(16)
.setBold()
.setTextAlignment(TextAlignment.CENTER)
.setMarginBottom(20);
document.add(tocTitle);
// 添加目录内容
for (Catalogue entry : tocEntries) {
Paragraph tocItem = new Paragraph()
.add(entry.getTitle())
.addTabStops(new TabStop(500, TabAlignment.RIGHT))
.add(new Tab())
.add(String.valueOf(entry.getPageNumber()))
.setMarginBottom(5);
document.add(tocItem);
}
document.add(new AreaBreak());
}
/*
* 生成表内容
*/
private void generateTableContentWithToc(Document document, List<Map<String, Object>> tables,
PdfFont contentFont)
{
int pageNum = 3;
for (Map<String, Object> tableMap : tables)
{
String tableName = getStringValue(tableMap, "TABLE_NAME");
String tableComment = getStringValue(tableMap, "TABLE_COMMENT");
// 添加表标题
addTableTitle(document, tableName, tableComment, contentFont);
// 创建并填充表格
Table pdfTable = createTableWithHeader(contentFont);
fillTableContent(pdfTable, tableName, contentFont);
document.add(pdfTable);
}
}
/**
* 验证输入参数
*/
private void validateParameters(List<Map<String, Object>> tables, String fileName, String title)
{
Objects.requireNonNull(tables, "表信息列表不能为null");
Objects.requireNonNull(fileName, "文件名不能为null");
Objects.requireNonNull(title, "标题不能为null");
if (tables.isEmpty())
{
throw new IllegalArgumentException("表信息列表不能为空");
}
if (fileName.trim().isEmpty())
{
throw new IllegalArgumentException("文件名不能为空");
}
}
/**
* 添加封面页
*/
private void addCoverPage(Document document, String title, PdfFont titleFont)
{
Paragraph titleParagraph = new Paragraph(title)
.setFont(titleFont)
.setFontSize(24)
.setTextAlignment(TextAlignment.CENTER)
.setMarginBottom(20);
document.add(titleParagraph);
document.add(new Paragraph("\n")); // 添加空行
document.add(new AreaBreak());
}
/**
* 添加表标题
*/
private void addTableTitle(Document document, String tableName, String tableComment, PdfFont font)
{
Paragraph tableTitle = new Paragraph("表名: " + tableName + " (" + tableComment + ")")
.setFont(font)
.setFontSize(12)
.setTextAlignment(TextAlignment.CENTER)
.setMarginBottom(10);
document.add(tableTitle);
}
/**
* 创建带表头的表格
*/
private Table createTableWithHeader(PdfFont headerFont)
{
Table table = new Table(UnitValue.createPercentArray(TABLE_COLUMN_WIDTHS));
table.setWidth(UnitValue.createPercentValue(100));
// 添加表头
for (String header : TABLE_HEADERS)
{
Cell cell = new Cell()
.add(new Paragraph(header).setFont(headerFont).setFontSize(10))
.setBackgroundColor(ColorConstants.LIGHT_GRAY)
.setTextAlignment(TextAlignment.CENTER);
table.addHeaderCell(cell);
}
return table;
}
/**
* 填充表格内容
*/
private void fillTableContent(Table table, String tableName, PdfFont contentFont)
{
List<Map<String, Object>> fields = getTable(tableName);
for (Map<String, Object> field : fields)
{
table.addCell(createContentCell(getStringValue(field, "COLUMN_NAME"), contentFont));
table.addCell(createContentCell(getStringValue(field, "DATA_TYPE"), contentFont));
table.addCell(createContentCell(getStringValue(field, "CHARACTER_MAXIMUM_LENGTH"), contentFont));
table.addCell(createContentCell(getStringValue(field, "IS_NULLABLE"), contentFont));
table.addCell(createContentCell(getStringValue(field, "COLUMN_DEFAULT"), contentFont));
table.addCell(createContentCell(getStringValue(field, "COLUMN_COMMENT"), contentFont));
}
}
/**
* 安全获取字符串值
*/
private String getStringValue(Map<String, Object> map, String key)
{
Object valueObj = map.getOrDefault(key, "");
return valueObj instanceof String ? (String) valueObj :
(valueObj == null ? "" : valueObj.toString());
}
/**
* 从数据库中获取表字段信息
*/
private List<Map<String, Object>> getTable(String tableName)
{
try
{
return tableMapper.getTable(tableName);
} catch (Exception e)
{
log.error("查询表结构失败: {}", tableName, e);
throw new RuntimeException("查询表结构失败: " + tableName, e);
}
}
/**
* 创建内容单元格
*/
private Cell createContentCell(String text, PdfFont font)
{
return new Cell()
.add(new Paragraph(text).setFont(font).setFontSize(9))
.setTextAlignment(TextAlignment.CENTER);
}
}
在我的代码中使用除了封面页和目录页每页添加页码然后用每个表的表名去判断当前页码然后生成目录页码
最新发布