java - Compilación JSP en cadena o en memoria bytearray con Tomcat/Websphere
(1)
Estoy haciendo la conversión a la imagen y salida de 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.
¿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.
Podría realizar una solicitud de red a la página utilizando las API Socket y luego leer el resultado final que se representa desde 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.
Use 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.
Este es un problema francamente irritante, uno que he tenido que manejar varias veces y al que nunca he encontrado una solución satisfactoria.
El problema básico es que la API de servlet no es de ayuda aquí, así que tienes que engañarla. 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 usarlo 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.