poi-tl
poi-tl copied to clipboard
请教一下,是否有办法实现生成目录
需求的报告模板中大概包括标题、目录、前言、章节(根据模板动态生成的标题+文字+表格+图片),其中目录需要根据章节的实际情况动态生成。在网上没有找到什么好的解决方案,请教一下实现思路,非常感谢。
#13
没有研究过目录,如果用poi没有找到合适的API,可以找找一些其它处理word的jar包。
我之前也是有生成目录的需求,但poi好像没有什么好用的API。 后来只能用poi ti 生成完文档后,再用Jacob去生成目录。
我之前也是有生成目录的需求,但poi好像没有什么好用的API。 后来只能用poi ti 生成完文档后,再用Jacob去生成目录。
你好,可以分享一下代码示例吗,谢谢
我之前也是有生成目录的需求,但poi好像没有什么好用的API。 后来只能用poi ti 生成完文档后,再用Jacob去生成目录。
你好,可以分享一下代码示例吗,谢谢
你可以去搜搜下docx4j这个库去生成目录。网上有很多demo
@onlylivi
https://gist.github.com/issac21/c12885c032fc95efb43ce4d190eb1610
private void wordTemplateHandler(File file) { JacobWordUtil wordUtil = new JacobWordUtil(false); try { wordUtil.openDocument(file.getAbsolutePath()); /* 更新目录 */ wordUtil.updateTablesOfContents(); } catch (Exception e) { log.error("更新目录失败", e); throw new RuntimeException(file.getName() + ",文件更新目录失败:" + e.getMessage()); }finally { wordUtil.close(); } }
word文档中添加一个标记 :{目录}
那么就会在那个地方生成目录。(记得添加jacob的dll文件,因为jacob是调用本地的Word程序,其实就是想当于打开word,然后点击程序上的“生成目录”)
反正感觉这样比较麻烦,一直在找更好的方法
我之前也是有生成目录的需求,但poi好像没有什么好用的API。 后来只能用poi ti 生成完文档后,再用Jacob去生成目录。
你好,可以分享一下代码示例吗,谢谢
你可以去搜搜下docx4j这个库去生成目录。网上有很多demo
好的,谢谢
@onlylivi https://gist.github.com/issac21/c12885c032fc95efb43ce4d190eb1610
private void wordTemplateHandler(File file) { JacobWordUtil wordUtil = new JacobWordUtil(false); try { wordUtil.openDocument(file.getAbsolutePath()); /* 更新目录 */ wordUtil.updateTablesOfContents(); } catch (Exception e) { log.error("更新目录失败", e); throw new RuntimeException(file.getName() + ",文件更新目录失败:" + e.getMessage()); }finally { wordUtil.close(); } }
word文档中添加一个标记 :{目录} 那么就会在那个地方生成目录。(记得添加jacob的dll文件,因为jacob是调用本地的Word程序,其实就是想当于打开word,然后点击程序上的“生成目录”)反正感觉这样比较麻烦,一直在找更好的方法
我查了一下,jacob好像只能在windows平台用,真是巧了,我们的应用要部署在linux上,哎 多谢兄弟了哈
我之前也是有生成目录的需求,但poi好像没有什么好用的API。 后来只能用poi ti 生成完文档后,再用Jacob去生成目录。
你好~请问你最后文档生成成功了吗? 生成的目录要根据标题来生成,想请问你一下标题是怎么生成的呢?标题可以用poi生成吗?
@AnnaHuangPro 我的是本地有安装word的,我看了word自带的标题名称是“标题 1”之类的。所以代码中我直接使用了
XWPFParagraph titleParagraph = doc.insertNewParagraph(run); titleParagraph.setStyle("标题 1"); XWPFRun titleRun = titleParagraph.createRun(); titleRun.setFontSize(14); titleRun.setFontFamily("宋体"); titleRun.setText(title);
如果不的话,先把文档生成出来,再把想要的标题手动在word里设置保存好,然后把word转成xml,再去看xml中的属性是如何定义的。
很多样式的东西我不知道poi是如果去设置属性的,我就会看xml中的属性,对照着设置就可以了
@AnnaHuangPro 我的是本地有安装word的,我看了word自带的标题名称是“标题 1”之类的。所以代码中我直接使用了
XWPFParagraph titleParagraph = doc.insertNewParagraph(run); titleParagraph.setStyle("标题 1"); XWPFRun titleRun = titleParagraph.createRun(); titleRun.setFontSize(14); titleRun.setFontFamily("宋体"); titleRun.setText(title);
如果不的话,先把文档生成出来,再把想要的标题手动在word里设置保存好,然后把word转成xml,再去看xml中的属性是如何定义的。 很多样式的东西我不知道poi是如果去设置属性的,我就会看xml中的属性,对照着设置就可以了
好的 谢谢你哟~ 还想请问你一下 你用jacob生成目录成功了吗?
@AnnaHuangPro 使用jacob生成目录,我是成功的。 但我的数据比较多,我有时候生成的数据有1000页,这时候生成目录就会非慢,甚至会导致word假死。
@AnnaHuangPro 使用jacob生成目录,我是成功的。 但我的数据比较多,我有时候生成的数据有1000页,这时候生成目录就会非慢,甚至会导致word假死。
嗯嗯 我生成80多页也是慢得很~ 谢谢你啦~
poi有个XWPFDocument.createTOC() 提供了目录生成思路,但是没有对应页码 参看 Apache POI自动生成Word文档(带目录)
不知作者大大是否有页码的生成思路
@xiaobrid Sorry,暂时没有思路,有时间的确可以增加一个 TOCRenderPolicy这样的目录插件。
可以试试这个方法:https://my.oschina.net/u/3410302/blog/3048367。apache poi原生实现。
@xuanlv886 有空可以为poi-tl提供个目录策略的pull request吗:在指定模板位置渲染目录 ?
大佬们,有解决目录生成问题吗?在windows上平台上是目录生成比较好实现,但是我现在的需求是需要兼容windows、liunx、wps、office。太难了,目前还没有发现很好的方案。
@onlylivi @Sayi @issac21 @ucstone @AnnaHuangPro 有liunx平台生成word目录兼容wps、office的方案吗?万分感谢。
jacob生成目录方法 public void updateToc() { // 返回一个TablesOfContents 集合, 该集合代表指定文档中的目录表。 此为只读属性。 Dispatch tablesOfContents = Dispatch.call(doc, "TablesOfContents").toDispatch();// 整个目录区域 Variant tablesOfContent = Dispatch.call(tablesOfContents, "Item", new Variant(1)); /*更新目录,有两个方法:Update 更新域,UpdatePageNumbers 只更新页码/ Dispatch toc = tablesOfContent.toDispatch(); toc.call(toc, "Update"); } 不过只支持windows。
关于TOCRenderPolicy的使用,
ChessData data = new ChessData(); data.setMulu("目录"); data.setCatalog("目录"); data.setAuthor("chess"); data.setDate(new Date().toString()); ProjBase projBase = new ProjBase(); XWPFTemplate template = XWPFTemplate.compile(resource).render(data); List<MetaTemplate> elementTemplates = template.getElementTemplates(); ElementTemplate metaTemplate = (ElementTemplate)elementTemplates.get(0); TOCRenderPolicy tocRenderPolicy = new TOCRenderPolicy(); tocRenderPolicy.render( metaTemplate,data,template); template.writeToFile("chess_example.docx");
目录会占用掉你在word文档中的第一个{{}}标签,用来固定位置
关于TOCRenderPolicy的使用,
ChessData data = new ChessData(); data.setMulu("目录"); data.setCatalog("目录"); data.setAuthor("chess"); data.setDate(new Date().toString()); ProjBase projBase = new ProjBase(); XWPFTemplate template = XWPFTemplate.compile(resource).render(data); List<MetaTemplate> elementTemplates = template.getElementTemplates(); ElementTemplate metaTemplate = (ElementTemplate)elementTemplates.get(0); TOCRenderPolicy tocRenderPolicy = new TOCRenderPolicy(); tocRenderPolicy.render( metaTemplate,data,template); template.writeToFile("chess_example.docx");
目录会占用掉你在word文档中的第一个{{}}标签,用来固定位置
如何生成页码?
关于TOCRenderPolicy的使用,
ChessData data = new ChessData(); data.setMulu("目录"); data.setCatalog("目录"); data.setAuthor("chess"); data.setDate(new Date().toString()); ProjBase projBase = new ProjBase(); XWPFTemplate template = XWPFTemplate.compile(resource).render(data); List<MetaTemplate> elementTemplates = template.getElementTemplates(); ElementTemplate metaTemplate = (ElementTemplate)elementTemplates.get(0); TOCRenderPolicy tocRenderPolicy = new TOCRenderPolicy(); tocRenderPolicy.render( metaTemplate,data,template); template.writeToFile("chess_example.docx");
目录会占用掉你在word文档中的第一个{{}}标签,用来固定位置
试了一下,报异常: java.lang.ClassCastException: class com.deepoove.poi.template.ChartTemplate cannot be cast to class com.deepoove.poi.template.run.RunTemplate (com.deepoove.poi.template.ChartTemplate and com.deepoove.poi.template.run.RunTemplate are in unnamed module of loader 'app')
问下按照代码中的示例:
XWPFDocument doc = new XWPFDocument(new FileInputStream("E:\\workspace\\JavaProj\\poi-tl\\poi-tl\\src\\test\\resources\\animal\\test2.test"));
XWPFStyles styles = doc.getStyles();
System.out.println(styles);
XWPFParagraph p = doc.createParagraph();
XWPFRun run = p.createRun();
run.setText("Heading 1");
p.getCTP().addNewPPr();
p.getCTP().getPPr().addNewPStyle();
p.setStyle(HEADING1);
XWPFParagraph tocPara = doc.createParagraph();
CTP ctP = tocPara.getCTP();
CTSimpleField toc = ctP.addNewFldSimple();
toc.setInstr("TOC \\h");
toc.setDirty(XWPFOnOff.ON);
System.out.println(doc.isEnforcedUpdateFields());
doc.enforceUpdateFields();
doc.createTOC();
doc.write(new FileOutputStream("CreateWordBookmark.docx"));
doc.close();
并没有生成目录,是不是目录插件目前还不能用?
目录渲染可以借助word多级列表与标题实现,我们可以在word模板内定义好多级列表样式,类似这样:
并将其链接至标题样式上:
定义好目录信息:
当我们由模板渲染出不同的章节时,确保最后调用下
doc.enforceUpdateFields();
当文档打开时会提示更新目录,相当于右键目录进行了“更新域”操作,之后目录和页码便会根据对应的标题渲染出来
哥,有demo实例代码吗,生成目录
目录渲染可以借助word多级列表与标题实现,我们可以在word模板内定义好多级列表样式,类似这样:
并将其链接至标题样式上:
定义好目录信息:
当我们由模板渲染出不同的章节时,确保最后调用下
doc.enforceUpdateFields();
当文档打开时会提示更新目录,相当于右键目录进行了“更新域”操作,之后目录和页码便会根据对应的标题渲染出来
xd,有没有办法可以避免每次打开word都显示需要更新作用域这个问题啊QAQ
#901
5年了,这个目录还是无解吗?
暂时还没想到解决办法,doc.enforceUpdateFields();方法是在setting.xml中添加<w:updateFields w:val="true"/> 弹窗是word弹的。 可以看ECMA-376-1:2016 这个位置 17.15.1.90 updateFields (Automatically Recalculate Fields on Open)