在存储到磁盘之前显示上载的图像

时间:2013-12-02 16:55:23

标签: jsf file-upload primefaces

向大家致意,

我正在使用primefaces 4和Tomcat 7.我希望用户能够上传多个图像,并在将这些图像写入磁盘之前立即查看每个上传的图像(当它们在内存中时)。图像将仅在表单提交后写入磁盘。我正在使用p:fileUpload组件。

以下是相关代码:

...
<p:tab id="imageTab" title="#{msgs.images}">

    <p:dataGrid id="imagesDataGrid" columns="4" value="#{modifyProductAdminBean.imageIds}" 
                                    var="imgId" >
        <p:graphicImage value="#{pA_ImageService.image}" >
            <f:param name="id" value="#{imgId}" />
        </p:graphicImage>    
    </p:dataGrid>

    <p:fileUpload fileUploadListener="#{modifyProductAdminBean.handleFileUpload}" mode="advanced"
        dragDropSupport="true" multiple="true" sizeLimit="5242880"
        invalidFileMessage="#{msgs.invalidFileType}"
        invalidSizeMessage="#{msgs.fileTooLarge}"
        allowTypes="/(\.|\/)(gif|jpe?g|png|jpg)$/"
        cancelLabel="#{msgs.cancel}"
        uploadLabel="#{msgs.upload}"
        label="#{msgs.choose}"
        update="imagesDataGrid" />
</p:tab>
...


@ManagedBean
@ViewScoped
public class ModifyProductAdminBean implements Serializable {
    private Map<String, UploadedFile> uploadedImages;

    public void handleFileUpload(FileUploadEvent event) {
        UploadedFile file = event.getFile(); 
        String uniqueId = UUID.randomUUID().toString();
        this.getUploadedImages().put(uniqueId, file);
    }

    public Set<String> getImageIds() {
        return this.getUploadedImages().keySet();
    }

    public Map<String, UploadedFile> getUploadedImages() {
        return uploadedImages;
    }
    ...
}


@ManagedBean
@ApplicationScoped
public class PA_ImageService implements Serializable {

    private final ModifyProductAdminBean modifyProductAdminBean;

    public PA_ImageService() {
        this.modifyProductAdminBean = BeanManager.findBean("modifyProductAdminBean");
    }

    // Taken from http://stackoverflow.com/questions/8207325/display-image-from-database-with-pgraphicimage
    public StreamedContent getImage() {
        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 imageId = context.getExternalContext().getRequestParameterMap().get("id");
            // remove [, ] characters between
            imageId = imageId.substring(1, imageId.length() - 1);
            UploadedFile uFile = this.modifyProductAdminBean.getUploadedImages().get(imageId);
            return new DefaultStreamedContent(new ByteArrayInputStream(uFile.getContents()));
        }
    }

    ...
}


public class BeanManager implements Serializable {
    @SuppressWarnings("unchecked")
    public static <T> T findBean(String beanName) {
        FacesContext context = FacesContext.getCurrentInstance();
        return (T) context.getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", Object.class);
    }
    ...
}

当我运行此代码时,我在“PA_ImageService”的最后一行得到一个NullPointerException(返回new ...)。更确切地说,虽然uFile不为null,但“uFile.getContents()”返回null。为什么?我做错了什么?


我观察到的更多细节:

我注意到当我上传文件时,Tomcat会暂时将其存储在E:\Program Files (x86)\Apache Software Foundation\Apache Tomcat 7.0.41\work\Catalina\localhost\MyProject文件的.tmp目录中。

通过调试项目,我可以看到:当我到达if (context... == PhaseId.RENDER_RESPONSE)的{​​{1}}行时,.tmp文件仍然存在。但是,在PA_ImageService方法的第二次访问中,当控件移动到getImage()块时,我可以看到tmp文件不再存在。因此,无法检索其内容,因此无法检索else结果。

有关这种情况如何发生的任何想法?

2 个答案:

答案 0 :(得分:1)

您需要将图像存储在(临时)磁盘/数据库位置,而不是视图范围bean的属性。您可以将其存储为会话范围bean的属性,但我不建议在HTTP会话中携带占用内存的字节,这在需要序列化时会受到影响,例如服务器集群。

您可以轻松使用File#renameTo()从临时位置移动到固定位置。您可以轻松运行会话侦听器来获取/清除任何与用户相关的临时文件。

答案 1 :(得分:0)

这里最明显的问题是你试图从@ViewScoped bean中访问@ApplicationScoped bean;这在JSF中是非法的。

您只能注射范围比注射目标范围更广的豆类。这意味着您可以按以下范围的顺序注入bean:

  

ApplicationScope &gt;&gt; SessionScope &gt;&gt; ViewScope &gt;&gt; RequestScope

话虽如此,虽然我无法看到您如何将ModifyProductAdminBean注入PA_ImageService(没有注释或 faces-config.xml 可见),但它是安全的说以下行不应该起作用

UploadedFile uFile = this.modifyProductAdminBean.getUploadedImages().get(imageId);