Java iText7中已添加至文档的Link链接文本如何修改才能生效
问题原因
你修改Link文本不生效的核心原因是:当你把Link实例放入Paragraph、再加入Cell、最终把Table添加到Document后,Link的初始文本已经被转换为布局节点里的静态文本内容,后续对原Link实例调用setText()方法,并不会同步更新已经挂载到文档元素树里的对应文本节点,immediateFlush=false只是禁止内容立即写入输出流,不支持回溯修改已添加元素的内部子内容。
解决方案
iText7生成动态页码目录的标准实现逻辑是先渲染所有正文内容,记录每个章节对应的目标名称和页码映射,再生成目录插入到文档最前面,不需要提前写占位内容,修正后的可运行代码如下:
public class UpdateLinkTest { PdfDocument pdfDocument = null; Color hyperlinkColor = new DeviceRgb(0, 102, 204); public static void main(String[] args) throws Exception { List<String[]> notes = new ArrayList<>(); notes.add(new String[] {"me", "title", "this is my text" }); notes.add(new String[] {"me2", "title2", "this is my text 2" }); new UpdateLinkTest().exportPdf(notes, new File("./test2.pdf")); } public void exportPdf(List<String[]> notes, File selectedFile) throws Exception { PdfWriter pdfWriter = new PdfWriter(selectedFile); pdfDocument = new PdfDocument(pdfWriter); Document document = new Document(pdfDocument, PageSize.A4, false); // 第一步:先渲染所有正文,记录每个章节的页码 Map<Integer, Integer> chapterPageMap = new HashMap<>(); addNotesText(notes, document, chapterPageMap); // 第二步:生成目录,插入到文档第一页前面 pdfDocument.addNewPage(1, PageSize.A4); document.getRenderer().setCurrentPage(1); addSummaryTable(notes, document, chapterPageMap); document.close(); } private void addSummaryTable(List<String[]> notes, Document document, Map<Integer, Integer> chapterPageMap) { Table table = new Table(3); float pageWidth = PageSize.A4.getWidth(); table.setWidth(pageWidth-document.getLeftMargin()*2); // 表头 addCell("Author", table, true); addCell("Title", table, true); addCell("Page", table, true); int count = 0; for (String[] note : notes) { addCell(note[0], table, false); addCell(note[1], table, false); // 直接用提前拿到的页码创建Link Integer pageNum = chapterPageMap.get(count+1); Link link = new Link(String.valueOf(pageNum), PdfAction.createGoTo(""+ (count+1))); addCell(link, hyperlinkColor, table, false); count++; } document.add(table); } private void addNotesText(List<String[]> notes, Document document, Map<Integer, Integer> chapterPageMap) throws Exception { int count = 0; for (String[] note : notes) { count++; // 记录当前章节开始的页码 chapterPageMap.put(count, pdfDocument.getNumberOfPages() + 1); Paragraph noteText = new Paragraph(note[2]); noteText.setDestination(count+""); document.add(noteText); if (note != notes.get(notes.size()-1)) { document.add(new AreaBreak(AreaBreakType.NEXT_PAGE)); } } } private static void addCell(String text, Table table, boolean isHeader) { Cell c1 = new Cell().add(new Paragraph(text)); table.addCell(c1); } private static void addCell(Link link, Color fontColor, Table table, boolean isHeader) { Cell c1 = new Cell().add(new Paragraph(link)); link.setUnderline(); link.setFontColor(fontColor); table.addCell(c1); } }
关键修改点
- 调整了渲染顺序,先渲染正文拿到每个章节的实际页码,再生成目录
- 目录直接插入到文档的第一页位置,不需要提前写占位内容
- 去掉了无用的Link列表存储逻辑,直接根据提前记录的页码映射创建正确的目录链接
内容的提问来源于stack exchange,提问作者deccles
相关产品推荐
相关产品推荐

