【问题标题】:Display uploaded image in JSF在 JSF 中显示上传的图像
【发布时间】:2012-07-15 10:41:34
【问题描述】:

我有一个视图范围的 bean,我在其中创建了一个人。一个人可以有一张照片。这张照片是在创建此人的同一页面上上传的。图片未存储在数据库或磁盘中(因为尚未创建此人)。 bean 必须是视图范围的,因为可以在其他地方创建一个人,并且这使用相同的 bean。如果 bean 是会话范围的,并且用户上传了图片但没有保存人员,则该图片将在用户下次尝试创建人员时显示。

我通过使用两个 bean 解决了这个问题;一个视图范围 bean 用于创建人员,一个会话范围 bean 用于上传图片并将图片作为流获取。然而,这会导致上述问题。

我怎样才能更好地解决这个问题?

上传 bean:

@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();
    }
}

create-a-person bean:

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

相关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>

【问题讨论】:

    标签: file-upload jsf-2 primefaces graphicimage


    【解决方案1】:

    我通过简单地将上传的图像编码为base64然后通过html&lt;img&gt;标签正常显示来做到这一点。

    这是我的托管 bean:

    @ManagedBean
    @ViewScoped
    public class ImageMB {
    
    private String base64Image;
    
    public void onUploadImage(FileUploadEvent event) {
        String fileName = event.getFile().getFileName();
        //Get file extension.
        String extension = "png";
        int i = fileName.lastIndexOf('.');
        if (i > 0) {
            extension = fileName.substring(i + 1).toLowerCase();
        }
    
        String encodedImage = java.util.Base64.getEncoder().encodeToString(event.getFile().getContents());
        this.base64Image = String.format("data:image/%s;base64, %s", 
             extension, encodedImage));
    }
    

    这里是 JSF 部分:

    <p:fileUpload id="imageFileUploader"
                  fileUploadListener="#{imageMB.onUploadImage}"
                  mode="advanced"    
                  multiple="false"
                  fileLimit="1"
                  allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
                  update="@form"/>
    
    <div>
        <img src="#{toolAddEditMB.base64Image}" 
             style="#{toolAddEditMB.base64Image eq null ? 'display: none' : ''}"/>
    </div>
    

    【讨论】:

      【解决方案2】:

      添加.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>
      

      这是托管 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);
              }
          }
      }
      

      在 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>
      

      以及 WEBINF/lib 文件夹中的以下 jar 文件。

      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-sources,commons-io-2.4-tests,commons-io-2.4-test-sources,commons -fileupload-1.3,commons-fileupload-1.3-javadoc,commons-fileupload-1.3-sources,commons-fileupload-1.3-tests,commons-fileupload-1.3-test-sources

      View.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>
      

      【讨论】:

      • 尽量保持你的例子简短。里面有很多不需要的代码。它只会降低示例的可读性。
      【解决方案3】:

      我采用了不同的方法。我最初是为了显示上传的图像,但是如果尚未创建 Person,将其全部保留在客户端似乎是一个更好的主意。我找到了this question,并根据选择的答案创建了以下内容:

      如果浏览器是 IE 并且版本小于 9 以兼容,则在头部包含 html5shiv

      <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" />
      

      要显示/上传图像,我有这些元素:

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

      还有一些 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}']"));
          });
      

      uploadedPicture 属性现在是一个简单的属性:

      @ManagedBean(name = "personBean")
      @ViewScoped
      public class PersonBean
      {
          private UploadedFile uploadedPicture;
      
          public UploadedFile getUploadedPicture()
          {
              return uploadedPicture;
          }
      
          public void setUploadedPicture(UploadedFile uploadedPicture)
          {
              this.uploadedPicture = uploadedPicture;
          }
      }
      

      【讨论】:

      • 有趣的是,您要求在 JSF 中提供一个示例,并以一些“Javascript/JQuery 魔术”结束。您对另一个答案的评论也不仅仅是必要的,因为他的例子非常好。有许多 JSF 方法可以很好地完成您的任务 - 这里不需要包含 JS。您能否也编辑您的问题或答案?问题和答案不能放在一起。
      • 答案解决了我的问题,那么他们怎么不适合?我还想指出,这个问题的日期是 2012 年 7 月 16 日,那是两年多以前的事了。我可以肯定地说,这个问题与我无关。如果我的回答有问题,您可以编辑它。 ;-)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多