Flying Saucer XHTML的相对路径?

我正在使用Flying Saucer将一些PDF文档从字符串渲染为XHTML。 我的代码是这样的:

iTextRenderer.setDocument(documentGenerator.generate(xhtmlDocumentAsString)); iTextRenderer.layout(); iTextRenderer.createPDF(outputStream); 

我想要了解的是,当使用这种方法时,XHTML中的相对路径从哪里解决? 例如,对于图像或样式表。 我能够使用此方法成功生成基于文本的文档,但我需要了解如何引用我的图像和CSS。

setDocument()方法有两个参数:document和url。 url参数指示用于添加到xhtml中出现的相对路径的基本URL,例如img标记。

假设你有:

  

现在假设文件夹“images”位于:

 C:/physical/route/to/app/images/ 

您可以使用setDocument()作为:

 renderer.setDocument(xhtmlDoc, "file:///C:/physical/route/to/app/"); 

注意尾部斜杠,没有它就无法工作。

这是它对我有用的方式。 我假设您可以使用其他类型的url,例如“http:// …”。

这个星期,我为此工作,我给你一些对我来说很好的东西。

在现实生活中,您的XHTML文档指向具有相对路径的多个资源(图像,css等)。 您还必须向Flying Saucer解释在哪里找到它们。 它们可以位于类路径中,也可以位于文件系统中。 (如果他们在网络上,你可以设置基本url,所以这没有帮助)

所以你必须像这样扩展ITextUserAgent:

 private static class ResourceLoaderUserAgent extends ITextUserAgent { public ResourceLoaderUserAgent(ITextOutputDevice outputDevice) { super(outputDevice); } protected InputStream resolveAndOpenStream(String uri) { InputStream is = super.resolveAndOpenStream(uri); String fileName = ""; try { String[] split = uri.split("/"); fileName = split[split.length - 1]; } catch (Exception e) { return null; } if (is == null) { // Resource is on the classpath try{ is = ResourceLoaderUserAgent.class.getResourceAsStream("/etc/images/" + fileName); } catch (Exception e) { } if (is == null) { // Resource is in the file system try { is = new FileInputStream(new File("C:\\images\\" + fileName)); } catch (Exception e) { } } return is; } } 

你这样使用它:

 // Output stream containing the result ByteArrayOutputStream baos = new ByteArrayOutputStream(); ITextRenderer renderer = new ITextRenderer(); ResourceLoaderUserAgent callback = new ResourceLoaderUserAgent(renderer.getOutputDevice()); callback.setSharedContext(renderer.getSharedContext()); renderer.getSharedContext().setUserAgentCallback(callback); renderer.setDocumentFromString(htmlSourceAsString); renderer.layout(); renderer.createPDF(baos); renderer.finishPDF(); 

干杯。

AtilaUy的答案是飞碟的默认方式。

更一般的答案是它询问UserAgentContext。 当文档设置时,它将在UserAgentContext上调用setBaseURL()。然后,当它想要读取实际资源数据时,它将调用resolveURL()来解析相对URL并最终解析resolveAndOpenStream()。

好吧,这个答案可能为时已晚,你无论如何都要使用它,但是当我出发时我需要这样的答案,并且设置自定义用户代理上下文是我最终使用的解决方案。

您可以拥有文件路径,也可以是绝对路径,或http:// urls。 相对路径可以工作,但不可移植,因为它取决于您运行程序的目录

我认为更简单的方法是:

  DomNodeList images = result.getElementsByTagName("img"); for (DomElement e : images) { e.setAttribute("src", result.getFullyQualifiedUrl(e.getAttribute("src")).toString()); } 

解决路径的另一种方法是覆盖UserAgentCallback#resolveURI ,它提供比固定URL更动态的行为(如AtilaUy的答案,在大多数情况下看起来非常有效)。

这就是我如何让XHTMLPane使用动态生成的样式表:

 public static UserAgentCallback interceptCssResourceLoading( final UserAgentCallback defaultAgentCallback, final Map< URI, CSSResource > cssResources ) { return new UserAgentCallback() { @Override public CSSResource getCSSResource( final String uriAsString ) { final URI uri = uriQuiet( uriAsString ) ; // Just rethrow unchecked exception. final CSSResource cssResource = cssResources.get( uri ) ; if( cssResource == null ) { return defaultAgentCallback.getCSSResource( uriAsString ) ; } else { return cssResource ; } } @Override public String resolveURI( final String uriAsString ) { final URI uri = uriQuiet( uriAsString ) ; if( cssResources.containsKey( uri ) ) { return uriAsString ; } else { return defaultAgentCallback.resolveURI( uriAsString ) ; } } // Delegate all other methods to defaultUserAgentCallback. } ; } 

然后我就这样使用它:

  final UserAgentCallback defaultAgentCallback = xhtmlPanel.getSharedContext().getUserAgentCallback() ; xhtmlPanel.getSharedContext().setUserAgentCallback( interceptCssResourceLoading( defaultAgentCallback, cssResources ) ) ; xhtmlPanel.setDocumentFromString( xhtml, null, new XhtmlNamespaceHandler() ) ; 

对我来说最好的解决方案是:

 renderer.setDocumentFromString(htmlContent, new ClassPathResource("/META-INF/pdfTemplates/").getURL().toExternalForm()); 

然后在html中提供所有提供的样式和图像(如

   

)按预期呈现。