2009-07-27 7 views
6

Estoy haciendo conversión a imagen y PDF. Necesito un documento HTML de entrada generado por nuestras aplicaciones JSP. Básicamente, necesito renderizar el producto de salida final de una aplicación basada en JSP en una Cadena o memoria y luego usar esa cadena para otro procesamiento.compilación JSP en cadena o en memoria bytearray con Tomcat/Websphere

¿De qué manera puedo invocar el renderizador JSP para obtener el contenido HTML final que normalmente se envía al usuario? Idealmente, estoy buscando algo que funcione para múltiples servidores de aplicaciones como websphere. Pero algo que es específico de Tomcat también funcionará.

Hay un par de enfoques diferentes, pero creo que renderizar el JSP (que puede incluir sub JSP) es el mejor enfoque.

Rutas opcionales de las que preferiría no estar.

  1. pude realizar una solicitud de red a la página utilizando las API de socket y después lee el resultado final que se representa a partir de esa página en particular. Esta es probablemente la siguiente mejor opción, pero trabajamos en varios servidores y JVM, la orientación de la página que necesito sería complicada.

  2. Utilice un filtro para obtener la salida de la página final. Ok, pero siempre he tenido problemas con los filtros y lasexcepciones ilegales. Parece que nunca funciona al 100% de la manera que necesito.

Parece que esto debería ser simple. El compilador JSP es esencialmente solo una biblioteca para analizar un documento JSP de entrada y subdocumentos y luego generar contenido HTML. Me gustaría invocar ese proceso a través del código Java. En el servidor y posiblemente como una aplicación de consola independiente.

Respuesta

6

Este es un problema francamente irritante, uno que he tenido que manejar algunas veces y en el que nunca he encontrado una solución satisfactoria.

El problema básico es que la API de servlet no es de ayuda aquí, por lo que hay que engañar. Mi solución es escribir una subclase de HttpServletResponseWrapper que anule los métodos getWriter() y getOutput() y capture los datos en un búfer. A continuación, reenvía() su solicitud al URI del JSP que desea capturar, sustituyendo la respuesta original por la respuesta del contenedor. A continuación, extrae los datos del búfer, los manipula y escribe el resultado final en la respuesta original.

Aquí está mi código que hace esto:

public class CapturingResponseWrapper extends HttpServletResponseWrapper { 

    private final OutputStream buffer; 

    private PrintWriter writer; 
    private ServletOutputStream outputStream; 

    public CapturingResponseWrapper(HttpServletResponse response, OutputStream buffer) { 
     super(response); 
     this.buffer = buffer; 
    } 

    @Override 
    public ServletOutputStream getOutputStream() { 
     if (outputStream == null) { 
      outputStream = new DelegatingServletOutputStream(buffer); 
     } 
     return outputStream; 
    } 

    @Override 
    public PrintWriter getWriter() { 
     if (writer == null) { 
      writer = new PrintWriter(buffer); 
     } 
     return writer; 
    } 

    @Override 
    public void flushBuffer() throws IOException { 
     if (writer != null) { 
      writer.flush(); 
     } 
     if (outputStream != null) { 
      outputStream.flush(); 
     } 
    } 

} 

El código para utilizarlo puede ser algo como esto:

HttpServletRequest originalRequest = ... 
HttpServletResponse originalResponse = ... 

ByteArrayOutputStream bufferStream = new ByteArrayOutputStream(); 
CapturingResponseWrapper responseWrapper = new CapturingResponseWrapper(originalResponse, bufferStream); 

originalRequest.getRequestDispatcher("/my.jsp").forward(originalRequest, responseWrapper); 

responseWrapper.flushBuffer(); 
byte[] buffer = bufferStream.toByteArray(); 
// now use the data 

Es muy feo, pero es la mejor solución que he encontrado. En caso de que se esté preguntando, la respuesta del contenedor debe contener la respuesta original porque la especificación del servlet dice que no puede sustituir un objeto de solicitud o respuesta completamente diferente cuando reenvía, debe usar los originales o las versiones empaquetadas de los mismos.

+0

+1 Me pegó. –

+0

Tengo la sensación de que todos tienen la misma solución espantosa. – skaffman

+0

Ese es un buen enfoque. Algo así como el enfoque orientado al "filtro". Pero el único problema con esto, hay dos problemas. 1. No puede ejecutar esto como un sistema independiente. P.ej.no se puede hacer: main() {compileJSP()} 2. Si usa esto dentro del código de filtro, algunos servidores de aplicación son nimpicking sobre el estado de la envoltura de solicitud y tiendo a obtenerexcepcionessexuales y no puedo obtener el JSP para renderizar en una cadena (esencialmente cuando lo hago esto nunca es sencillo). Pero, sí, esa es una buena solución. –