2012-07-16 49 views
7

Tengo una vista de bean con ámbito donde creo una persona. Una persona puede tener una imagen. Esta imagen se carga en la misma página donde se creó la persona. La imagen no se almacena en una base de datos o en un disco (ya que la persona aún no se ha creado). El bean tiene que ser visto desde una persona que puede ser creada en otro lugar y esto usa el mismo bean. Si el bean tiene un ámbito de sesión y un usuario carga una imagen pero no la guarda, la imagen se mostrará la próxima vez que el usuario intente crear una persona.Mostrar imagen cargada en JSF

Lo resolví usando dos frijoles; una vista de bean con ámbito para crear la persona y una sesión de bean con ámbito para cargar la imagen y obtener la imagen como una secuencia. Sin embargo, esto causa el problema mencionado anteriormente.

¿Cómo puedo resolver esto de una mejor manera?

El grano de carga:

@ManagedBean(name = "uploadBean") 
@SessionScoped 
public class UploadBean 
{ 
    private UploadedFile uploadedFile; 

    public UploadedFile getUploadedFile() 
    { 
     return uploadedFile; 
    } 

    public StreamedContent getUploadedFileAsStream() 
    { 
     if (uploadedFile != null) 
     { 
      return new DefaultStreamedContent(new ByteArrayInputStream(uploadedFile.getContents())); 
     } 
     return null; 
    } 

    public void uploadFile(FileUploadEvent event) 
    { 
     uploadedFile = event.getFile(); 
    } 
} 

El crear a un persona frijol:

@ManagedBean(name = "personBean") 
@ViewScoped 
public class PersonBean 
{ 
    private Person newPerson = new Person(); 

    public Person getNewPerson() 
    { 
     return newPerson; 
    } 

    private UploadedFile getUploadedPicture() 
    { 
     FacesContext context = FacesContext.getCurrentInstance(); 
     ELContext elContext = context.getELContext(); 
     UploadBean uploadBean = (UploadBean) elContext.getELResolver().getValue(elContext, null, "uploadBean"); 
     return uploadBean.getUploadedFile(); 
    } 

    public void createPerson() 
    { 
     UploadedFile uploadedPicture = getUploadedPicture(); 
     // Create person with picture; 
    } 
} 

La parte correspondiente página JSF:

<h:form enctype="multipart/form-data"> 
    <p:outputPanel layout="block" id="personPicture"> 
     <p:graphicImage height="150" 
      value="#{uploadBean.uploadedFileAsStream}" 
      rendered="#{uploadBean.uploadedFileAsStream != null}" /> 
    </p:outputPanel> 
     <p:fileUpload auto="true" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" 
      fileUploadListener="#{uploadBean.uploadedFile}" 
      update="personPicture" /> 
    <p:commandButton value="Save" actionListener="#{personBean.createPerson()}"/> 
</h:form> 

Respuesta

3

He pasado por un diferente enfoque. Inicialmente opté por mostrar una imagen cargada, sin embargo, si no se creó el Person, parecía una mejor idea para mantenerlo en el lado del cliente. He encontrado this question y creé la siguiente basado en la respuesta elegida:

En la cabeza incluyo html5shiv si el navegador es Internet Explorer y la versión es inferior a 9 para la compatibilidad:

<h:outputText value="&lt;!--[if lt IE 9]&gt;" escape="false" /> 
<h:outputScript library="js" name="html5shiv.js" /> 
<h:outputText value="&lt;![endif]--&gt;" escape="false" /> 

Para mostrar/subir el imagen que tengo estos elementos:

<p:fileUpload binding="#{upload}" mode="simple" 
    allowTypes="/(\.|\/)(gif|jpe?g|png)$/" 
    value="#{personBean.uploadedPicture}"/> 
<p:graphicImage value="#" height="150" binding="#{image}" /> 

y un poco de magia JavaScript/jQuery:

function readPicture(input, output) 
{ 
    if (input.files && input.files[0]) 
    { 
     var reader = new FileReader(); 
     reader.onload = function(e) 
     { 
      output.attr('src', e.target.result); 
     }; 
     reader.readAsDataURL(input.files[0]); 
    } 
} 

$("[id='#{upload.clientId}']").change(
    function() 
    { 
     readPicture(this, $("[id='#{image.clientId}']")); 
    }); 

El uploadedPicture propiedad es ahora una propiedad sencilla:

@ManagedBean(name = "personBean") 
@ViewScoped 
public class PersonBean 
{ 
    private UploadedFile uploadedPicture; 

    public UploadedFile getUploadedPicture() 
    { 
     return uploadedPicture; 
    } 

    public void setUploadedPicture(UploadedFile uploadedPicture) 
    { 
     this.uploadedPicture = uploadedPicture; 
    } 
} 
+2

Es interesante, que pidió un ejemplo en JSF y terminó con un poco de "Javascript/JQuery magic". También su comentario a la otra respuesta es más que necasario, porque el ejemplo de él es bastante agradable. Hay muchas formas JSF para hacer su tarea bastante bien, y no es necesario incluir JS aquí. ¿Puedes por favor editar tu pregunta o respuesta también? La pregunta y la respuesta no encajan juntas. – alexander

+0

La respuesta resolvió el problema que tenía, entonces ¿cómo no encajan? También me gustaría decir que la pregunta tiene fecha del 16 de julio de 2012, hace más de dos años. Puedo decir con seguridad que esta pregunta es irrelevante para mí. Si hay algo mal con mi respuesta, puede editarlo. ;-) – siebz0r

3

Add.xhtml

<h:form id="add-form" enctype="multipart/form-data"> 
     <p:growl id="messages" showDetail="true"/> 
     <h:panelGrid columns="2"> 
       <p:outputLabel for="choose" value="Choose Image :" /> 
       <p:fileUpload id="choose" validator="#{productController.validateFile}" multiple="false" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" value="#{productController.file}" required="true" mode="simple"/> 
      <p:commandButton value="Submit" ajax="false" update="messages" id="save-btn" actionListener="#{productController.saveProduct}"/> 
     </h:panelGrid> 
</h:form> 

Aquí se gestiona Código Bean:

@ManagedBean 
@RequestScoped 
public class ProductController implements Serializable{ 
    private ProductBean bean; 
    @ManagedProperty(value = "#{ProductService}") 
    private ProductService productService; 
    private StreamedContent content; 
    private UploadedFile file; 
    public StreamedContent getContent() { 
     FacesContext context = FacesContext.getCurrentInstance(); 

     if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) { 
       return new DefaultStreamedContent(); 
      } 
     else{ 
      String imageId = context.getExternalContext().getRequestParameterMap().get("id"); 
      Product product = getProductService().getProductById(Integer.parseInt(imageId)); 
      return new DefaultStreamedContent(new ByteArrayInputStream(product.getProductImage())); 
     } 
    } 
    public ProductController() { 
     bean = new ProductBean(); 
    } 

    public void setContent(StreamedContent content) { 
     this.content = content; 
    } 
    public UploadedFile getFile() { 
     return file; 
    } 

    public void setFile(UploadedFile file) { 
     this.file = file; 
    } 
    public void saveProduct(){ 
     try{ 
      Product product = new Product(); 
      product.setProductImage(getFile().getContents()); 

      getProductService().saveProduct(product); 
      file = null; 

     } 
     catch(Exception ex){ 
      ex.printStackTrace(); 
     } 
    } 
    public void validateFile(FacesContext ctx, 
      UIComponent comp, 
      Object value) { 
     List<FacesMessage> msgs = new ArrayList<FacesMessage>(); 
     UploadedFile file = (UploadedFile)value; 
     int fileByte = file.getContents().length; 
     if(fileByte > 15360){ 
      msgs.add(new FacesMessage("Too big must be at most 15KB")); 
     } 
     if (!(file.getContentType().startsWith("image"))) { 
      msgs.add(new FacesMessage("not an Image file")); 
     } 
     if (!msgs.isEmpty()) { 
      throw new ValidatorException(msgs); 
     } 
    } 
} 

Añadir estas líneas de código en la web. xml

<filter> 
    <filter-name>PrimeFaces FileUpload Filter</filter-name> 
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>PrimeFaces FileUpload Filter</filter-name> 
    <servlet-name>Faces Servlet</servlet-name> 
</filter-mapping> 

Y luego de los archivos jar en la carpeta WEBINF/lib.

commons-io-X.X and commons-fileupload-X.X, recommended most recent version. 

commons-io-2,4, commons-io-2,4-javadoc, commons-io-2,4-fuentes, commons-io-2,4-pruebas, commons-io-2,4-test fuentes, Commons -fileupload-1.3, commons-fileupload-1,3-javadoc, Commons-FileUpload-1,3-sources, commons-FileUpload-1,3-pruebas, commons-fileupload-1,3-test fuentes

Vista.xhtml

<h:form id="ShowProducts"> 
    <p:dataTable rowsPerPageTemplate="3,6,9" var="products" paginator="true" rows="3" emptyMessage="Catalog is empty" value="#{productController.bean.products}"> 
     <p:column headerText="Product Name"> 
      <p:graphicImage width="80" height="80" value="#{productController.content}"> 
       <f:param name="id" value="#{products.productId}" /> 
      </p:graphicImage> 
      #{products.productName} 
     </p:column> 
    </p:dataTable> 
</h:form> 
+2

Trate de mantener sus ejemplos cortos. Hay un montón de código allí que no es necesario. Solo hace que el ejemplo sea menos legible. – siebz0r

Cuestiones relacionadas