streamedcontent from database image jsf jsf-2 primefaces

database - from - Visualice la imagen dinámica desde la base de datos con p: graphicImage y StreamedContent



primefaces graphic image from database (4)

Aquí hay un par de posibilidades (y publique la clase completa si no es así).

1) No estás inicializando la imagen correctamente 2) Tu transmisión está vacía por lo que no obtienes nada

Supongo que student.getImage () tiene una firma de byte [], así que primero asegúrese de que esos datos estén realmente intactos y representen una imagen. En segundo lugar, no especifica un tipo de contenido que debe ser "imagen / jpg" o lo que sea que esté usando.

Aquí hay un código repetitivo para verificarlo, estoy usando Primefaces 2 para esto.

/** ''test'' package with ''test/test.png'' on the path */ @RequestScoped @ManagedBean(name="imageBean") public class ImageBean { private DefaultStreamedContent content; public StreamedContent getContent() { if(content == null) { /* use your database call here */ BufferedInputStream in = new BufferedInputStream(ImageBean.class.getClassLoader().getResourceAsStream("test/test.png")); ByteArrayOutputStream out = new ByteArrayOutputStream(); int val = -1; /* this is a simple test method to double check values from the stream */ try { while((val = in.read()) != -1) out.write(val); } catch(IOException e) { e.printStackTrace(); } byte[] bytes = out.toByteArray(); System.out.println("Bytes -> " + bytes.length); content = new DefaultStreamedContent(new ByteArrayInputStream(bytes), "image/png", "test.png"); } return content; } }

y algo de marcado ...

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.prime.com.tr/ui" > <h:head> </h:head> <h:body> <p:graphicImage value="#{imageBean.content}" /> </h:body> </html>

Si ese código funciona, entonces está configurado correctamente. A pesar de que es un código de basura para las transmisiones (no lo use en producción) , debería darle un punto para solucionarlo. Supongo que es posible que suceda algo en su JPA u otro marco de base de datos donde su byte [] está vacío o tiene un formato incorrecto. Alternativamente, podría tener un problema de tipo de contenido.

Por último, clonaría los datos del bean para que student.getImage () solo se copiara en una nueva matriz y luego se usara. De esta forma, si tienes algo desconocido en curso (algo más moviendo el objeto o cambiando el byte [] no estás jugando con tus transmisiones.

Haz algo como:

byte[] data = new byte[student.getImage().length] for(int i = 0; i < data.length; i++) data[i] = student.getImage()[i];

para que tu bean tenga una copia (o Arrays.copy () - lo que sea que flote tu bote). No puedo dejar de insistir en que algo tan simple como este / tipo de contenido suele ser lo que está mal. Suerte con ello.

Estoy tratando de mostrar los bytes de imagen que se guardan en la base de datos como contenido StreamedContent en el <p:graphicImage> siguiente manera:

<p:graphicImage value="#{item.imageF}" width="50" id="grpImage" height="80"/>

private StreamedContent content; // getter and setter public StreamedContent getImageF() { if (student.getImage() != null) { InputStream is = new ByteArrayInputStream(student.getImage()); System.out.println("Byte :"+student.getImage()); content = new DefaultStreamedContent(is, "", student.getStuID()); System.out.println("ddd ------------------------------- " + content); return content; } return content; }

Esto devuelve una imagen en blanco. ¿Cómo es esto causado y cómo puedo resolverlo?

El stdout imprime lo siguiente:

INFO: Byte :[B@a2fb48 INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@b0887b INFO: Byte :[B@a2fb48 INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1d06a92 INFO: Byte :[B@d52f0b INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@39a60 INFO: Byte :[B@d52f0b INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@8c3daa INFO: Byte :[B@124728a INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1dbe05b INFO: Byte :[B@124728a INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@66a266 INFO: Byte :[B@a2fb48 INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1293976 INFO: Byte :[B@a2fb48 INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@17b7399 INFO: Byte :[B@d52f0b INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1e245a5 INFO: Byte :[B@d52f0b INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@4a7153 INFO: Byte :[B@124728a INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@1561bfd INFO: Byte :[B@124728a INFO: ddd ------------------------------- org.primefaces.model.DefaultStreamedContent@47a8c2


El <p:graphicImage> requiere un método getter especial. Se invocará dos veces por cada imagen generada, cada una en una solicitud HTTP completamente diferente.

La primera solicitud HTTP, que ha solicitado el resultado HTML de una página JSF, invocará el getter por primera vez para generar el elemento HTML <img> con la URL única y autogenerada correcta en el atributo src que contiene información sobre qué bean y getter exactamente deberían invocarse cada vez que el webbrowser está a punto de solicitar la imagen. Tenga en cuenta que el getter en este momento no necesita devolver el contenido de la imagen. No se usaría de ninguna manera, ya que no es así como funciona HTML (las imágenes no están "en línea" en el formato HTML, sino que se solicitan por separado).

Una vez que el navegador web recupera el resultado HTML como respuesta HTTP, analizará el origen HTML para presentar el resultado visualmente al usuario final. Una vez que el navegador web encuentra un elemento <img> durante el análisis del código fuente HTML, enviará una nueva solicitud HTTP en la URL tal como se especifica en su atributo src para descargar el contenido de esa imagen e incrustarla en la presentación visual. Esto invocará el método getter por segunda vez, que a su vez devolverá el contenido real de la imagen.

En su caso particular, PrimeFaces aparentemente no pudo identificar e invocar el getter para recuperar el contenido de la imagen real, o el getter no devolvió el contenido esperado de la imagen. El uso del nombre de la variable #{item} y la cantidad de llamadas en el registro sugiere que lo estaba usando en un <ui:repeat> o a un <h:dataTable> . Lo más probable es que el bean de respaldo tenga un alcance de solicitud y el modelo de datos no se conserve adecuadamente durante la solicitud de la imagen y JSF no podrá invocar el captador durante la ronda de iteración correcta. Un bean de ámbito de vista tampoco funcionaría, ya que el estado de la vista JSF no está disponible cuando el navegador realmente solicita la imagen.

Para resolver este problema, la mejor opción es volver a escribir el método getter como tal para poder invocarlo por solicitud, en donde pase el identificador de imagen único como <f:param> lugar de depender de algunas propiedades del bean de respaldo que puede quedar "fuera de sincronización" durante las siguientes solicitudes HTTP. Tendría mucho sentido usar un bean administrado con ámbito de aplicación separado para esto, que no tiene ningún estado. Además, un InputStream puede leerse solo una vez, no varias veces.

En otras palabras: nunca declare StreamedContent ni ningún InputStream o incluso UploadedFile como una propiedad de bean; solo cree una novedad en la obtención de un bean @ApplicationScoped sin @ApplicationScoped cuando el @ApplicationScoped realmente solicita el contenido de la imagen .

P.ej

<p:dataTable value="#{bean.students}" var="student"> <p:column> <p:graphicImage value="#{studentImages.image}"> <f:param name="studentId" value="#{student.id}" /> </p:graphicImage> </p:column> </p:dataTable>

Donde el StudentImages respaldo StudentImages puede verse así:

@Named // Or @ManagedBean @ApplicationScoped public class StudentImages { @EJB private StudentService service; public StreamedContent getImage() throws IOException { FacesContext context = FacesContext.getCurrentInstance(); if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) { // So, we''re rendering the HTML. Return a stub StreamedContent so that it will generate right URL. return new DefaultStreamedContent(); } else { // So, browser is requesting the image. Return a real StreamedContent with the image bytes. String studentId = context.getExternalContext().getRequestParameterMap().get("studentId"); Student student = studentService.find(Long.valueOf(studentId)); return new DefaultStreamedContent(new ByteArrayInputStream(student.getImage())); } } }

Tenga en cuenta que este es un caso muy especial en el que la lógica empresarial en un método getter es completamente legítimo, teniendo en cuenta cómo funciona <p:graphicImage> debajo de las cubiertas. Invocar la lógica de negocio en getters es generalmente desaprobado, ver también por qué JSF llama getters varias veces . No use este caso especial como excusa para otros casos estándar (no especiales). Tenga en cuenta que no puede hacer uso de la función EL 2.2 de pasar argumentos de métodos como #{studentImages.image(student.id)} porque este argumento no terminará en la URL de la imagen. Por lo tanto, realmente debe pasarlos como <f:param> .

Si usa OmniFaces 2.0 o posterior , considere utilizar su <o:graphicImage> que se puede usar de manera más intuitiva, con un método getter con alcance de aplicación que delega directamente al método de servicio y admite los argumentos del método EL 2.2.

Así que:

<p:dataTable value="#{bean.students}" var="student"> <p:column> <o:graphicImage value="#{studentImages.getImage(student.id)}" /> </p:column> </p:dataTable>

Con

@Named // Or @ManagedBean @ApplicationScoped public class StudentImages { @EJB private StudentService service; public byte[] getImage(Long studentId) { return studentService.find(studentId).getImage(); } }

Ver también el blog sobre el tema.


Intenta incluir un tipo de mimo. En su ejemplo publicado, lo tiene como "". La imagen en blanco puede deberse a que no reconoce la secuencia como un archivo de imagen ya que convirtió ese campo en una cadena vacía. Así que agrega un tipo de imagen mime / png o image / jpg y mira si eso funciona:

String mimeType = "image/jpg"; StreamedContent file = new DefaultStreamedContent(bytes, mimeType, filename);


La respuesta de BalusC es (como de costumbre) la correcta.

Pero tenga en mente una cosa (como ya lo dijo). La solicitud final se realiza desde el navegador para obtener la URL de la etiqueta <img> construida. Esto no se hace en un contexto ''jsf''.

Entonces, si intenta, por ejemplo, acceder a la fase Id (registro o cualquier otra razón)

context.getCurrentPhaseId().getName()

Esto dará como resultado una NullPointerException y el mensaje de error engañoso que obtendrá es:

org.primefaces.application.resource.StreamedContentHandler () - Error in streaming dynamic resource. Error reading ''image'' on type a.b.SomeBean

Me llevó bastante tiempo descubrir cuál era el problema.