2010-03-04 16 views
5

Estoy usando Flying Saucer para renderizar algunos documentos PDF de cadenas a XHTML. Mi código es algo como:Rutas relativas en Flying Saucer XHTML?

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

Lo que estoy tratando de entender es, cuando se utiliza este método, en el que se rutas relativas en el XHTML resueltos a partir? Por ejemplo, para imágenes o hojas de estilo. Puedo usar este método para generar con éxito un documento basado en texto, pero necesito entender cómo hacer referencia a mis imágenes y CSS.

Respuesta

14

El método setDocument() toma dos parámetros: documento y url. El parámetro url indica la url base utilizada para anteponer a las rutas relativas que aparecen en el xhtml, como en las etiquetas img.

suponga que tiene:

<img src="images/img1.jpg"> 

Supongamos ahora que la carpeta "imágenes" se encuentra en:

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

Es posible utilizar setDocument() como:

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

Aviso del raya al final, no funcionará sin ella.

Esta es la forma en que funcionó para mí. Supongo que podría usar otros tipos de URL como "http: // ...".

0

Puede tener rutas de acceso de archivos, que deben ser absolutas, o http: // urls. Las rutas relativas pueden funcionar pero no son portátiles porque depende de qué directorio haya ejecutado su programa desde

1

La respuesta de AtilaUy es inmediata para la manera predeterminada en que funcionan las cosas en Flying Saucer.

La respuesta más general es que pregunta al UserAgentContext. Llamará a setBaseURL() en el UserAgentContext cuando el documento esté configurado. Luego llamará a resolveURL() para resolver las URL relativas y, en última instancia, a resolverAndOpenStream() cuando quiera leer los datos reales del recurso.

Bueno, esta respuesta es probablemente demasiado tarde para que pueda utilizarla de todos modos, pero necesitaba una respuesta como esta cuando me puse en marcha, y la configuración de un agente de usuario personalizado es la solución que terminé usando.

5

Esta semana trabajé en esto, y les doy lo que funcionó bien para mí.

En la vida real, su documento XHTML apunta a múltiples recursos (imágenes, css, etc.) con rutas relativas. También debe explicar a Flying Saucer dónde encontrarlos. Pueden estar en su classpath o en su sistema de archivos. (Si están en la red, sólo se puede establecer la URL base, así que esto no va a ayudar)

Así que hay que extender el ITextUserAgent así:

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; 
    } 
} 

Y utilizar de esta manera :

// 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(); 

Cheers.

0

creo que un enfoque más sencillo sería:

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

Otra forma de resolver los caminos es reemplazar UserAgentCallback#resolveURI, que ofrece un comportamiento más dinámico que una URL fija (como en la respuesta de AtilaUy, que parece bastante válida para mayoria de los casos).

Éste es cómo hacer una XHTMLPane uso de hojas de estilo generadas de forma dinámica:

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. 

    } ; 
} 

Entonces lo uso así:

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

La mejor solución para mí fue:

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

Luego todos los estilos e imágenes provistos en html (como

<img class="logo" src="images/logo.png" /> 
<link rel="stylesheet" type="text/css" media="all" href="css/style.css"></link> 

) se visualizaron como se esperaba.

+0

Esto debe ser una solución basada en Spring. –

Cuestiones relacionadas